Bug 1487885. Update webrender to d89e290c57aab76c45d8016975240cf762354e39

This commit is contained in:
Jeff Muizelaar 2018-09-05 13:18:10 -04:00
Родитель 028a5e54ee
Коммит ae8d2d3c90
14 изменённых файлов: 687 добавлений и 618 удалений

Просмотреть файл

@ -102,22 +102,41 @@ vec2 get_outer_corner_scale(int segment) {
return p;
}
vec4 mod_color(vec4 color, float f) {
return vec4(clamp(color.rgb * f, vec3(0.0), vec3(color.a)), color.a);
// NOTE(emilio): If you change this algorithm, do the same change
// in border.rs
vec4 mod_color(vec4 color, bool is_black, bool lighter) {
const float light_black = 0.7;
const float dark_black = 0.3;
const float dark_scale = 0.66666666;
const float light_scale = 1.0;
if (is_black) {
if (lighter) {
return vec4(vec3(light_black), color.a);
}
return vec4(vec3(dark_black), color.a);
}
if (lighter) {
return vec4(color.rgb * light_scale, color.a);
}
return vec4(color.rgb * dark_scale, color.a);
}
vec4[2] get_colors_for_side(vec4 color, int style) {
vec4 result[2];
const vec2 f = vec2(1.3, 0.7);
bool is_black = color.rgb == vec3(0.0, 0.0, 0.0);
switch (style) {
case BORDER_STYLE_GROOVE:
result[0] = mod_color(color, f.x);
result[1] = mod_color(color, f.y);
result[0] = mod_color(color, is_black, true);
result[1] = mod_color(color, is_black, false);
break;
case BORDER_STYLE_RIDGE:
result[0] = mod_color(color, f.y);
result[1] = mod_color(color, f.x);
result[0] = mod_color(color, is_black, false);
result[1] = mod_color(color, is_black, true);
break;
default:
result[0] = color;

Просмотреть файл

@ -490,6 +490,9 @@ impl AlphaBatchBuilder {
);
let source_task_id = pic
.raster_config
.as_ref()
.expect("BUG: no raster config")
.surface
.as_ref()
.expect("BUG: unexpected surface in splitting")
@ -636,7 +639,7 @@ impl AlphaBatchBuilder {
// for it and add it to the current plane splitter.
if picture.is_in_3d_context {
// Push into parent plane splitter.
debug_assert!(picture.surface.is_some());
debug_assert!(picture.raster_config.is_some());
let transform = &ctx.transforms
.get_transform_by_id(transform_id);
@ -666,13 +669,16 @@ impl AlphaBatchBuilder {
return;
}
let add_to_parent_pic = match picture.composite_mode {
Some(PictureCompositeMode::Filter(filter)) => {
assert!(filter.is_visible());
match filter {
FilterOp::Blur(..) => {
match picture.surface {
Some(ref surface) => {
match picture.raster_config {
Some(ref raster_config) => {
let surface = raster_config.surface
.as_ref()
.expect("bug: surface must be allocated by now");
match raster_config.composite_mode {
PictureCompositeMode::Filter(filter) => {
assert!(filter.is_visible());
match filter {
FilterOp::Blur(..) => {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
@ -703,108 +709,96 @@ impl AlphaBatchBuilder {
clip_task_address,
};
batch.push(PrimitiveInstance::from(instance));
false
}
None => {
true
FilterOp::DropShadow(offset, ..) => {
// Draw an instance of the shadow first, following by the content.
// Both the shadow and the content get drawn as a brush image.
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
// Gets the saved render task ID of the content, which is
// deeper in the render task tree than the direct child.
let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
// Build BatchTextures for shadow/content
let shadow_textures = BatchTextures::render_target_cache();
let content_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCache(saved_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
};
// Build batch keys for shadow/content
let shadow_key = BatchKey::new(kind, non_segmented_blend_mode, shadow_textures);
let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);
// Retrieve the UV rect addresses for shadow/content.
let cache_task_id = surface.resolve_render_task_id();
let shadow_uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache)
.as_int();
let content_uv_rect_address = render_tasks[secondary_id]
.get_texture_address(gpu_cache)
.as_int();
// Get the GPU cache address of the extra data handle.
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
let content_prim_header_index = prim_headers.push(&prim_header, [
content_uv_rect_address,
(ShaderColorMode::Image as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_rect = prim_metadata.local_rect.translate(&offset);
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
let shadow_prim_header = PrimitiveHeader {
local_rect: shadow_rect,
local_clip_rect: shadow_clip_rect,
specific_prim_address: shadow_prim_address,
..prim_header
};
let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, [
shadow_uv_rect_address,
(ShaderColorMode::Alpha as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_instance = BrushInstance {
prim_header_index: shadow_prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
let content_instance = BrushInstance {
prim_header_index: content_prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
self.batch_list
.get_suitable_batch(shadow_key, bounding_rect)
.push(PrimitiveInstance::from(shadow_instance));
self.batch_list
.get_suitable_batch(content_key, bounding_rect)
.push(PrimitiveInstance::from(content_instance));
}
}
}
FilterOp::DropShadow(offset, ..) => {
// Draw an instance of the shadow first, following by the content.
// Both the shadow and the content get drawn as a brush image.
if let Some(ref surface) = picture.surface {
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray),
);
// Gets the saved render task ID of the content, which is
// deeper in the render task tree than the direct child.
let secondary_id = picture.secondary_render_task_id.expect("no secondary!?");
let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?");
debug_assert_ne!(saved_index, SavedTargetIndex::PENDING);
// Build BatchTextures for shadow/content
let shadow_textures = BatchTextures::render_target_cache();
let content_textures = BatchTextures {
colors: [
SourceTexture::RenderTaskCache(saved_index),
SourceTexture::Invalid,
SourceTexture::Invalid,
],
};
// Build batch keys for shadow/content
let shadow_key = BatchKey::new(kind, non_segmented_blend_mode, shadow_textures);
let content_key = BatchKey::new(kind, non_segmented_blend_mode, content_textures);
// Retrieve the UV rect addresses for shadow/content.
let cache_task_id = surface.resolve_render_task_id();
let shadow_uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache)
.as_int();
let content_uv_rect_address = render_tasks[secondary_id]
.get_texture_address(gpu_cache)
.as_int();
// Get the GPU cache address of the extra data handle.
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
let content_prim_header_index = prim_headers.push(&prim_header, [
content_uv_rect_address,
(ShaderColorMode::Image as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_rect = prim_metadata.local_rect.translate(&offset);
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
let shadow_prim_header = PrimitiveHeader {
local_rect: shadow_rect,
local_clip_rect: shadow_clip_rect,
specific_prim_address: shadow_prim_address,
..prim_header
};
let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, [
shadow_uv_rect_address,
(ShaderColorMode::Alpha as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_instance = BrushInstance {
prim_header_index: shadow_prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
let content_instance = BrushInstance {
prim_header_index: content_prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
self.batch_list
.get_suitable_batch(shadow_key, bounding_rect)
.push(PrimitiveInstance::from(shadow_instance));
self.batch_list
.get_suitable_batch(content_key, bounding_rect)
.push(PrimitiveInstance::from(content_instance));
}
false
}
_ => {
match picture.surface {
Some(ref surface) => {
_ => {
let key = BatchKey::new(
BatchKind::Brush(BrushBatchKind::Blend),
BlendMode::PremultipliedAlpha,
@ -868,110 +862,92 @@ impl AlphaBatchBuilder {
let batch = self.batch_list.get_suitable_batch(key, bounding_rect);
batch.push(PrimitiveInstance::from(instance));
false
}
None => {
true
}
}
}
PictureCompositeMode::MixBlend(mode) => {
let cache_task_id = surface.resolve_render_task_id();
let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id,
source_id: cache_task_id,
backdrop_id,
},
),
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
);
let batch = self.batch_list.get_suitable_batch(key, bounding_rect);
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(cache_task_id);
let prim_header_index = prim_headers.push(&prim_header, [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
batch.push(PrimitiveInstance::from(instance));
}
PictureCompositeMode::Blit => {
let cache_task_id = surface.resolve_render_task_id();
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(
kind,
non_segmented_blend_mode,
BatchTextures::render_target_cache(),
);
let batch = self.batch_list.get_suitable_batch(
key,
bounding_rect,
);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache)
.as_int();
let prim_header_index = prim_headers.push(&prim_header, [
uv_rect_address,
(ShaderColorMode::Image as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
batch.push(PrimitiveInstance::from(instance));
}
}
}
Some(PictureCompositeMode::MixBlend(mode)) => {
let cache_task_id = picture
.surface
.as_ref()
.expect("bug: no surface allocated")
.resolve_render_task_id();
let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id,
source_id: cache_task_id,
backdrop_id,
},
),
BlendMode::PremultipliedAlpha,
BatchTextures::no_texture(),
);
let batch = self.batch_list.get_suitable_batch(key, bounding_rect);
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(cache_task_id);
let prim_header_index = prim_headers.push(&prim_header, [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
batch.push(PrimitiveInstance::from(instance));
false
}
Some(PictureCompositeMode::Blit) => {
let cache_task_id = picture
.surface
.as_ref()
.expect("bug: no surface allocated")
.resolve_render_task_id();
let kind = BatchKind::Brush(
BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
);
let key = BatchKey::new(
kind,
non_segmented_blend_mode,
BatchTextures::render_target_cache(),
);
let batch = self.batch_list.get_suitable_batch(
key,
bounding_rect,
);
let uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache)
.as_int();
let prim_header_index = prim_headers.push(&prim_header, [
uv_rect_address,
(ShaderColorMode::Image as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(),
};
batch.push(PrimitiveInstance::from(instance));
false
}
None => {
true
// If this picture is being drawn into an existing target (i.e. with
// no composition operation), recurse and add to the current batch list.
self.add_pic_to_batch(
picture,
task_id,
ctx,
gpu_cache,
render_tasks,
deferred_resolves,
prim_headers,
);
}
};
// If this picture is being drawn into an existing target (i.e. with
// no composition operation), recurse and add to the current batch list.
if add_to_parent_pic {
self.add_pic_to_batch(
picture,
task_id,
ctx,
gpu_cache,
render_tasks,
deferred_resolves,
prim_headers,
);
}
}
BrushKind::Image { request, ref visible_tiles, .. } if !visible_tiles.is_empty() => {

Просмотреть файл

@ -201,40 +201,34 @@ impl<'a> DisplayListFlattener<'a> {
}
pub trait BorderSideHelpers {
fn border_color(
&self,
scale_factor_0: f32,
scale_factor_1: f32,
black_color_0: f32,
black_color_1: f32,
) -> ColorF;
fn border_color(&self, is_inner_border: bool) -> ColorF;
}
impl BorderSideHelpers for BorderSide {
fn border_color(
&self,
scale_factor_0: f32,
scale_factor_1: f32,
black_color_0: f32,
black_color_1: f32,
) -> ColorF {
match self.style {
BorderStyle::Inset => {
if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
self.color.scale_rgb(scale_factor_1)
} else {
ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
}
}
BorderStyle::Outset => {
if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
self.color.scale_rgb(scale_factor_0)
} else {
ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
}
}
_ => self.color,
fn border_color(&self, is_inner_border: bool) -> ColorF {
let lighter = match self.style {
BorderStyle::Inset => is_inner_border,
BorderStyle::Outset => !is_inner_border,
_ => return self.color,
};
// The modulate colors below are not part of the specification. They are
// derived from the Gecko source code and experimentation, and used to
// modulate the colors in order to generate colors for the inset/outset
// and groove/ridge border styles.
//
// NOTE(emilio): Gecko at least takes the background color into
// account, should we do the same? Looks a bit annoying for this.
//
// NOTE(emilio): If you change this algorithm, do the same change on
// get_colors_for_side in cs_border_segment.glsl.
if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
let scale = if lighter { 1.0 } else { 2.0 / 3.0 };
return self.color.scale_rgb(scale)
}
let black = if lighter { 0.7 } else { 0.3 };
ColorF::new(black, black, black, self.color.a)
}
}
@ -912,21 +906,8 @@ impl BorderRenderTaskInfo {
side1.style
};
// These modulate colors are not part of the specification. They
// are derived from the Gecko source code and experimentation, and
// used to modulate the colors in order to generate colors for
// the inset/outset and groove/ridge border styles.
let color0 = if flip0 {
side0.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
} else {
side0.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
};
let color1 = if flip1 {
side1.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
} else {
side1.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
};
let color0 = side0.border_color(flip0);
let color1 = side1.border_color(flip1);
add_segment(
info.task_rect,

Просмотреть файл

@ -425,6 +425,7 @@ impl ClipStore {
gpu_cache: &mut GpuCache,
resource_cache: &mut ResourceCache,
device_pixel_scale: DevicePixelScale,
world_rect: &WorldRect,
) -> Option<ClipChainInstance> {
let mut local_clip_rect = local_prim_clip_rect;
let spatial_nodes = &clip_scroll_tree.spatial_nodes;
@ -472,17 +473,11 @@ impl ClipStore {
if let Some(clip_rect) = clip_node.item.get_local_clip_rect() {
match conversion {
ClipSpaceConversion::Local => {
local_clip_rect = match local_clip_rect.intersection(&clip_rect) {
Some(local_clip_rect) => local_clip_rect,
None => return None,
};
local_clip_rect = local_clip_rect.intersection(&clip_rect)?;
}
ClipSpaceConversion::Offset(ref offset) => {
let clip_rect = clip_rect.translate(offset);
local_clip_rect = match local_clip_rect.intersection(&clip_rect) {
Some(local_clip_rect) => local_clip_rect,
None => return None,
};
local_clip_rect = local_clip_rect.intersection(&clip_rect)?;
}
ClipSpaceConversion::Transform(..) => {
// TODO(gw): In the future, we can reduce the size
@ -508,20 +503,11 @@ impl ClipStore {
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
}
let local_bounding_rect = match local_prim_rect.intersection(&local_clip_rect) {
Some(rect) => rect,
None => return None,
};
let local_bounding_rect = local_prim_rect.intersection(&local_clip_rect)?;
let pic_clip_rect = match prim_to_pic_mapper.map(&local_bounding_rect) {
Some(pic_bounding_rect) => pic_bounding_rect,
None => return None,
};
let pic_clip_rect = prim_to_pic_mapper.map(&local_bounding_rect)?;
let world_clip_rect = match pic_to_world_mapper.map(&pic_clip_rect) {
Some(world_clip_rect) => world_clip_rect,
None => return None,
};
let world_clip_rect = pic_to_world_mapper.map(&pic_clip_rect)?;
// Now, we've collected all the clip nodes that *potentially* affect this
// primitive region, and reduced the size of the prim region as much as possible.
@ -550,6 +536,7 @@ impl ClipStore {
node.item.get_clip_result_complex(
transform,
&world_clip_rect,
world_rect,
)
}
};
@ -869,6 +856,7 @@ impl ClipItem {
&self,
transform: &LayoutToWorldTransform,
prim_world_rect: &WorldRect,
world_rect: &WorldRect,
) -> ClipResult {
let (clip_rect, inner_rect) = match *self {
ClipItem::Rectangle(clip_rect, ClipMode::Clip) => {
@ -897,7 +885,11 @@ impl ClipItem {
}
}
let outer_clip_rect = match project_rect(transform, &clip_rect) {
let outer_clip_rect = match project_rect(
transform,
&clip_rect,
world_rect,
) {
Some(outer_clip_rect) => outer_clip_rect,
None => return ClipResult::Partial,
};

Просмотреть файл

@ -963,8 +963,8 @@ impl<'a> DisplayListFlattener<'a> {
// If not already isolated for some other reason,
// make this picture as isolated.
if parent_pic.composite_mode.is_none() {
parent_pic.composite_mode = Some(PictureCompositeMode::Blit);
if parent_pic.requested_composite_mode.is_none() {
parent_pic.requested_composite_mode = Some(PictureCompositeMode::Blit);
}
}

Просмотреть файл

@ -12,7 +12,7 @@ use gpu_cache::GpuCache;
use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind};
use hit_test::{HitTester, HitTestingRun};
use internal_types::{FastHashMap};
use picture::PictureSurface;
use picture::{PictureCompositeMode, PictureSurface, RasterConfig};
use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveStore, Transform, SpaceMapper};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_backend::FrameId;
@ -24,7 +24,7 @@ use std::f32;
use std::sync::Arc;
use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
use util;
use util::{self, MaxRect};
#[derive(Clone, Copy, Debug, PartialEq)]
@ -108,14 +108,24 @@ impl PictureState {
pub fn new(
ref_spatial_node_index: SpatialNodeIndex,
clip_scroll_tree: &ClipScrollTree,
world_rect: WorldRect,
) -> Self {
let map_local_to_pic = SpaceMapper::new(ref_spatial_node_index);
let mut map_pic_to_world = SpaceMapper::new(SpatialNodeIndex(0));
let mut map_pic_to_world = SpaceMapper::new(
SpatialNodeIndex(0),
world_rect,
);
map_pic_to_world.set_target_spatial_node(
ref_spatial_node_index,
clip_scroll_tree,
);
let pic_bounds = map_pic_to_world.unmap(
&world_rect,
).unwrap_or(PictureRect::max_rect());
let map_local_to_pic = SpaceMapper::new(
ref_spatial_node_index,
pic_bounds,
);
PictureState {
tasks: Vec::new(),
@ -246,6 +256,7 @@ impl FrameBuilder {
let mut pic_state = PictureState::new(
root_spatial_node_index,
&frame_context.clip_scroll_tree,
frame_context.world_rect,
);
let pic_context = self
@ -290,7 +301,10 @@ impl FrameBuilder {
);
let render_task_id = frame_state.render_tasks.add(root_render_task);
pic.surface = Some(PictureSurface::RenderTask(render_task_id));
pic.raster_config = Some(RasterConfig {
composite_mode: PictureCompositeMode::Blit,
surface: Some(PictureSurface::RenderTask(render_task_id)),
});
Some(render_task_id)
}

Просмотреть файл

@ -29,6 +29,15 @@ use util::{TransformedRectKind, world_rect_to_device_pixels};
this picture (e.g. in screen space or local space).
*/
#[derive(Debug)]
pub struct RasterConfig {
pub composite_mode: PictureCompositeMode,
// If this picture is drawn to an intermediate surface,
// the associated target information.
pub surface: Option<PictureSurface>,
}
/// Specifies how this Picture should be composited
/// onto the target it belongs to.
#[derive(Debug, Copy, Clone, PartialEq)]
@ -116,10 +125,6 @@ pub struct PictureCacheKey {
#[derive(Debug)]
pub struct PicturePrimitive {
// If this picture is drawn to an intermediate surface,
// the associated target information.
pub surface: Option<PictureSurface>,
// List of primitive runs that make up this picture.
pub runs: Vec<PrimitiveRun>,
pub state: Option<PictureState>,
@ -140,7 +145,8 @@ pub struct PicturePrimitive {
pub secondary_render_task_id: Option<RenderTaskId>,
/// How this picture should be composited.
/// If None, don't composite - just draw directly on parent surface.
pub composite_mode: Option<PictureCompositeMode>,
pub requested_composite_mode: Option<PictureCompositeMode>,
pub raster_config: Option<RasterConfig>,
// If true, this picture is part of a 3D context.
pub is_in_3d_context: bool,
// If requested as a frame output (for rendering
@ -158,7 +164,7 @@ pub struct PicturePrimitive {
impl PicturePrimitive {
fn resolve_scene_properties(&mut self, properties: &SceneProperties) -> bool {
match self.composite_mode {
match self.requested_composite_mode {
Some(PictureCompositeMode::Filter(ref mut filter)) => {
match *filter {
FilterOp::Opacity(ref binding, ref mut value) => {
@ -175,7 +181,7 @@ impl PicturePrimitive {
pub fn new_image(
id: PictureId,
composite_mode: Option<PictureCompositeMode>,
requested_composite_mode: Option<PictureCompositeMode>,
is_in_3d_context: bool,
pipeline_id: PipelineId,
frame_output_pipeline_id: Option<PipelineId>,
@ -184,9 +190,9 @@ impl PicturePrimitive {
PicturePrimitive {
runs: Vec::new(),
state: None,
surface: None,
secondary_render_task_id: None,
composite_mode,
requested_composite_mode,
raster_config: None,
is_in_3d_context,
frame_output_pipeline_id,
extra_gpu_data_handle: GpuCacheHandle::new(),
@ -196,21 +202,6 @@ impl PicturePrimitive {
}
}
pub fn can_draw_directly_to_parent_surface(&self) -> bool {
match self.composite_mode {
Some(PictureCompositeMode::Filter(filter)) => {
filter.is_noop()
}
Some(PictureCompositeMode::Blit) |
Some(PictureCompositeMode::MixBlend(..)) => {
false
}
None => {
true
}
}
}
pub fn take_context(
&mut self,
parent_allows_subpixel_aa: bool,
@ -225,13 +216,25 @@ impl PicturePrimitive {
return None;
}
let actual_composite_mode = match self.requested_composite_mode {
Some(PictureCompositeMode::Filter(filter)) if filter.is_noop() => None,
mode => mode,
};
self.raster_config = actual_composite_mode.map(|composite_mode| {
RasterConfig {
composite_mode,
surface: None,
}
});
// Disallow subpixel AA if an intermediate surface is needed.
// TODO(lsalzman): allow overriding parent if intermediate surface is opaque
let allow_subpixel_aa = parent_allows_subpixel_aa &&
self.can_draw_directly_to_parent_surface();
self.raster_config.is_none();
let inflation_factor = match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let inflation_factor = match self.raster_config {
Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)), .. }) => {
// The amount of extra space needed for primitives inside
// this picture to ensure the visibility check is correct.
BLUR_SAMPLE_SCALE * blur_radius
@ -247,7 +250,7 @@ impl PicturePrimitive {
apply_local_clip_rect: self.apply_local_clip_rect,
inflation_factor,
allow_subpixel_aa,
has_surface: !self.can_draw_directly_to_parent_surface(),
has_surface: self.raster_config.is_some(),
})
}
@ -281,12 +284,12 @@ impl PicturePrimitive {
Some(local_rect) => {
let local_content_rect = LayoutRect::from_untyped(&local_rect.to_untyped());
match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
match self.raster_config {
Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)), .. }) => {
let inflate_size = (blur_radius * BLUR_SAMPLE_SCALE).ceil();
local_content_rect.inflate(inflate_size, inflate_size)
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, blur_radius, _))) => {
Some(RasterConfig { composite_mode: PictureCompositeMode::Filter(FilterOp::DropShadow(_, blur_radius, _)), .. }) => {
let inflate_size = (blur_radius * BLUR_SAMPLE_SCALE).ceil();
local_content_rect.inflate(inflate_size, inflate_size)
@ -306,7 +309,7 @@ impl PicturePrimitive {
}
}
None => {
assert!(self.can_draw_directly_to_parent_surface());
assert!(self.raster_config.is_none());
LayoutRect::zero()
}
}
@ -327,324 +330,326 @@ impl PicturePrimitive {
) {
let mut pic_state_for_children = self.take_state();
if self.can_draw_directly_to_parent_surface() {
pic_state.tasks.extend(pic_state_for_children.tasks);
self.surface = None;
return;
}
match self.raster_config {
Some(ref mut raster_config) => {
let clipped_world_rect = prim_metadata
.clipped_world_rect
.as_ref()
.expect("bug: trying to draw an off-screen picture!?");
let clipped_world_rect = prim_metadata
.clipped_world_rect
.as_ref()
.expect("bug: trying to draw an off-screen picture!?");
let clipped = world_rect_to_device_pixels(
*clipped_world_rect,
frame_context.device_pixel_scale,
).to_i32();
let clipped = world_rect_to_device_pixels(
*clipped_world_rect,
frame_context.device_pixel_scale,
).to_i32();
let pic_rect = pic_state.map_local_to_pic
.map(&prim_metadata.local_rect)
.unwrap();
let world_rect = pic_state.map_pic_to_world
.map(&pic_rect)
.unwrap();
let pic_rect = pic_state.map_local_to_pic
.map(&prim_metadata.local_rect)
.unwrap();
let world_rect = pic_state.map_pic_to_world
.map(&pic_rect)
.unwrap();
let unclipped = world_rect_to_device_pixels(
world_rect,
frame_context.device_pixel_scale,
);
// TODO(gw): Almost all of the Picture types below use extra_gpu_cache_data
// to store the same type of data. The exception is the filter
// with a ColorMatrix, which stores the color matrix here. It's
// probably worth tidying this code up to be a bit more consistent.
// Perhaps store the color matrix after the common data, even though
// it's not used by that shader.
match self.composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = clipped
.inflate(blur_range, blur_range)
.intersection(&unclipped.to_i32())
.unwrap();
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&device_rect,
let unclipped = world_rect_to_device_pixels(
world_rect,
frame_context.device_pixel_scale,
);
// If we are drawing a blur that has primitives or clips that contain
// a complex coordinate system, don't bother caching them (for now).
// It's likely that they are animating and caching may not help here
// anyway. In the future we should relax this a bit, so that we can
// cache tasks with complex coordinate systems if we detect the
// relevant transforms haven't changed from frame to frame.
let surface = if pic_state_for_children.has_non_root_coord_system {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
prim_index,
device_rect.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
// TODO(gw): Almost all of the Picture types below use extra_gpu_cache_data
// to store the same type of data. The exception is the filter
// with a ColorMatrix, which stores the color matrix here. It's
// probably worth tidying this code up to be a bit more consistent.
// Perhaps store the color matrix after the common data, even though
// it's not used by that shader.
let picture_task_id = frame_state.render_tasks.add(picture_task);
match raster_config.composite_mode {
PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = clipped
.inflate(blur_range, blur_range)
.intersection(&unclipped.to_i32())
.unwrap();
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
PictureSurface::RenderTask(render_task_id)
} else {
// Get the relative clipped rect within the overall prim rect, that
// forms part of the cache key.
let pic_relative_render_rect = PictureIntRect::new(
PictureIntPoint::new(
device_rect.origin.x - unclipped.origin.x as i32,
device_rect.origin.y - unclipped.origin.y as i32,
),
PictureIntSize::new(
device_rect.size.width,
device_rect.size.height,
),
);
// Request a render task that will cache the output in the
// texture cache.
let cache_item = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
size: device_rect.size,
kind: RenderTaskCacheKeyKind::Picture(PictureCacheKey {
scene_id: frame_context.scene_id,
picture_id: self.id,
unclipped_size: unclipped.size.to_i32(),
pic_relative_render_rect,
}),
},
frame_state.gpu_cache,
frame_state.render_tasks,
None,
false,
|render_tasks| {
let child_tasks = mem::replace(&mut pic_state_for_children.tasks, Vec::new());
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&device_rect,
frame_context.device_pixel_scale,
);
// If we are drawing a blur that has primitives or clips that contain
// a complex coordinate system, don't bother caching them (for now).
// It's likely that they are animating and caching may not help here
// anyway. In the future we should relax this a bit, so that we can
// cache tasks with complex coordinate systems if we detect the
// relevant transforms haven't changed from frame to frame.
let surface = if pic_state_for_children.has_non_root_coord_system {
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
prim_index,
device_rect.origin,
child_tasks,
pic_state_for_children.tasks,
uv_rect_kind,
);
let picture_task_id = render_tasks.add(picture_task);
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
let render_task_id = render_tasks.add(blur_render_task);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
render_task_id
PictureSurface::RenderTask(render_task_id)
} else {
// Get the relative clipped rect within the overall prim rect, that
// forms part of the cache key.
let pic_relative_render_rect = PictureIntRect::new(
PictureIntPoint::new(
device_rect.origin.x - unclipped.origin.x as i32,
device_rect.origin.y - unclipped.origin.y as i32,
),
PictureIntSize::new(
device_rect.size.width,
device_rect.size.height,
),
);
// Request a render task that will cache the output in the
// texture cache.
let cache_item = frame_state.resource_cache.request_render_task(
RenderTaskCacheKey {
size: device_rect.size,
kind: RenderTaskCacheKeyKind::Picture(PictureCacheKey {
scene_id: frame_context.scene_id,
picture_id: self.id,
unclipped_size: unclipped.size.to_i32(),
pic_relative_render_rect,
}),
},
frame_state.gpu_cache,
frame_state.render_tasks,
None,
false,
|render_tasks| {
let child_tasks = mem::replace(&mut pic_state_for_children.tasks, Vec::new());
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
prim_index,
device_rect.origin,
child_tasks,
uv_rect_kind,
);
let picture_task_id = render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation,
picture_task_id,
render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
let render_task_id = render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
render_task_id
}
);
PictureSurface::TextureCache(cache_item)
};
raster_config.surface = Some(surface);
}
PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color)) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = clipped
.inflate(blur_range, blur_range)
.intersection(&unclipped.to_i32())
.unwrap();
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&device_rect,
frame_context.device_pixel_scale,
);
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
prim_index,
device_rect.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
picture_task.mark_for_saving();
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation.round(),
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
self.secondary_render_task_id = Some(picture_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
raster_config.surface = Some(PictureSurface::RenderTask(render_task_id));
// If the local rect of the contents changed, force the cache handle
// to be invalidated so that the primitive data below will get
// uploaded to the GPU this frame. This can occur during property
// animation.
if pic_state.local_rect_changed {
frame_state.gpu_cache.invalidate(&mut self.extra_gpu_data_handle);
}
);
PictureSurface::TextureCache(cache_item)
};
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
// TODO(gw): This is very hacky code below! It stores an extra
// brush primitive below for the special case of a
// drop-shadow where we need a different local
// rect for the shadow. To tidy this up in future,
// we could consider abstracting the code in prim_store.rs
// that writes a brush primitive header.
self.surface = Some(surface);
}
Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => {
let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0;
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
// [brush specific data]
// [segment_rect, segment data]
let shadow_rect = prim_metadata.local_rect.translate(&offset);
// The clipped field is the part of the picture that is visible
// on screen. The unclipped field is the screen-space rect of
// the complete picture, if no screen / clip-chain was applied
// (this includes the extra space for blur region). To ensure
// that we draw a large enough part of the picture to get correct
// blur results, inflate that clipped area by the blur range, and
// then intersect with the total screen rect, to minimize the
// allocation size.
let device_rect = clipped
.inflate(blur_range, blur_range)
.intersection(&unclipped.to_i32())
.unwrap();
// ImageBrush colors
request.push(color.premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([
prim_metadata.local_rect.size.width,
prim_metadata.local_rect.size.height,
0.0,
0.0,
]);
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&device_rect,
frame_context.device_pixel_scale,
);
let mut picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, device_rect.size),
unclipped.size,
prim_index,
device_rect.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
picture_task.mark_for_saving();
let picture_task_id = frame_state.render_tasks.add(picture_task);
let blur_render_task = RenderTask::new_blur(
blur_std_deviation.round(),
picture_task_id,
frame_state.render_tasks,
RenderTargetKind::Color,
ClearMode::Transparent,
);
self.secondary_render_task_id = Some(picture_task_id);
let render_task_id = frame_state.render_tasks.add(blur_render_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
// If the local rect of the contents changed, force the cache handle
// to be invalidated so that the primitive data below will get
// uploaded to the GPU this frame. This can occur during property
// animation.
if pic_state.local_rect_changed {
frame_state.gpu_cache.invalidate(&mut self.extra_gpu_data_handle);
}
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
// TODO(gw): This is very hacky code below! It stores an extra
// brush primitive below for the special case of a
// drop-shadow where we need a different local
// rect for the shadow. To tidy this up in future,
// we could consider abstracting the code in prim_store.rs
// that writes a brush primitive header.
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
// [brush specific data]
// [segment_rect, segment data]
let shadow_rect = prim_metadata.local_rect.translate(&offset);
// ImageBrush colors
request.push(color.premultiplied());
request.push(PremultipliedColorF::WHITE);
request.push([
prim_metadata.local_rect.size.width,
prim_metadata.local_rect.size.height,
0.0,
0.0,
]);
// segment rect / extra data
request.push(shadow_rect);
request.push([0.0, 0.0, 0.0, 0.0]);
}
}
Some(PictureCompositeMode::MixBlend(..)) => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Filter(filter)) => {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
// segment rect / extra data
request.push(shadow_rect);
request.push([0.0, 0.0, 0.0, 0.0]);
}
}
PictureCompositeMode::MixBlend(..) => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let readback_task_id = frame_state.render_tasks.add(
RenderTask::new_readback(clipped)
);
self.secondary_render_task_id = Some(readback_task_id);
pic_state.tasks.push(readback_task_id);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
raster_config.surface = Some(PictureSurface::RenderTask(render_task_id));
}
PictureCompositeMode::Filter(filter) => {
if let FilterOp::ColorMatrix(m) = filter {
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
for i in 0..5 {
request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]);
}
}
}
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
raster_config.surface = Some(PictureSurface::RenderTask(render_task_id));
}
PictureCompositeMode::Blit => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
raster_config.surface = Some(PictureSurface::RenderTask(render_task_id));
}
}
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
}
Some(PictureCompositeMode::Blit) | None => {
let uv_rect_kind = calculate_uv_rect_kind(
&prim_metadata.local_rect,
&prim_context.transform,
&clipped,
frame_context.device_pixel_scale,
);
let picture_task = RenderTask::new_picture(
RenderTaskLocation::Dynamic(None, clipped.size),
unclipped.size,
prim_index,
clipped.origin,
pic_state_for_children.tasks,
uv_rect_kind,
);
let render_task_id = frame_state.render_tasks.add(picture_task);
pic_state.tasks.push(render_task_id);
self.surface = Some(PictureSurface::RenderTask(render_task_id));
None => {
pic_state.tasks.extend(pic_state_for_children.tasks);
}
}
}

Просмотреть файл

@ -116,14 +116,19 @@ pub struct SpaceMapper<F, T> {
kind: CoordinateSpaceMapping<F, T>,
pub ref_spatial_node_index: SpatialNodeIndex,
current_target_spatial_node_index: SpatialNodeIndex,
bounds: TypedRect<f32, T>,
}
impl<F, T> SpaceMapper<F, T> where F: fmt::Debug {
pub fn new(ref_spatial_node_index: SpatialNodeIndex) -> Self {
pub fn new(
ref_spatial_node_index: SpatialNodeIndex,
bounds: TypedRect<f32, T>,
) -> Self {
SpaceMapper {
kind: CoordinateSpaceMapping::Local,
ref_spatial_node_index,
current_target_spatial_node_index: ref_spatial_node_index,
bounds,
}
}
@ -161,6 +166,21 @@ impl<F, T> SpaceMapper<F, T> where F: fmt::Debug {
}
}
pub fn unmap(&self, rect: &TypedRect<f32, T>) -> Option<TypedRect<f32, F>> {
match self.kind {
CoordinateSpaceMapping::Local => {
Some(TypedRect::from_untyped(&rect.to_untyped()))
}
CoordinateSpaceMapping::Offset(ref offset) => {
let offset = TypedVector2D::new(-offset.x, -offset.y);
Some(TypedRect::from_untyped(&rect.translate(&offset).to_untyped()))
}
CoordinateSpaceMapping::Transform(ref transform) => {
transform.inverse_rect_footprint(rect)
}
}
}
pub fn map(&self, rect: &TypedRect<f32, F>) -> Option<TypedRect<f32, T>> {
match self.kind {
CoordinateSpaceMapping::Local => {
@ -170,7 +190,7 @@ impl<F, T> SpaceMapper<F, T> where F: fmt::Debug {
Some(TypedRect::from_untyped(&rect.translate(offset).to_untyped()))
}
CoordinateSpaceMapping::Transform(ref transform) => {
match project_rect(transform, rect) {
match project_rect(transform, rect, &self.bounds) {
Some(bounds) => {
Some(bounds)
}
@ -408,7 +428,10 @@ impl BrushKind {
// Construct a brush that is a border with `border` style and `widths`
// dimensions.
pub fn new_border(border: NormalBorder, widths: BorderWidths) -> BrushKind {
pub fn new_border(mut border: NormalBorder, widths: BorderWidths) -> BrushKind {
// FIXME(emilio): Is this the best place to do this?
border.normalize(&widths);
let cache_key = BorderCacheKey::new(&border, &widths);
BrushKind::Border {
source: BorderSource::Border {
@ -527,7 +550,7 @@ impl BrushPrimitive {
pub fn may_need_clip_mask(&self) -> bool {
match self.kind {
BrushKind::Picture(ref pic) => {
pic.composite_mode.is_some()
pic.raster_config.is_some()
}
_ => {
true
@ -1465,7 +1488,7 @@ impl PrimitiveStore {
// If we encounter a picture that is a pass-through
// (i.e. no composite mode), then we can recurse into
// that to try and find a primitive to collapse to.
if pic.composite_mode.is_none() {
if pic.requested_composite_mode.is_none() {
return self.get_opacity_collapse_prim(run.base_prim_index);
}
}
@ -1496,7 +1519,7 @@ impl PrimitiveStore {
pic_prim_index: PrimitiveIndex,
) {
// Only handle opacity filters for now.
let binding = match self.get_pic(pic_prim_index).composite_mode {
let binding = match self.get_pic(pic_prim_index).requested_composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Opacity(binding, _))) => {
binding
}
@ -1544,7 +1567,7 @@ impl PrimitiveStore {
// intermediate surface or incur an extra blend / blit. Instead,
// the collapsed primitive will be drawn directly into the
// parent picture.
self.get_pic_mut(pic_prim_index).composite_mode = None;
self.get_pic_mut(pic_prim_index).requested_composite_mode = None;
}
pub fn prim_count(&self) -> usize {
@ -1601,6 +1624,7 @@ impl PrimitiveStore {
let mut pic_state_for_children = PictureState::new(
root_spatial_node_index,
frame_context.clip_scroll_tree,
frame_context.world_rect,
);
// Mark whether this picture has a complex coordinate system.
@ -1693,6 +1717,7 @@ impl PrimitiveStore {
frame_state.gpu_cache,
frame_state.resource_cache,
frame_context.device_pixel_scale,
&frame_context.world_rect,
);
let clip_chain = match clip_chain {
@ -2210,6 +2235,7 @@ impl Primitive {
frame_state.gpu_cache,
frame_state.resource_cache,
frame_context.device_pixel_scale,
&frame_context.world_rect,
);
match segment_clip_chain {

Просмотреть файл

@ -7,7 +7,7 @@ use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest};
use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use api::{FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
use api::{ExternalImageData, ExternalImageType, BlobImageResult, BlobImageParams};
use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
use api::{GlyphDimensions, IdNamespace};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
use api::{TileOffset, TileSize, TileRange, NormalizedRect, BlobImageData};
@ -350,6 +350,23 @@ impl BlobImageResources for Resources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate {
self.font_templates.get(&key).unwrap()
}
fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData> {
match self.font_instances.read().unwrap().get(&key) {
Some(instance) => Some(FontInstanceData {
font_key: instance.font_key,
size: instance.size,
options: Some(FontInstanceOptions {
render_mode: instance.render_mode,
flags: instance.flags,
bg_color: instance.bg_color,
synthetic_italics: instance.synthetic_italics,
}),
platform_options: instance.platform_options,
variations: instance.variations.clone(),
}),
None => None,
}
}
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)> {
self.image_templates
.get(key)

Просмотреть файл

@ -22,7 +22,7 @@ pub trait MatrixHelpers<Src, Dst> {
fn has_2d_inverse(&self) -> bool;
fn exceeds_2d_scale(&self, limit: f64) -> bool;
fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>>;
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> Option<TypedRect<f32, Src>>;
fn transform_kind(&self) -> TransformedRectKind;
fn is_simple_translation(&self) -> bool;
fn is_simple_2d_translation(&self) -> bool;
@ -90,13 +90,13 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
m.inverse().map(|inv| TypedPoint2D::new(inv.m31, inv.m32))
}
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src> {
TypedRect::from_points(&[
self.inverse_project(&rect.origin).unwrap_or(TypedPoint2D::zero()),
self.inverse_project(&rect.top_right()).unwrap_or(TypedPoint2D::zero()),
self.inverse_project(&rect.bottom_left()).unwrap_or(TypedPoint2D::zero()),
self.inverse_project(&rect.bottom_right()).unwrap_or(TypedPoint2D::zero()),
])
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> Option<TypedRect<f32, Src>> {
Some(TypedRect::from_points(&[
self.inverse_project(&rect.origin)?,
self.inverse_project(&rect.top_right())?,
self.inverse_project(&rect.bottom_left())?,
self.inverse_project(&rect.bottom_right())?,
]))
}
fn transform_kind(&self) -> TransformedRectKind {
@ -393,7 +393,7 @@ impl<Src, Dst> FastTransform<Src, Dst> {
FastTransform::Transform { inverse: Some(ref inverse), is_2d: true, .. } =>
inverse.transform_rect(rect),
FastTransform::Transform { ref transform, is_2d: false, .. } =>
Some(transform.inverse_rect_footprint(rect)),
transform.inverse_rect_footprint(rect),
FastTransform::Transform { inverse: None, .. } => None,
}
}
@ -446,6 +446,7 @@ pub type LayoutToWorldFastTransform = FastTransform<LayoutPixel, WorldPixel>;
pub fn project_rect<F, T>(
transform: &TypedTransform3D<f32, F, T>,
rect: &TypedRect<f32, F>,
bounds: &TypedRect<f32, T>,
) -> Option<TypedRect<f32, T>>
where F: fmt::Debug
{
@ -462,7 +463,7 @@ pub fn project_rect<F, T>(
let mut clipper = Clipper::new();
clipper.add_frustum(
transform,
None,
Some(*bounds),
);
let polygon = Polygon::from_rect(*rect, 1);

Просмотреть файл

@ -273,6 +273,33 @@ impl NormalBorder {
b.bottom.color = color;
b
}
/// Normalizes a border so that we don't render disallowed stuff, like inset
/// borders that are less than two pixels wide.
#[inline]
pub fn normalize(&mut self, widths: &BorderWidths) {
#[inline]
fn renders_small_border_solid(style: BorderStyle) -> bool {
match style {
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Inset |
BorderStyle::Outset => true,
_ => false,
}
}
let normalize_side = |side: &mut BorderSide, width: f32| {
if renders_small_border_solid(side.style) && width < 2. {
side.style = BorderStyle::Solid;
}
};
normalize_side(&mut self.left, widths.left);
normalize_side(&mut self.right, widths.right);
normalize_side(&mut self.top, widths.top);
normalize_side(&mut self.bottom, widths.bottom);
}
}
#[repr(u32)]

Просмотреть файл

@ -2,6 +2,7 @@
* 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 app_units::Au;
#[cfg(target_os = "macos")]
use core_foundation::string::CFString;
#[cfg(target_os = "macos")]
@ -347,6 +348,15 @@ impl FontInstanceKey {
}
}
#[derive(Clone)]
pub struct FontInstanceData {
pub font_key: FontKey,
pub size: Au,
pub options: Option<FontInstanceOptions>,
pub platform_options: Option<FontInstancePlatformOptions>,
pub variations: Vec<FontVariation>,
}
pub type GlyphIndex = u32;
#[repr(C)]

Просмотреть файл

@ -4,7 +4,7 @@
extern crate serde_bytes;
use font::{FontInstanceKey, FontKey, FontTemplate};
use font::{FontInstanceKey, FontInstanceData, FontKey, FontTemplate};
use std::sync::Arc;
use {DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
use {IdNamespace, TileOffset, TileSize};
@ -177,6 +177,7 @@ impl ImageData {
/// The resources exposed by the resource cache available for use by the blob rasterizer.
pub trait BlobImageResources {
fn get_font_data(&self, key: FontKey) -> &FontTemplate;
fn get_font_instance_data(&self, key: FontInstanceKey) -> Option<FontInstanceData>;
fn get_image(&self, key: ImageKey) -> Option<(&ImageData, &ImageDescriptor)>;
}

Просмотреть файл

@ -1 +1 @@
3fa5eb8aaa0172306bfdc5e87d1d0c9af39d103a
d89e290c57aab76c45d8016975240cf762354e39