Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly support tiling clip mask images. #3220

Merged
merged 11 commits into from Oct 23, 2018

image: use iterators instead of callbacks for repetitions.

They're nicer, IMO.
  • Loading branch information
emilio committed Oct 23, 2018
commit ea7dc27bd82dc49c21fb7687e735b9d7f5944f3a
@@ -14,7 +14,7 @@ use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId, ROOT_SPATIAL_NODE_IND
use ellipse::Ellipse;
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use gpu_types::{BoxShadowStretchMode};
use image::{for_each_tile, for_each_repetition};
use image::{self, Repetition, for_each_tile};
use intern;
use internal_types::FastHashSet;
use prim_store::{ClipData, ImageMaskData, SpaceMapper, VisibleImageTile};
@@ -284,45 +284,47 @@ impl ClipNode {
} else {
clipped_rect.intersection(&mask.rect).unwrap()
};
for_each_repetition(

let repetitions = image::repetitions(
&mask.rect,
&visible_rect,
&mask.rect.size,
&mut |origin, _| {
let image_rect = LayoutRect {
origin: *origin,
size: mask.rect.size,
};
for_each_tile(
&image_rect,
&visible_rect,
&device_image_size,
tile_size as u32,
&mut |tile_rect, tile_offset, tile_flags| {
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);
}

tiles.push(VisibleImageTile {
tile_offset,
handle,
edge_flags: tile_flags,
local_rect: *tile_rect,
local_clip_rect: visible_rect,
});
},
)
}
mask.rect.size,
);

for Repetition { origin, .. } in repetitions {
let image_rect = LayoutRect {
origin,
size: mask.rect.size,
};
for_each_tile(
&image_rect,
&visible_rect,
&device_image_size,
tile_size as u32,
&mut |tile_rect, tile_offset, tile_flags| {
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);
}

tiles.push(VisibleImageTile {
tile_offset,
handle,
edge_flags: tile_flags,
local_rect: *tile_rect,
local_clip_rect: visible_rect,
});
},
)
}
*visible_tiles = Some(tiles);
} else {
if let Some(request) = gpu_cache.request(&mut self.gpu_cache_handle) {
@@ -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,
visible_rect: &LayoutRect,
stride: &LayoutSize,
callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask),
) {
stride: LayoutSize,
) -> RepetitionIterator {
assert!(stride.width > 0.0);
assert!(stride.height > 0.0);

let visible_rect = match prim_rect.intersection(&visible_rect) {
Some(rect) => rect,
None => return,
Some(rect) => rect,
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 {
@@ -58,39 +125,26 @@ pub fn for_each_repetition(
let x0 = prim_rect.origin.x + nx * stride.width;
let y0 = prim_rect.origin.y + ny * stride.height;

let mut p = LayoutPoint::new(x0, y0);

let x_most = visible_rect.max_x();
let y_most = visible_rect.max_y();

let x_count = f32::ceil((x_most - x0) / stride.width) 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::empty();
if y == 0 {
row_flags |= EdgeAaSegmentMask::TOP;
}
if y == y_count - 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}

for x in 0..x_count {
let mut edge_flags = row_flags;
if x == 0 {
edge_flags |= EdgeAaSegmentMask::LEFT;
}
if x == x_count - 1 {
edge_flags |= EdgeAaSegmentMask::RIGHT;
}

callback(&p, edge_flags);

p.x += stride.width;
}
let mut row_flags = EdgeAaSegmentMask::TOP;
if y_count == 1 {
row_flags |= EdgeAaSegmentMask::BOTTOM;
}

p.x = x0;
p.y += stride.height;
RepetitionIterator {
current_origin: LayoutPoint::new(x0, y0),
initial_origin: LayoutPoint::new(x0, y0),
current_x: 0,
current_y: 0,
x_count,
y_count,
row_flags,
stride,
}
}

@@ -20,7 +20,7 @@ use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
use gpu_types::BrushFlags;
use image::{for_each_tile, for_each_repetition};
use image::{self, Repetition, for_each_tile};
use intern;
use picture::{PictureCompositeMode, PicturePrimitive};
#[cfg(debug_assertions)]
@@ -2167,28 +2167,24 @@ fn decompose_repeated_primitive(
);
let stride = *stretch_size + *tile_spacing;

for_each_repetition(
prim_local_rect,
&visible_rect,
&stride,
&mut |origin, _| {

let mut handle = GpuCacheHandle::new();
let rect = LayoutRect {
origin: *origin,
size: *stretch_size,
};
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
callback(&rect, request);
}
let repetitions = image::repetitions(prim_local_rect, &visible_rect, stride);
for Repetition { origin, .. } in repetitions {
let mut handle = GpuCacheHandle::new();
let rect = LayoutRect {
origin: origin,
size: *stretch_size,
};

visible_tiles.push(VisibleGradientTile {
local_rect: rect,
local_clip_rect: tight_clip_rect,
handle
});
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
});
}

if visible_tiles.is_empty() {
// At this point if we don't have tiles to show it means we could probably
@@ -2694,49 +2690,50 @@ impl Primitive {

visible_tiles.clear();

for_each_repetition(
let repetitions = image::repetitions(
&self.local_rect,
&visible_rect,
&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,
});
}
);
}
stride,
);

for Repetition { origin, edge_flags } in repetitions {
let edge_flags = base_edge_flags | edge_flags;

let image_rect = LayoutRect {
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,
});
}
);
}

if visible_tiles.is_empty() {
// 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.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.