зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1487885. Update webrender to d89e290c57aab76c45d8016975240cf762354e39
This commit is contained in:
Родитель
028a5e54ee
Коммит
ae8d2d3c90
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче