зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1501322 - Update webrender to 9b1a2f7e46cfb3496d43421b828543b08bb45810. r=kats
Differential Revision: https://phabricator.services.mozilla.com/D9539 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
2ee98a6df4
Коммит
b0e8d7dd2d
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
#include shared,clip_shared
|
#include shared,clip_shared
|
||||||
|
|
||||||
varying vec3 vLocalPos;
|
varying vec2 vLocalPos;
|
||||||
varying vec3 vClipMaskImageUv;
|
varying vec2 vClipMaskImageUv;
|
||||||
|
|
||||||
flat varying vec4 vClipMaskUvRect;
|
flat varying vec4 vClipMaskUvRect;
|
||||||
flat varying vec4 vClipMaskUvInnerRect;
|
flat varying vec4 vClipMaskUvInnerRect;
|
||||||
|
@ -13,13 +13,15 @@ flat varying float vLayer;
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
struct ImageMaskData {
|
struct ImageMaskData {
|
||||||
RectWithSize local_rect;
|
RectWithSize local_mask_rect;
|
||||||
|
RectWithSize local_tile_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageMaskData fetch_mask_data(ivec2 address) {
|
ImageMaskData fetch_mask_data(ivec2 address) {
|
||||||
vec4 data = fetch_from_gpu_cache_1_direct(address);
|
vec4 data[2] = fetch_from_gpu_cache_2_direct(address);
|
||||||
RectWithSize local_rect = RectWithSize(data.xy, data.zw);
|
RectWithSize mask_rect = RectWithSize(data[0].xy, data[0].zw);
|
||||||
ImageMaskData mask_data = ImageMaskData(local_rect);
|
RectWithSize tile_rect = RectWithSize(data[1].xy, data[1].zw);
|
||||||
|
ImageMaskData mask_data = ImageMaskData(mask_rect, tile_rect);
|
||||||
return mask_data;
|
return mask_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ void main(void) {
|
||||||
Transform clip_transform = fetch_transform(cmi.clip_transform_id);
|
Transform clip_transform = fetch_transform(cmi.clip_transform_id);
|
||||||
Transform prim_transform = fetch_transform(cmi.prim_transform_id);
|
Transform prim_transform = fetch_transform(cmi.prim_transform_id);
|
||||||
ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
|
ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
|
||||||
RectWithSize local_rect = mask.local_rect;
|
RectWithSize local_rect = mask.local_mask_rect;
|
||||||
ImageResource res = fetch_image_resource_direct(cmi.resource_address);
|
ImageResource res = fetch_image_resource_direct(cmi.resource_address);
|
||||||
|
|
||||||
ClipVertexInfo vi = write_clip_tile_vertex(
|
ClipVertexInfo vi = write_clip_tile_vertex(
|
||||||
|
@ -38,12 +40,9 @@ void main(void) {
|
||||||
clip_transform,
|
clip_transform,
|
||||||
area
|
area
|
||||||
);
|
);
|
||||||
vLocalPos = vi.local_pos;
|
vLocalPos = vi.local_pos.xy / vi.local_pos.z;
|
||||||
vLayer = res.layer;
|
vLayer = res.layer;
|
||||||
|
vClipMaskImageUv = (vLocalPos - mask.local_tile_rect.p0) / mask.local_tile_rect.size;
|
||||||
vec2 local_pos = vLocalPos.xy / vLocalPos.z;
|
|
||||||
|
|
||||||
vClipMaskImageUv = vec3((local_pos - local_rect.p0) / local_rect.size, 0.0);
|
|
||||||
vec2 texture_size = vec2(textureSize(sColor0, 0));
|
vec2 texture_size = vec2(textureSize(sColor0, 0));
|
||||||
vClipMaskUvRect = vec4(res.uv_rect.p0, res.uv_rect.p1 - res.uv_rect.p0) / texture_size.xyxy;
|
vClipMaskUvRect = vec4(res.uv_rect.p0, res.uv_rect.p1 - res.uv_rect.p0) / texture_size.xyxy;
|
||||||
// applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
|
// applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
|
||||||
|
@ -54,17 +53,19 @@ void main(void) {
|
||||||
|
|
||||||
#ifdef WR_FRAGMENT_SHADER
|
#ifdef WR_FRAGMENT_SHADER
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 local_pos = vLocalPos.xy / vLocalPos.z;
|
float alpha = init_transform_fs(vLocalPos);
|
||||||
|
|
||||||
float alpha = init_transform_fs(local_pos);
|
// TODO: Handle repeating masks?
|
||||||
|
vec2 clamped_mask_uv = clamp(vClipMaskImageUv, vec2(0.0, 0.0), vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
// Ensure we don't draw outside of our tile.
|
||||||
|
// FIXME(emilio): Can we do this earlier?
|
||||||
|
if (clamped_mask_uv != vClipMaskImageUv)
|
||||||
|
discard;
|
||||||
|
|
||||||
bool repeat_mask = false; //TODO
|
|
||||||
vec2 clamped_mask_uv = repeat_mask ? fract(vClipMaskImageUv.xy) :
|
|
||||||
clamp(vClipMaskImageUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
|
|
||||||
vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
|
vec2 source_uv = clamp(clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy,
|
||||||
vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw);
|
vClipMaskUvInnerRect.xy, vClipMaskUvInnerRect.zw);
|
||||||
float clip_alpha = texture(sColor0, vec3(source_uv, vLayer)).r; //careful: texture has type A8
|
float clip_alpha = texture(sColor0, vec3(source_uv, vLayer)).r; //careful: texture has type A8
|
||||||
|
|
||||||
oFragColor = vec4(alpha * clip_alpha, 1.0, 1.0, 1.0);
|
oFragColor = vec4(alpha * clip_alpha, 1.0, 1.0, 1.0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1949,37 +1949,51 @@ impl ClipBatcher {
|
||||||
resource_address: GpuCacheAddress::invalid(),
|
resource_address: GpuCacheAddress::invalid(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let gpu_address = gpu_cache.get_address(&clip_node.gpu_cache_handle);
|
|
||||||
|
|
||||||
match clip_node.item {
|
match clip_node.item {
|
||||||
ClipItem::Image(ref mask, is_valid) => {
|
ClipItem::Image { ref mask, ref visible_tiles } => {
|
||||||
if is_valid {
|
let request = ImageRequest {
|
||||||
if let Ok(cache_item) = resource_cache.get_cached_image(
|
key: mask.image,
|
||||||
ImageRequest {
|
rendering: ImageRendering::Auto,
|
||||||
key: mask.image,
|
tile: None,
|
||||||
rendering: ImageRendering::Auto,
|
};
|
||||||
tile: None,
|
let mut add_image = |request: ImageRequest, clip_data_address: GpuCacheAddress| {
|
||||||
|
let cache_item = match resource_cache.get_cached_image(request) {
|
||||||
|
Ok(item) => item,
|
||||||
|
Err(..) => {
|
||||||
|
warn!("Warnings: skip a image mask");
|
||||||
|
debug!("Mask: {:?}, request: {:?}", mask, request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.images
|
||||||
|
.entry(cache_item.texture_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(ClipMaskInstance {
|
||||||
|
clip_data_address,
|
||||||
|
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
|
||||||
|
..instance
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
match *visible_tiles {
|
||||||
|
Some(ref tiles) => {
|
||||||
|
for tile in tiles {
|
||||||
|
add_image(
|
||||||
|
request.with_tile(tile.tile_offset),
|
||||||
|
gpu_cache.get_address(&tile.handle),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
self.images
|
|
||||||
.entry(cache_item.texture_id)
|
|
||||||
.or_insert(Vec::new())
|
|
||||||
.push(ClipMaskInstance {
|
|
||||||
clip_data_address: gpu_address,
|
|
||||||
resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle),
|
|
||||||
..instance
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
warn!("Warnings: skip a image mask");
|
|
||||||
debug!("Key:{:?} Rect::{:?}", mask.image, mask.rect);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else {
|
None => {
|
||||||
warn!("Warnings: clip masks that are tiled blobs are not yet supported (#2852)");
|
let gpu_address =
|
||||||
continue;
|
gpu_cache.get_address(&clip_node.gpu_cache_handle);
|
||||||
|
add_image(request, gpu_address)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClipItem::BoxShadow(ref info) => {
|
ClipItem::BoxShadow(ref info) => {
|
||||||
|
let gpu_address =
|
||||||
|
gpu_cache.get_address(&clip_node.gpu_cache_handle);
|
||||||
let rt_handle = info
|
let rt_handle = info
|
||||||
.cache_handle
|
.cache_handle
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -2002,6 +2016,8 @@ impl ClipBatcher {
|
||||||
ClipItem::Rectangle(_, mode) => {
|
ClipItem::Rectangle(_, mode) => {
|
||||||
if !clip_instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) ||
|
if !clip_instance.flags.contains(ClipNodeFlags::SAME_COORD_SYSTEM) ||
|
||||||
mode == ClipMode::ClipOut {
|
mode == ClipMode::ClipOut {
|
||||||
|
let gpu_address =
|
||||||
|
gpu_cache.get_address(&clip_node.gpu_cache_handle);
|
||||||
self.rectangles.push(ClipMaskInstance {
|
self.rectangles.push(ClipMaskInstance {
|
||||||
clip_data_address: gpu_address,
|
clip_data_address: gpu_address,
|
||||||
..instance
|
..instance
|
||||||
|
@ -2009,6 +2025,8 @@ impl ClipBatcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClipItem::RoundedRectangle(..) => {
|
ClipItem::RoundedRectangle(..) => {
|
||||||
|
let gpu_address =
|
||||||
|
gpu_cache.get_address(&clip_node.gpu_cache_handle);
|
||||||
self.rectangles.push(ClipMaskInstance {
|
self.rectangles.push(ClipMaskInstance {
|
||||||
clip_data_address: gpu_address,
|
clip_data_address: gpu_address,
|
||||||
..instance
|
..instance
|
||||||
|
|
|
@ -14,9 +14,10 @@ use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, ROOT_SPATIAL_NODE_IND
|
||||||
use ellipse::Ellipse;
|
use ellipse::Ellipse;
|
||||||
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
||||||
use gpu_types::{BoxShadowStretchMode};
|
use gpu_types::{BoxShadowStretchMode};
|
||||||
|
use image::{self, Repetition};
|
||||||
use intern;
|
use intern;
|
||||||
use internal_types::FastHashSet;
|
use internal_types::FastHashSet;
|
||||||
use prim_store::{ClipData, ImageMaskData, SpaceMapper};
|
use prim_store::{ClipData, ImageMaskData, SpaceMapper, VisibleMaskImageTile};
|
||||||
use render_task::to_cache_size;
|
use render_task::to_cache_size;
|
||||||
use resource_cache::{ImageRequest, ResourceCache};
|
use resource_cache::{ImageRequest, ResourceCache};
|
||||||
use std::{cmp, u32};
|
use std::{cmp, u32};
|
||||||
|
@ -145,14 +146,14 @@ impl From<ClipItemKey> for ClipNode {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ClipItemKey::ImageMask(rect, image, repeat) => {
|
ClipItemKey::ImageMask(rect, image, repeat) => {
|
||||||
ClipItem::Image(
|
ClipItem::Image {
|
||||||
ImageMask {
|
mask: ImageMask {
|
||||||
image,
|
image,
|
||||||
rect: LayoutRect::from_au(rect),
|
rect: LayoutRect::from_au(rect),
|
||||||
repeat,
|
repeat,
|
||||||
},
|
},
|
||||||
true,
|
visible_tiles: None,
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
ClipItemKey::BoxShadow(shadow_rect, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => {
|
ClipItemKey::BoxShadow(shadow_rect, shadow_radius, prim_shadow_rect, blur_radius, clip_mode) => {
|
||||||
ClipItem::new_box_shadow(
|
ClipItem::new_box_shadow(
|
||||||
|
@ -263,14 +264,79 @@ impl ClipNode {
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
resource_cache: &mut ResourceCache,
|
resource_cache: &mut ResourceCache,
|
||||||
device_pixel_scale: DevicePixelScale,
|
device_pixel_scale: DevicePixelScale,
|
||||||
|
clipped_rect: &LayoutRect,
|
||||||
) {
|
) {
|
||||||
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
|
match self.item {
|
||||||
match self.item {
|
ClipItem::Image { ref mask, ref mut visible_tiles } => {
|
||||||
ClipItem::Image(ref mask, ..) => {
|
let request = ImageRequest {
|
||||||
let data = ImageMaskData { local_rect: mask.rect };
|
key: mask.image,
|
||||||
data.write_gpu_blocks(request);
|
rendering: ImageRendering::Auto,
|
||||||
|
tile: None,
|
||||||
|
};
|
||||||
|
*visible_tiles = None;
|
||||||
|
if let Some(props) = resource_cache.get_image_properties(mask.image) {
|
||||||
|
if let Some(tile_size) = props.tiling {
|
||||||
|
let mut mask_tiles = Vec::new();
|
||||||
|
|
||||||
|
let device_image_size = props.descriptor.size;
|
||||||
|
let visible_rect = if mask.repeat {
|
||||||
|
*clipped_rect
|
||||||
|
} else {
|
||||||
|
clipped_rect.intersection(&mask.rect).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let repetitions = image::repetitions(
|
||||||
|
&mask.rect,
|
||||||
|
&visible_rect,
|
||||||
|
mask.rect.size,
|
||||||
|
);
|
||||||
|
|
||||||
|
for Repetition { origin, .. } in repetitions {
|
||||||
|
let image_rect = LayoutRect {
|
||||||
|
origin,
|
||||||
|
size: mask.rect.size,
|
||||||
|
};
|
||||||
|
let tiles = image::tiles(
|
||||||
|
&image_rect,
|
||||||
|
&visible_rect,
|
||||||
|
&device_image_size,
|
||||||
|
tile_size as u32,
|
||||||
|
);
|
||||||
|
for tile in tiles {
|
||||||
|
resource_cache.request_image(
|
||||||
|
request.with_tile(tile.offset),
|
||||||
|
gpu_cache,
|
||||||
|
);
|
||||||
|
let mut handle = GpuCacheHandle::new();
|
||||||
|
if let Some(request) = gpu_cache.request(&mut handle) {
|
||||||
|
let data = ImageMaskData {
|
||||||
|
local_mask_rect: mask.rect,
|
||||||
|
local_tile_rect: tile.rect,
|
||||||
|
};
|
||||||
|
data.write_gpu_blocks(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
mask_tiles.push(VisibleMaskImageTile {
|
||||||
|
tile_offset: tile.offset,
|
||||||
|
handle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*visible_tiles = Some(mask_tiles);
|
||||||
|
} else {
|
||||||
|
if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) {
|
||||||
|
let data = ImageMaskData {
|
||||||
|
local_mask_rect: mask.rect,
|
||||||
|
local_tile_rect: mask.rect,
|
||||||
|
};
|
||||||
|
data.write_gpu_blocks(request);
|
||||||
|
}
|
||||||
|
resource_cache.request_image(request, gpu_cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ClipItem::BoxShadow(ref info) => {
|
}
|
||||||
|
ClipItem::BoxShadow(ref mut info) => {
|
||||||
|
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
|
||||||
request.push([
|
request.push([
|
||||||
info.shadow_rect_alloc_size.width,
|
info.shadow_rect_alloc_size.width,
|
||||||
info.shadow_rect_alloc_size.height,
|
info.shadow_rect_alloc_size.height,
|
||||||
|
@ -285,39 +351,7 @@ impl ClipNode {
|
||||||
]);
|
]);
|
||||||
request.push(info.prim_shadow_rect);
|
request.push(info.prim_shadow_rect);
|
||||||
}
|
}
|
||||||
ClipItem::Rectangle(rect, mode) => {
|
|
||||||
let data = ClipData::uniform(rect, 0.0, mode);
|
|
||||||
data.write(&mut request);
|
|
||||||
}
|
|
||||||
ClipItem::RoundedRectangle(ref rect, ref radius, mode) => {
|
|
||||||
let data = ClipData::rounded_rect(rect, radius, mode);
|
|
||||||
data.write(&mut request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.item {
|
|
||||||
ClipItem::Image(ref mask, ref mut is_valid) => {
|
|
||||||
if let Some(properties) = resource_cache.get_image_properties(mask.image) {
|
|
||||||
// Clip masks with tiled blob images are not currently supported.
|
|
||||||
// This results in them being ignored, which is not ideal, but
|
|
||||||
// is better than crashing in resource cache!
|
|
||||||
// See https://github.com/servo/webrender/issues/2852.
|
|
||||||
*is_valid = properties.tiling.is_none();
|
|
||||||
}
|
|
||||||
|
|
||||||
if *is_valid {
|
|
||||||
resource_cache.request_image(
|
|
||||||
ImageRequest {
|
|
||||||
key: mask.image,
|
|
||||||
rendering: ImageRendering::Auto,
|
|
||||||
tile: None,
|
|
||||||
},
|
|
||||||
gpu_cache,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ClipItem::BoxShadow(ref mut info) => {
|
|
||||||
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
|
// Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur
|
||||||
// "the image that would be generated by applying to the shadow a
|
// "the image that would be generated by applying to the shadow a
|
||||||
// Gaussian blur with a standard deviation equal to half the blur radius."
|
// Gaussian blur with a standard deviation equal to half the blur radius."
|
||||||
|
@ -348,8 +382,18 @@ impl ClipNode {
|
||||||
data.write(&mut request);
|
data.write(&mut request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClipItem::Rectangle(..) |
|
ClipItem::Rectangle(rect, mode) => {
|
||||||
ClipItem::RoundedRectangle(..) => {}
|
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
|
||||||
|
let data = ClipData::uniform(rect, 0.0, mode);
|
||||||
|
data.write(&mut request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ClipItem::RoundedRectangle(ref rect, ref radius, mode) => {
|
||||||
|
if let Some(mut request) = gpu_cache.request(&mut self.gpu_cache_handle) {
|
||||||
|
let data = ClipData::rounded_rect(rect, radius, mode);
|
||||||
|
data.write(&mut request);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -568,6 +612,7 @@ impl ClipStore {
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
resource_cache,
|
resource_cache,
|
||||||
device_pixel_scale,
|
device_pixel_scale,
|
||||||
|
&local_bounding_rect,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculate some flags that are required for the segment
|
// Calculate some flags that are required for the segment
|
||||||
|
@ -593,7 +638,7 @@ impl ClipStore {
|
||||||
needs_mask |= match node.item {
|
needs_mask |= match node.item {
|
||||||
ClipItem::Rectangle(_, ClipMode::ClipOut) |
|
ClipItem::Rectangle(_, ClipMode::ClipOut) |
|
||||||
ClipItem::RoundedRectangle(..) |
|
ClipItem::RoundedRectangle(..) |
|
||||||
ClipItem::Image(..) |
|
ClipItem::Image { .. } |
|
||||||
ClipItem::BoxShadow(..) => {
|
ClipItem::BoxShadow(..) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -767,15 +812,13 @@ impl ClipItemKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub enum ClipItem {
|
pub enum ClipItem {
|
||||||
Rectangle(LayoutRect, ClipMode),
|
Rectangle(LayoutRect, ClipMode),
|
||||||
RoundedRectangle(LayoutRect, BorderRadius, ClipMode),
|
RoundedRectangle(LayoutRect, BorderRadius, ClipMode),
|
||||||
/// The boolean below is a crash workaround for #2852, will be true unless
|
Image { mask: ImageMask, visible_tiles: Option<Vec<VisibleMaskImageTile>> },
|
||||||
/// the mask is a tiled blob.
|
|
||||||
Image(ImageMask, bool),
|
|
||||||
BoxShadow(BoxShadowClipSource),
|
BoxShadow(BoxShadowClipSource),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,8 +931,8 @@ impl ClipItem {
|
||||||
ClipItem::Rectangle(_, ClipMode::ClipOut) => None,
|
ClipItem::Rectangle(_, ClipMode::ClipOut) => None,
|
||||||
ClipItem::RoundedRectangle(clip_rect, _, ClipMode::Clip) => Some(clip_rect),
|
ClipItem::RoundedRectangle(clip_rect, _, ClipMode::Clip) => Some(clip_rect),
|
||||||
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) => None,
|
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) => None,
|
||||||
ClipItem::Image(ref mask, ..) if mask.repeat => None,
|
ClipItem::Image { ref mask, .. } if mask.repeat => None,
|
||||||
ClipItem::Image(ref mask, ..) => Some(mask.rect),
|
ClipItem::Image { ref mask, .. } => Some(mask.rect),
|
||||||
ClipItem::BoxShadow(..) => None,
|
ClipItem::BoxShadow(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -910,7 +953,7 @@ impl ClipItem {
|
||||||
}
|
}
|
||||||
ClipItem::Rectangle(_, ClipMode::ClipOut) |
|
ClipItem::Rectangle(_, ClipMode::ClipOut) |
|
||||||
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) |
|
ClipItem::RoundedRectangle(_, _, ClipMode::ClipOut) |
|
||||||
ClipItem::Image(..) |
|
ClipItem::Image { .. } |
|
||||||
ClipItem::BoxShadow(..) => {
|
ClipItem::BoxShadow(..) => {
|
||||||
return ClipResult::Partial
|
return ClipResult::Partial
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1064,7 @@ impl ClipItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClipItem::Image(ref mask, ..) => {
|
ClipItem::Image { ref mask, .. } => {
|
||||||
if mask.repeat {
|
if mask.repeat {
|
||||||
ClipResult::Partial
|
ClipResult::Partial
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -39,7 +39,8 @@ impl HitTestClipNode {
|
||||||
ClipItem::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
|
ClipItem::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
|
||||||
ClipItem::RoundedRectangle(ref rect, ref radii, ref mode) =>
|
ClipItem::RoundedRectangle(ref rect, ref radii, ref mode) =>
|
||||||
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
|
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
|
||||||
ClipItem::Image(ref mask, ..) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
|
ClipItem::Image { ref mask, .. } =>
|
||||||
|
HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
|
||||||
ClipItem::BoxShadow(_) => HitTestRegion::Invalid,
|
ClipItem::BoxShadow(_) => HitTestRegion::Invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,85 @@ pub fn simplify_repeated_primitive(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_each_repetition(
|
pub struct Repetition {
|
||||||
|
pub origin: LayoutPoint,
|
||||||
|
pub edge_flags: EdgeAaSegmentMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RepetitionIterator {
|
||||||
|
current_x: i32,
|
||||||
|
x_count: i32,
|
||||||
|
current_y: i32,
|
||||||
|
y_count: i32,
|
||||||
|
row_flags: EdgeAaSegmentMask,
|
||||||
|
current_origin: LayoutPoint,
|
||||||
|
initial_origin: LayoutPoint,
|
||||||
|
stride: LayoutSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for RepetitionIterator {
|
||||||
|
type Item = Repetition;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.current_x == self.x_count {
|
||||||
|
self.current_y += 1;
|
||||||
|
if self.current_y >= self.y_count {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.current_x = 0;
|
||||||
|
|
||||||
|
self.row_flags = EdgeAaSegmentMask::empty();
|
||||||
|
if self.current_y == self.y_count - 1 {
|
||||||
|
self.row_flags |= EdgeAaSegmentMask::BOTTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.current_origin.x = self.initial_origin.x;
|
||||||
|
self.current_origin.y += self.stride.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut edge_flags = self.row_flags;
|
||||||
|
if self.current_x == 0 {
|
||||||
|
edge_flags |= EdgeAaSegmentMask::LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.current_x == self.x_count - 1 {
|
||||||
|
edge_flags |= EdgeAaSegmentMask::RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
let repetition = Repetition {
|
||||||
|
origin: self.current_origin,
|
||||||
|
edge_flags: edge_flags,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.current_origin.x += self.stride.width;
|
||||||
|
self.current_x += 1;
|
||||||
|
|
||||||
|
Some(repetition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repetitions(
|
||||||
prim_rect: &LayoutRect,
|
prim_rect: &LayoutRect,
|
||||||
visible_rect: &LayoutRect,
|
visible_rect: &LayoutRect,
|
||||||
stride: &LayoutSize,
|
stride: LayoutSize,
|
||||||
callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
|
) -> RepetitionIterator {
|
||||||
) {
|
|
||||||
assert!(stride.width > 0.0);
|
assert!(stride.width > 0.0);
|
||||||
assert!(stride.height > 0.0);
|
assert!(stride.height > 0.0);
|
||||||
|
|
||||||
let visible_rect = match prim_rect.intersection(&visible_rect) {
|
let visible_rect = match prim_rect.intersection(&visible_rect) {
|
||||||
Some(rect) => rect,
|
Some(rect) => rect,
|
||||||
None => return,
|
None => {
|
||||||
|
return RepetitionIterator {
|
||||||
|
current_origin: LayoutPoint::zero(),
|
||||||
|
initial_origin: LayoutPoint::zero(),
|
||||||
|
current_x: 0,
|
||||||
|
current_y: 0,
|
||||||
|
x_count: 0,
|
||||||
|
y_count: 0,
|
||||||
|
stride,
|
||||||
|
row_flags: EdgeAaSegmentMask::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let nx = if visible_rect.origin.x > prim_rect.origin.x {
|
let nx = if visible_rect.origin.x > prim_rect.origin.x {
|
||||||
|
@ -58,49 +125,109 @@ pub fn for_each_repetition(
|
||||||
let x0 = prim_rect.origin.x + nx * stride.width;
|
let x0 = prim_rect.origin.x + nx * stride.width;
|
||||||
let y0 = prim_rect.origin.y + ny * stride.height;
|
let y0 = prim_rect.origin.y + ny * stride.height;
|
||||||
|
|
||||||
let mut p = LayoutPoint::new(x0, y0);
|
|
||||||
|
|
||||||
let x_most = visible_rect.max_x();
|
let x_most = visible_rect.max_x();
|
||||||
let y_most = visible_rect.max_y();
|
let y_most = visible_rect.max_y();
|
||||||
|
|
||||||
let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
|
let x_count = f32::ceil((x_most - x0) / stride.width) as i32;
|
||||||
let y_count = f32::ceil((y_most - y0) / stride.height) as i32;
|
let y_count = f32::ceil((y_most - y0) / stride.height) as i32;
|
||||||
|
|
||||||
for y in 0..y_count {
|
let mut row_flags = EdgeAaSegmentMask::TOP;
|
||||||
let mut row_flags = EdgeAaSegmentMask::empty();
|
if y_count == 1 {
|
||||||
if y == 0 {
|
row_flags |= EdgeAaSegmentMask::BOTTOM;
|
||||||
row_flags |= EdgeAaSegmentMask::TOP;
|
}
|
||||||
}
|
|
||||||
if y == y_count - 1 {
|
|
||||||
row_flags |= EdgeAaSegmentMask::BOTTOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in 0..x_count {
|
RepetitionIterator {
|
||||||
let mut edge_flags = row_flags;
|
current_origin: LayoutPoint::new(x0, y0),
|
||||||
if x == 0 {
|
initial_origin: LayoutPoint::new(x0, y0),
|
||||||
edge_flags |= EdgeAaSegmentMask::LEFT;
|
current_x: 0,
|
||||||
}
|
current_y: 0,
|
||||||
if x == x_count - 1 {
|
x_count,
|
||||||
edge_flags |= EdgeAaSegmentMask::RIGHT;
|
y_count,
|
||||||
}
|
row_flags,
|
||||||
|
stride,
|
||||||
callback(&p, edge_flags);
|
|
||||||
|
|
||||||
p.x += stride.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.x = x0;
|
|
||||||
p.y += stride.height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_each_tile(
|
#[derive(Debug)]
|
||||||
|
pub struct Tile {
|
||||||
|
pub rect: LayoutRect,
|
||||||
|
pub offset: TileOffset,
|
||||||
|
pub edge_flags: EdgeAaSegmentMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TileIterator {
|
||||||
|
current_x: u16,
|
||||||
|
x_count: u16,
|
||||||
|
current_y: u16,
|
||||||
|
y_count: u16,
|
||||||
|
origin: TileOffset,
|
||||||
|
tile_size: LayoutSize,
|
||||||
|
leftover_offset: TileOffset,
|
||||||
|
leftover_size: LayoutSize,
|
||||||
|
local_origin: LayoutPoint,
|
||||||
|
row_flags: EdgeAaSegmentMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for TileIterator {
|
||||||
|
type Item = Tile;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.current_x == self.x_count {
|
||||||
|
self.current_y += 1;
|
||||||
|
if self.current_y >= self.y_count {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.current_x = 0;
|
||||||
|
self.row_flags = EdgeAaSegmentMask::empty();
|
||||||
|
if self.current_y == self.y_count - 1 {
|
||||||
|
self.row_flags |= EdgeAaSegmentMask::BOTTOM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile_offset = self.origin + vec2(self.current_x, self.current_y);
|
||||||
|
|
||||||
|
let mut segment_rect = LayoutRect {
|
||||||
|
origin: LayoutPoint::new(
|
||||||
|
self.local_origin.x + tile_offset.x as f32 * self.tile_size.width,
|
||||||
|
self.local_origin.y + tile_offset.y as f32 * self.tile_size.height,
|
||||||
|
),
|
||||||
|
size: self.tile_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
if tile_offset.x == self.leftover_offset.x {
|
||||||
|
segment_rect.size.width = self.leftover_size.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if tile_offset.y == self.leftover_offset.y {
|
||||||
|
segment_rect.size.height = self.leftover_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut edge_flags = self.row_flags;
|
||||||
|
if self.current_x == 0 {
|
||||||
|
edge_flags |= EdgeAaSegmentMask::LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.current_x == self.x_count - 1 {
|
||||||
|
edge_flags |= EdgeAaSegmentMask::RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile = Tile {
|
||||||
|
rect: segment_rect,
|
||||||
|
offset: tile_offset,
|
||||||
|
edge_flags,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.current_x += 1;
|
||||||
|
Some(tile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tiles(
|
||||||
prim_rect: &LayoutRect,
|
prim_rect: &LayoutRect,
|
||||||
visible_rect: &LayoutRect,
|
visible_rect: &LayoutRect,
|
||||||
device_image_size: &DeviceUintSize,
|
device_image_size: &DeviceUintSize,
|
||||||
device_tile_size: u32,
|
device_tile_size: u32,
|
||||||
callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
|
) -> TileIterator {
|
||||||
) {
|
|
||||||
// The image resource is tiled. We have to generate an image primitive
|
// The image resource is tiled. We have to generate an image primitive
|
||||||
// for each tile.
|
// for each tile.
|
||||||
// We need to do this because the image is broken up into smaller tiles in the texture
|
// We need to do this because the image is broken up into smaller tiles in the texture
|
||||||
|
@ -130,8 +257,21 @@ pub fn for_each_tile(
|
||||||
// the image in layer space intead of iterating over device tiles.
|
// the image in layer space intead of iterating over device tiles.
|
||||||
|
|
||||||
let visible_rect = match prim_rect.intersection(&visible_rect) {
|
let visible_rect = match prim_rect.intersection(&visible_rect) {
|
||||||
Some(rect) => rect,
|
Some(rect) => rect,
|
||||||
None => return,
|
None => {
|
||||||
|
return TileIterator {
|
||||||
|
current_x: 0,
|
||||||
|
current_y: 0,
|
||||||
|
x_count: 0,
|
||||||
|
y_count: 0,
|
||||||
|
row_flags: EdgeAaSegmentMask::empty(),
|
||||||
|
origin: TileOffset::zero(),
|
||||||
|
tile_size: LayoutSize::zero(),
|
||||||
|
leftover_offset: TileOffset::zero(),
|
||||||
|
leftover_size: LayoutSize::zero(),
|
||||||
|
local_origin: LayoutPoint::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let device_tile_size_f32 = device_tile_size as f32;
|
let device_tile_size_f32 = device_tile_size as f32;
|
||||||
|
@ -183,46 +323,21 @@ pub fn for_each_tile(
|
||||||
let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
|
let x_count = f32::ceil((visible_rect.max_x() - prim_rect.origin.x) / layer_tile_size.width) as u16 - t0.x;
|
||||||
let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;
|
let y_count = f32::ceil((visible_rect.max_y() - prim_rect.origin.y) / layer_tile_size.height) as u16 - t0.y;
|
||||||
|
|
||||||
for y in 0..y_count {
|
let mut row_flags = EdgeAaSegmentMask::TOP;
|
||||||
|
if y_count == 1 {
|
||||||
let mut row_flags = EdgeAaSegmentMask::empty();
|
row_flags |= EdgeAaSegmentMask::BOTTOM;
|
||||||
if y == 0 {
|
}
|
||||||
row_flags |= EdgeAaSegmentMask::TOP;
|
TileIterator {
|
||||||
}
|
current_x: 0,
|
||||||
if y == y_count - 1 {
|
current_y: 0,
|
||||||
row_flags |= EdgeAaSegmentMask::BOTTOM;
|
x_count,
|
||||||
}
|
y_count,
|
||||||
|
row_flags,
|
||||||
for x in 0..x_count {
|
origin: t0,
|
||||||
let tile_offset = t0 + vec2(x, y);
|
tile_size: layer_tile_size,
|
||||||
|
leftover_offset,
|
||||||
|
leftover_size: leftover_layer_size,
|
||||||
let mut segment_rect = LayoutRect {
|
local_origin: prim_rect.origin,
|
||||||
origin: LayoutPoint::new(
|
|
||||||
prim_rect.origin.x + tile_offset.x as f32 * layer_tile_size.width,
|
|
||||||
prim_rect.origin.y + tile_offset.y as f32 * layer_tile_size.height,
|
|
||||||
),
|
|
||||||
size: layer_tile_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
if tile_offset.x == leftover_offset.x {
|
|
||||||
segment_rect.size.width = leftover_layer_size.width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if tile_offset.y == leftover_offset.y {
|
|
||||||
segment_rect.size.height = leftover_layer_size.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut edge_flags = row_flags;
|
|
||||||
if x == 0 {
|
|
||||||
edge_flags |= EdgeAaSegmentMask::LEFT;
|
|
||||||
}
|
|
||||||
if x == x_count - 1 {
|
|
||||||
edge_flags |= EdgeAaSegmentMask::RIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(&segment_rect, tile_offset, edge_flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +367,7 @@ pub fn compute_tile_range(
|
||||||
|
|
||||||
pub fn for_each_tile_in_range(
|
pub fn for_each_tile_in_range(
|
||||||
range: &TileRange,
|
range: &TileRange,
|
||||||
callback: &mut FnMut(TileOffset),
|
mut callback: impl FnMut(TileOffset),
|
||||||
) {
|
) {
|
||||||
for y in 0..range.size.height {
|
for y in 0..range.size.height {
|
||||||
for x in 0..range.size.width {
|
for x in 0..range.size.width {
|
||||||
|
@ -277,20 +392,20 @@ mod tests {
|
||||||
callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
|
callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask),
|
||||||
) {
|
) {
|
||||||
let mut coverage = LayoutRect::zero();
|
let mut coverage = LayoutRect::zero();
|
||||||
let mut tiles = HashSet::new();
|
let mut seen_tiles = HashSet::new();
|
||||||
for_each_tile(prim_rect,
|
for tile in tiles(
|
||||||
visible_rect,
|
prim_rect,
|
||||||
device_image_size,
|
visible_rect,
|
||||||
device_tile_size,
|
device_image_size,
|
||||||
&mut |tile_rect, tile_offset, tile_flags| {
|
device_tile_size,
|
||||||
// make sure we don't get sent duplicate tiles
|
) {
|
||||||
assert!(!tiles.contains(&tile_offset));
|
// make sure we don't get sent duplicate tiles
|
||||||
tiles.insert(tile_offset);
|
assert!(!seen_tiles.contains(&tile.offset));
|
||||||
coverage = coverage.union(tile_rect);
|
seen_tiles.insert(tile.offset);
|
||||||
assert!(prim_rect.contains_rect(&tile_rect));
|
coverage = coverage.union(&tile.rect);
|
||||||
callback(tile_rect, tile_offset, tile_flags);
|
assert!(prim_rect.contains_rect(&tile.rect));
|
||||||
},
|
callback(&tile.rect, tile.offset, tile.edge_flags);
|
||||||
);
|
}
|
||||||
assert!(prim_rect.contains_rect(&coverage));
|
assert!(prim_rect.contains_rect(&coverage));
|
||||||
assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
|
assert!(coverage.contains_rect(&visible_rect.intersection(&prim_rect).unwrap_or(LayoutRect::zero())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
|
||||||
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
|
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
|
||||||
ToGpuBlocks};
|
ToGpuBlocks};
|
||||||
use gpu_types::BrushFlags;
|
use gpu_types::BrushFlags;
|
||||||
use image::{for_each_tile, for_each_repetition};
|
use image::{self, Repetition};
|
||||||
use intern;
|
use intern;
|
||||||
use picture::{PictureCompositeMode, PicturePrimitive};
|
use picture::{PictureCompositeMode, PicturePrimitive};
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -359,6 +359,8 @@ impl OpacityBinding {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct VisibleImageTile {
|
pub struct VisibleImageTile {
|
||||||
pub tile_offset: TileOffset,
|
pub tile_offset: TileOffset,
|
||||||
pub handle: GpuCacheHandle,
|
pub handle: GpuCacheHandle,
|
||||||
|
@ -367,6 +369,14 @@ pub struct VisibleImageTile {
|
||||||
pub local_clip_rect: LayoutRect,
|
pub local_clip_rect: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct VisibleMaskImageTile {
|
||||||
|
pub tile_offset: TileOffset,
|
||||||
|
pub handle: GpuCacheHandle,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VisibleGradientTile {
|
pub struct VisibleGradientTile {
|
||||||
pub handle: GpuCacheHandle,
|
pub handle: GpuCacheHandle,
|
||||||
|
@ -539,6 +549,8 @@ bitflags! {
|
||||||
///
|
///
|
||||||
/// *Note*: the bit values have to match the shader logic in
|
/// *Note*: the bit values have to match the shader logic in
|
||||||
/// `write_transform_vertex()` function.
|
/// `write_transform_vertex()` function.
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct EdgeAaSegmentMask: u8 {
|
pub struct EdgeAaSegmentMask: u8 {
|
||||||
const LEFT = 0x1;
|
const LEFT = 0x1;
|
||||||
const TOP = 0x2;
|
const TOP = 0x2;
|
||||||
|
@ -1262,12 +1274,16 @@ impl ClipCorner {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ImageMaskData {
|
pub struct ImageMaskData {
|
||||||
pub local_rect: LayoutRect,
|
/// The local rect of the whole masked area.
|
||||||
|
pub local_mask_rect: LayoutRect,
|
||||||
|
/// The local rect of an individual tile.
|
||||||
|
pub local_tile_rect: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToGpuBlocks for ImageMaskData {
|
impl ToGpuBlocks for ImageMaskData {
|
||||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||||
request.push(self.local_rect);
|
request.push(self.local_mask_rect);
|
||||||
|
request.push(self.local_tile_rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2159,28 +2175,24 @@ fn decompose_repeated_primitive(
|
||||||
);
|
);
|
||||||
let stride = *stretch_size + *tile_spacing;
|
let stride = *stretch_size + *tile_spacing;
|
||||||
|
|
||||||
for_each_repetition(
|
let repetitions = image::repetitions(prim_local_rect, &visible_rect, stride);
|
||||||
prim_local_rect,
|
for Repetition { origin, .. } in repetitions {
|
||||||
&visible_rect,
|
let mut handle = GpuCacheHandle::new();
|
||||||
&stride,
|
let rect = LayoutRect {
|
||||||
&mut |origin, _| {
|
origin: origin,
|
||||||
|
size: *stretch_size,
|
||||||
|
};
|
||||||
|
|
||||||
let mut handle = GpuCacheHandle::new();
|
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
|
||||||
let rect = LayoutRect {
|
callback(&rect, request);
|
||||||
origin: *origin,
|
|
||||||
size: *stretch_size,
|
|
||||||
};
|
|
||||||
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
|
|
||||||
callback(&rect, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
visible_tiles.push(VisibleGradientTile {
|
|
||||||
local_rect: rect,
|
|
||||||
local_clip_rect: tight_clip_rect,
|
|
||||||
handle
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
visible_tiles.push(VisibleGradientTile {
|
||||||
|
local_rect: rect,
|
||||||
|
local_clip_rect: tight_clip_rect,
|
||||||
|
handle
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if visible_tiles.is_empty() {
|
if visible_tiles.is_empty() {
|
||||||
// At this point if we don't have tiles to show it means we could probably
|
// At this point if we don't have tiles to show it means we could probably
|
||||||
|
@ -2329,7 +2341,7 @@ impl BrushPrimitive {
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ClipItem::Image(..) => {
|
ClipItem::Image { .. } => {
|
||||||
rect_clips_only = false;
|
rect_clips_only = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2686,50 +2698,51 @@ impl Primitive {
|
||||||
|
|
||||||
visible_tiles.clear();
|
visible_tiles.clear();
|
||||||
|
|
||||||
for_each_repetition(
|
let repetitions = image::repetitions(
|
||||||
&self.local_rect,
|
&self.local_rect,
|
||||||
&visible_rect,
|
&visible_rect,
|
||||||
&stride,
|
stride,
|
||||||
&mut |origin, edge_flags| {
|
|
||||||
let edge_flags = base_edge_flags | edge_flags;
|
|
||||||
|
|
||||||
let image_rect = LayoutRect {
|
|
||||||
origin: *origin,
|
|
||||||
size: stretch_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
for_each_tile(
|
|
||||||
&image_rect,
|
|
||||||
&visible_rect,
|
|
||||||
&device_image_size,
|
|
||||||
tile_size as u32,
|
|
||||||
&mut |tile_rect, tile_offset, tile_flags| {
|
|
||||||
|
|
||||||
frame_state.resource_cache.request_image(
|
|
||||||
request.with_tile(tile_offset),
|
|
||||||
frame_state.gpu_cache,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut handle = GpuCacheHandle::new();
|
|
||||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
|
|
||||||
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
|
|
||||||
request.push(PremultipliedColorF::WHITE);
|
|
||||||
request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]);
|
|
||||||
request.write_segment(*tile_rect, [0.0; 4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
visible_tiles.push(VisibleImageTile {
|
|
||||||
tile_offset,
|
|
||||||
handle,
|
|
||||||
edge_flags: tile_flags & edge_flags,
|
|
||||||
local_rect: *tile_rect,
|
|
||||||
local_clip_rect: tight_clip_rect,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for Repetition { origin, edge_flags } in repetitions {
|
||||||
|
let edge_flags = base_edge_flags | edge_flags;
|
||||||
|
|
||||||
|
let image_rect = LayoutRect {
|
||||||
|
origin,
|
||||||
|
size: stretch_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
let tiles = image::tiles(
|
||||||
|
&image_rect,
|
||||||
|
&visible_rect,
|
||||||
|
&device_image_size,
|
||||||
|
tile_size as u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
for tile in tiles {
|
||||||
|
frame_state.resource_cache.request_image(
|
||||||
|
request.with_tile(tile.offset),
|
||||||
|
frame_state.gpu_cache,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut handle = GpuCacheHandle::new();
|
||||||
|
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
|
||||||
|
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
|
||||||
|
request.push(PremultipliedColorF::WHITE);
|
||||||
|
request.push([tile.rect.size.width, tile.rect.size.height, 0.0, 0.0]);
|
||||||
|
request.write_segment(tile.rect, [0.0; 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
visible_tiles.push(VisibleImageTile {
|
||||||
|
tile_offset: tile.offset,
|
||||||
|
handle,
|
||||||
|
edge_flags: tile.edge_flags & edge_flags,
|
||||||
|
local_rect: tile.rect,
|
||||||
|
local_clip_rect: tight_clip_rect,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if visible_tiles.is_empty() {
|
if visible_tiles.is_empty() {
|
||||||
// At this point if we don't have tiles to show it means we could probably
|
// At this point if we don't have tiles to show it means we could probably
|
||||||
// have done a better a job at culling during an earlier stage.
|
// have done a better a job at culling during an earlier stage.
|
||||||
|
|
|
@ -554,7 +554,7 @@ impl RenderTask {
|
||||||
}
|
}
|
||||||
ClipItem::Rectangle(..) |
|
ClipItem::Rectangle(..) |
|
||||||
ClipItem::RoundedRectangle(..) |
|
ClipItem::RoundedRectangle(..) |
|
||||||
ClipItem::Image(..) => {}
|
ClipItem::Image { .. } => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1082,7 +1082,7 @@ impl ResourceCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_tile_in_range(&tiles, &mut|tile| {
|
for_each_tile_in_range(&tiles, |tile| {
|
||||||
let descriptor = BlobImageDescriptor {
|
let descriptor = BlobImageDescriptor {
|
||||||
offset: DevicePoint::new(
|
offset: DevicePoint::new(
|
||||||
tile.x as f32 * tile_size as f32,
|
tile.x as f32 * tile_size as f32,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
838ce479e6ef8eed44d68e5d283649d0963152b6
|
9b1a2f7e46cfb3496d43421b828543b08bb45810
|
||||||
|
|
|
@ -72,12 +72,18 @@ fn broadcast<T: Clone>(base_vals: &[T], num_items: usize) -> Vec<T> {
|
||||||
vals
|
vals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CheckerboardKind {
|
||||||
|
BlackGrey,
|
||||||
|
BlackTransparent,
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_checkerboard_image(
|
fn generate_checkerboard_image(
|
||||||
border: u32,
|
border: u32,
|
||||||
tile_x_size: u32,
|
tile_x_size: u32,
|
||||||
tile_y_size: u32,
|
tile_y_size: u32,
|
||||||
tile_x_count: u32,
|
tile_x_count: u32,
|
||||||
tile_y_count: u32,
|
tile_y_count: u32,
|
||||||
|
kind: CheckerboardKind,
|
||||||
) -> (ImageDescriptor, ImageData) {
|
) -> (ImageDescriptor, ImageData) {
|
||||||
let width = 2 * border + tile_x_size * tile_x_count;
|
let width = 2 * border + tile_x_size * tile_x_count;
|
||||||
let height = 2 * border + tile_y_size * tile_y_count;
|
let height = 2 * border + tile_y_size * tile_y_count;
|
||||||
|
@ -94,11 +100,22 @@ fn generate_checkerboard_image(
|
||||||
} else {
|
} else {
|
||||||
let xon = ((x - border) % (2 * tile_x_size)) < tile_x_size;
|
let xon = ((x - border) % (2 * tile_x_size)) < tile_x_size;
|
||||||
let yon = ((y - border) % (2 * tile_y_size)) < tile_y_size;
|
let yon = ((y - border) % (2 * tile_y_size)) < tile_y_size;
|
||||||
let value = if xon ^ yon { 0xff } else { 0x7f };
|
match kind {
|
||||||
pixels.push(value);
|
CheckerboardKind::BlackGrey => {
|
||||||
pixels.push(value);
|
let value = if xon ^ yon { 0xff } else { 0x7f };
|
||||||
pixels.push(value);
|
pixels.push(value);
|
||||||
pixels.push(0xff);
|
pixels.push(value);
|
||||||
|
pixels.push(value);
|
||||||
|
pixels.push(0xff);
|
||||||
|
}
|
||||||
|
CheckerboardKind::BlackTransparent => {
|
||||||
|
let value = if xon ^ yon { 0xff } else { 0x00 };
|
||||||
|
pixels.push(value);
|
||||||
|
pixels.push(value);
|
||||||
|
pixels.push(value);
|
||||||
|
pixels.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,10 +422,10 @@ impl YamlFrameReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_or_get_image(
|
pub fn add_or_get_image(
|
||||||
&mut self,
|
&mut self,
|
||||||
file: &Path,
|
file: &Path,
|
||||||
tiling: Option<i64>,
|
tiling: Option<i64>,
|
||||||
wrench: &mut Wrench,
|
wrench: &mut Wrench,
|
||||||
) -> (ImageKey, LayoutSize) {
|
) -> (ImageKey, LayoutSize) {
|
||||||
let key = (file.to_owned(), tiling);
|
let key = (file.to_owned(), tiling);
|
||||||
if let Some(k) = self.image_map.get(&key) {
|
if let Some(k) = self.image_map.get(&key) {
|
||||||
|
@ -476,7 +493,8 @@ impl YamlFrameReader {
|
||||||
args.get(4).unwrap_or(&"1000").parse::<u32>().unwrap(),
|
args.get(4).unwrap_or(&"1000").parse::<u32>().unwrap(),
|
||||||
args.get(5).unwrap_or(&"1000").parse::<u32>().unwrap(),
|
args.get(5).unwrap_or(&"1000").parse::<u32>().unwrap(),
|
||||||
),
|
),
|
||||||
("checkerboard", args, _) => {
|
(name @ "transparent-checkerboard", args, _) |
|
||||||
|
(name @ "checkerboard", args, _) => {
|
||||||
let border = args.get(0).unwrap_or(&"4").parse::<u32>().unwrap();
|
let border = args.get(0).unwrap_or(&"4").parse::<u32>().unwrap();
|
||||||
|
|
||||||
let (x_size, y_size, x_count, y_count) = match args.len() {
|
let (x_size, y_size, x_count, y_count) = match args.len() {
|
||||||
|
@ -497,12 +515,19 @@ impl YamlFrameReader {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let kind = if name == "transparent-checkerboard" {
|
||||||
|
CheckerboardKind::BlackTransparent
|
||||||
|
} else {
|
||||||
|
CheckerboardKind::BlackGrey
|
||||||
|
};
|
||||||
|
|
||||||
generate_checkerboard_image(
|
generate_checkerboard_image(
|
||||||
border,
|
border,
|
||||||
x_size,
|
x_size,
|
||||||
y_size,
|
y_size,
|
||||||
x_count,
|
x_count,
|
||||||
y_count,
|
y_count,
|
||||||
|
kind,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -600,8 +625,9 @@ impl YamlFrameReader {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let tiling = item["tile-size"].as_i64();
|
||||||
let (image_key, image_dims) =
|
let (image_key, image_dims) =
|
||||||
self.add_or_get_image(&file, None, wrench);
|
self.add_or_get_image(&file, tiling, wrench);
|
||||||
let image_rect = item["rect"]
|
let image_rect = item["rect"]
|
||||||
.as_rect()
|
.as_rect()
|
||||||
.unwrap_or(LayoutRect::new(LayoutPoint::zero(), image_dims));
|
.unwrap_or(LayoutRect::new(LayoutPoint::zero(), image_dims));
|
||||||
|
|
Загрузка…
Ссылка в новой задаче