зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1470125 - Update webrender to commit cdfaaeb5f74e416f39af1081c9a676c752d23896. r=Gankro
Includes regenerated webrender_ffi_generated.h header. MozReview-Commit-ID: I3lvkCH5IGz --HG-- extra : rebase_source : 654102de6773960af67069e7e4c2b27474d9a04c
This commit is contained in:
Родитель
b2e0ee9be4
Коммит
5a3f051406
|
@ -27,12 +27,12 @@ cfg-if = "0.1.2"
|
||||||
euclid = "0.17.3"
|
euclid = "0.17.3"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
gleam = "0.5"
|
gleam = "0.5"
|
||||||
image = { optional = true, version = "0.18" }
|
image = { optional = true, version = "0.19" }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
num-traits = "0.1.43"
|
num-traits = "0.1.43"
|
||||||
plane-split = "0.9.1"
|
plane-split = "0.9.1"
|
||||||
png = { optional = true, version = "0.11" }
|
png = { optional = true, version = "0.12" }
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
ron = { optional = true, version = "0.1.7" }
|
ron = { optional = true, version = "0.1.7" }
|
||||||
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
serde = { optional = true, version = "1.0", features = ["serde_derive"] }
|
||||||
|
|
|
@ -16,7 +16,6 @@ void brush_vs(
|
||||||
vec4 segment_data
|
vec4 segment_data
|
||||||
);
|
);
|
||||||
|
|
||||||
#define VECS_PER_BRUSH_PRIM 2
|
|
||||||
#define VECS_PER_SEGMENT 2
|
#define VECS_PER_SEGMENT 2
|
||||||
|
|
||||||
#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1
|
#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1
|
||||||
|
@ -24,76 +23,19 @@ void brush_vs(
|
||||||
#define BRUSH_FLAG_SEGMENT_REPEAT_X 4
|
#define BRUSH_FLAG_SEGMENT_REPEAT_X 4
|
||||||
#define BRUSH_FLAG_SEGMENT_REPEAT_Y 8
|
#define BRUSH_FLAG_SEGMENT_REPEAT_Y 8
|
||||||
|
|
||||||
//Note: these have to match `gpu_types` constants
|
|
||||||
#define INT_BITS (31)
|
|
||||||
#define CLIP_CHAIN_RECT_BITS (22)
|
|
||||||
#define SEGMENT_BITS (INT_BITS - CLIP_CHAIN_RECT_BITS)
|
|
||||||
#define EDGE_FLAG_BITS (4)
|
|
||||||
#define BRUSH_FLAG_BITS (4)
|
|
||||||
#define CLIP_SCROLL_INDEX_BITS (INT_BITS - EDGE_FLAG_BITS - BRUSH_FLAG_BITS)
|
|
||||||
|
|
||||||
struct BrushInstance {
|
|
||||||
int picture_address;
|
|
||||||
int prim_address;
|
|
||||||
int clip_chain_rect_index;
|
|
||||||
int scroll_node_id;
|
|
||||||
int clip_address;
|
|
||||||
int z;
|
|
||||||
int segment_index;
|
|
||||||
int edge_mask;
|
|
||||||
int flags;
|
|
||||||
ivec3 user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
BrushInstance load_brush() {
|
|
||||||
BrushInstance bi;
|
|
||||||
|
|
||||||
bi.picture_address = aData0.x & 0xffff;
|
|
||||||
bi.clip_address = aData0.x >> 16;
|
|
||||||
bi.prim_address = aData0.y;
|
|
||||||
bi.clip_chain_rect_index = aData0.z & ((1 << CLIP_CHAIN_RECT_BITS) - 1);
|
|
||||||
bi.segment_index = aData0.z >> CLIP_CHAIN_RECT_BITS;
|
|
||||||
bi.z = aData0.w;
|
|
||||||
bi.scroll_node_id = aData1.x & ((1 << CLIP_SCROLL_INDEX_BITS) - 1);
|
|
||||||
bi.edge_mask = (aData1.x >> CLIP_SCROLL_INDEX_BITS) & 0xf;
|
|
||||||
bi.flags = (aData1.x >> (CLIP_SCROLL_INDEX_BITS + EDGE_FLAG_BITS)) & 0xf;
|
|
||||||
bi.user_data = aData1.yzw;
|
|
||||||
|
|
||||||
return bi;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BrushPrimitive {
|
|
||||||
RectWithSize local_rect;
|
|
||||||
RectWithSize local_clip_rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
BrushPrimitive fetch_brush_primitive(int address, int clip_chain_rect_index) {
|
|
||||||
vec4 data[2] = fetch_from_resource_cache_2(address);
|
|
||||||
|
|
||||||
RectWithSize clip_chain_rect = fetch_clip_chain_rect(clip_chain_rect_index);
|
|
||||||
RectWithSize brush_clip_rect = RectWithSize(data[1].xy, data[1].zw);
|
|
||||||
RectWithSize clip_rect = intersect_rects(clip_chain_rect, brush_clip_rect);
|
|
||||||
|
|
||||||
BrushPrimitive prim = BrushPrimitive(RectWithSize(data[0].xy, data[0].zw), clip_rect);
|
|
||||||
|
|
||||||
return prim;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// Load the brush instance from vertex attributes.
|
// Load the brush instance from vertex attributes.
|
||||||
BrushInstance brush = load_brush();
|
int prim_header_address = aData.x;
|
||||||
|
int clip_address = aData.y;
|
||||||
// Load the geometry for this brush. For now, this is simply the
|
int segment_index = aData.z & 0xffff;
|
||||||
// local rect of the primitive. In the future, this will support
|
int edge_flags = (aData.z >> 16) & 0xff;
|
||||||
// loading segment rects, and other rect formats (glyphs).
|
int brush_flags = (aData.z >> 24) & 0xff;
|
||||||
BrushPrimitive brush_prim =
|
PrimitiveHeader ph = fetch_prim_header(prim_header_address);
|
||||||
fetch_brush_primitive(brush.prim_address, brush.clip_chain_rect_index);
|
|
||||||
|
|
||||||
// Fetch the segment of this brush primitive we are drawing.
|
// Fetch the segment of this brush primitive we are drawing.
|
||||||
int segment_address = brush.prim_address +
|
int segment_address = ph.specific_prim_address +
|
||||||
VECS_PER_BRUSH_PRIM +
|
|
||||||
VECS_PER_SPECIFIC_BRUSH +
|
VECS_PER_SPECIFIC_BRUSH +
|
||||||
brush.segment_index * VECS_PER_SEGMENT;
|
segment_index * VECS_PER_SEGMENT;
|
||||||
|
|
||||||
vec4[2] segment_data = fetch_from_resource_cache_2(segment_address);
|
vec4[2] segment_data = fetch_from_resource_cache_2(segment_address);
|
||||||
RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw);
|
RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw);
|
||||||
|
@ -101,20 +43,20 @@ void main(void) {
|
||||||
VertexInfo vi;
|
VertexInfo vi;
|
||||||
|
|
||||||
// Fetch the dynamic picture that we are drawing on.
|
// Fetch the dynamic picture that we are drawing on.
|
||||||
PictureTask pic_task = fetch_picture_task(brush.picture_address);
|
PictureTask pic_task = fetch_picture_task(ph.render_task_index);
|
||||||
ClipArea clip_area = fetch_clip_area(brush.clip_address);
|
ClipArea clip_area = fetch_clip_area(clip_address);
|
||||||
|
|
||||||
ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id);
|
Transform transform = fetch_transform(ph.transform_id);
|
||||||
|
|
||||||
// Write the normal vertex information out.
|
// Write the normal vertex information out.
|
||||||
if (scroll_node.is_axis_aligned) {
|
if (transform.is_axis_aligned) {
|
||||||
vi = write_vertex(
|
vi = write_vertex(
|
||||||
local_segment_rect,
|
local_segment_rect,
|
||||||
brush_prim.local_clip_rect,
|
ph.local_clip_rect,
|
||||||
float(brush.z),
|
ph.z,
|
||||||
scroll_node,
|
transform,
|
||||||
pic_task,
|
pic_task,
|
||||||
brush_prim.local_rect
|
ph.local_rect
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO(gw): transform bounds may be referenced by
|
// TODO(gw): transform bounds may be referenced by
|
||||||
|
@ -127,16 +69,16 @@ void main(void) {
|
||||||
init_transform_vs(vec4(vec2(-1000000.0), vec2(1000000.0)));
|
init_transform_vs(vec4(vec2(-1000000.0), vec2(1000000.0)));
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0));
|
bvec4 edge_mask = notEqual(edge_flags & ivec4(1, 2, 4, 8), ivec4(0));
|
||||||
bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
|
bool do_perspective_interpolation = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
|
||||||
|
|
||||||
vi = write_transform_vertex(
|
vi = write_transform_vertex(
|
||||||
local_segment_rect,
|
local_segment_rect,
|
||||||
brush_prim.local_rect,
|
ph.local_rect,
|
||||||
brush_prim.local_clip_rect,
|
ph.local_clip_rect,
|
||||||
mix(vec4(0.0), vec4(1.0), edge_mask),
|
mix(vec4(0.0), vec4(1.0), edge_mask),
|
||||||
float(brush.z),
|
ph.z,
|
||||||
scroll_node,
|
transform,
|
||||||
pic_task,
|
pic_task,
|
||||||
do_perspective_interpolation
|
do_perspective_interpolation
|
||||||
);
|
);
|
||||||
|
@ -158,13 +100,13 @@ void main(void) {
|
||||||
// Run the specific brush VS code to write interpolators.
|
// Run the specific brush VS code to write interpolators.
|
||||||
brush_vs(
|
brush_vs(
|
||||||
vi,
|
vi,
|
||||||
brush.prim_address + VECS_PER_BRUSH_PRIM,
|
ph.specific_prim_address,
|
||||||
brush_prim.local_rect,
|
ph.local_rect,
|
||||||
local_segment_rect,
|
local_segment_rect,
|
||||||
brush.user_data,
|
ph.user_data,
|
||||||
scroll_node.transform,
|
transform.m,
|
||||||
pic_task,
|
pic_task,
|
||||||
brush.flags,
|
brush_flags,
|
||||||
segment_data[1]
|
segment_data[1]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,11 +49,16 @@ void brush_vs(
|
||||||
mat4 transform,
|
mat4 transform,
|
||||||
PictureTask pic_task,
|
PictureTask pic_task,
|
||||||
int brush_flags,
|
int brush_flags,
|
||||||
vec4 unused
|
vec4 texel_rect
|
||||||
) {
|
) {
|
||||||
Gradient gradient = fetch_gradient(prim_address);
|
Gradient gradient = fetch_gradient(prim_address);
|
||||||
|
|
||||||
vPos = vi.local_pos - local_rect.p0;
|
if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
|
||||||
|
vPos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
|
||||||
|
vPos = vPos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
|
||||||
|
} else {
|
||||||
|
vPos = vi.local_pos - local_rect.p0;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 start_point = gradient.start_end_point.xy;
|
vec2 start_point = gradient.start_end_point.xy;
|
||||||
vec2 end_point = gradient.start_end_point.zw;
|
vec2 end_point = gradient.start_end_point.zw;
|
||||||
|
|
|
@ -49,11 +49,16 @@ void brush_vs(
|
||||||
mat4 transform,
|
mat4 transform,
|
||||||
PictureTask pic_task,
|
PictureTask pic_task,
|
||||||
int brush_flags,
|
int brush_flags,
|
||||||
vec4 unused
|
vec4 texel_rect
|
||||||
) {
|
) {
|
||||||
RadialGradient gradient = fetch_radial_gradient(prim_address);
|
RadialGradient gradient = fetch_radial_gradient(prim_address);
|
||||||
|
|
||||||
vPos = vi.local_pos - local_rect.p0;
|
if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
|
||||||
|
vPos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
|
||||||
|
vPos = vPos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
|
||||||
|
} else {
|
||||||
|
vPos = vi.local_pos - local_rect.p0;
|
||||||
|
}
|
||||||
|
|
||||||
vCenter = gradient.center_start_end_radius.xy;
|
vCenter = gradient.center_start_end_radius.xy;
|
||||||
vStartRadius = gradient.center_start_end_radius.z;
|
vStartRadius = gradient.center_start_end_radius.z;
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
|
||||||
#define VECS_PER_CLIP_SCROLL_NODE 9
|
|
||||||
|
|
||||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes;
|
|
||||||
|
|
||||||
struct ClipScrollNode {
|
|
||||||
mat4 transform;
|
|
||||||
mat4 inv_transform;
|
|
||||||
bool is_axis_aligned;
|
|
||||||
};
|
|
||||||
|
|
||||||
ClipScrollNode fetch_clip_scroll_node(int index) {
|
|
||||||
ClipScrollNode node;
|
|
||||||
|
|
||||||
// Create a UV base coord for each 8 texels.
|
|
||||||
// This is required because trying to use an offset
|
|
||||||
// of more than 8 texels doesn't work on some versions
|
|
||||||
// of OSX.
|
|
||||||
ivec2 uv = get_fetch_uv(index, VECS_PER_CLIP_SCROLL_NODE);
|
|
||||||
ivec2 uv0 = ivec2(uv.x + 0, uv.y);
|
|
||||||
ivec2 uv1 = ivec2(uv.x + 8, uv.y);
|
|
||||||
|
|
||||||
node.transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(0, 0));
|
|
||||||
node.transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(1, 0));
|
|
||||||
node.transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(2, 0));
|
|
||||||
node.transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(3, 0));
|
|
||||||
|
|
||||||
node.inv_transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(4, 0));
|
|
||||||
node.inv_transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(5, 0));
|
|
||||||
node.inv_transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(6, 0));
|
|
||||||
node.inv_transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(7, 0));
|
|
||||||
|
|
||||||
vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(0, 0));
|
|
||||||
node.is_axis_aligned = misc.x == 0.0;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the intersection of the plane (set up by "normal" and "point")
|
|
||||||
// with the ray (set up by "ray_origin" and "ray_dir"),
|
|
||||||
// writing the resulting scaler into "t".
|
|
||||||
bool ray_plane(vec3 normal, vec3 pt, vec3 ray_origin, vec3 ray_dir, out float t)
|
|
||||||
{
|
|
||||||
float denom = dot(normal, ray_dir);
|
|
||||||
if (abs(denom) > 1e-6) {
|
|
||||||
vec3 d = pt - ray_origin;
|
|
||||||
t = dot(d, normal) / denom;
|
|
||||||
return t >= 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the inverse transform "inv_transform"
|
|
||||||
// to the reference point "ref" in CSS space,
|
|
||||||
// producing a local point on a ClipScrollNode plane,
|
|
||||||
// set by a base point "a" and a normal "n".
|
|
||||||
vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
|
|
||||||
vec3 p = vec3(ref, -10000.0);
|
|
||||||
vec3 d = vec3(0, 0, 1.0);
|
|
||||||
|
|
||||||
float t = 0.0;
|
|
||||||
// get an intersection of the ClipScrollNode plane with Z axis vector,
|
|
||||||
// originated from the "ref" point
|
|
||||||
ray_plane(n, a, p, d, t);
|
|
||||||
float z = p.z + d.z * t; // Z of the visible point on the ClipScrollNode
|
|
||||||
|
|
||||||
vec4 r = inv_transform * vec4(ref, z, 1.0);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a CSS space position, transform it back into the ClipScrollNode space.
|
|
||||||
vec4 get_node_pos(vec2 pos, ClipScrollNode node) {
|
|
||||||
// get a point on the scroll node plane
|
|
||||||
vec4 ah = node.transform * vec4(0.0, 0.0, 0.0, 1.0);
|
|
||||||
vec3 a = ah.xyz / ah.w;
|
|
||||||
|
|
||||||
// get the normal to the scroll node plane
|
|
||||||
vec3 n = transpose(mat3(node.inv_transform)) * vec3(0.0, 0.0, 1.0);
|
|
||||||
return untransform(pos, n, a, node.inv_transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //WR_VERTEX_SHADER
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include rect,clip_scroll,render_task,resource_cache,snap,transform
|
#include rect,render_task,resource_cache,snap,transform
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ in ivec4 aClipDataResourceAddress;
|
||||||
|
|
||||||
struct ClipMaskInstance {
|
struct ClipMaskInstance {
|
||||||
int render_task_address;
|
int render_task_address;
|
||||||
int scroll_node_id;
|
int transform_id;
|
||||||
int segment;
|
int segment;
|
||||||
ivec2 clip_data_address;
|
ivec2 clip_data_address;
|
||||||
ivec2 resource_address;
|
ivec2 resource_address;
|
||||||
|
@ -29,7 +29,7 @@ ClipMaskInstance fetch_clip_item() {
|
||||||
ClipMaskInstance cmi;
|
ClipMaskInstance cmi;
|
||||||
|
|
||||||
cmi.render_task_address = aClipRenderTaskAddress;
|
cmi.render_task_address = aClipRenderTaskAddress;
|
||||||
cmi.scroll_node_id = aScrollNodeId;
|
cmi.transform_id = aScrollNodeId;
|
||||||
cmi.segment = aClipSegment;
|
cmi.segment = aClipSegment;
|
||||||
cmi.clip_data_address = aClipDataResourceAddress.xy;
|
cmi.clip_data_address = aClipDataResourceAddress.xy;
|
||||||
cmi.resource_address = aClipDataResourceAddress.zw;
|
cmi.resource_address = aClipDataResourceAddress.zw;
|
||||||
|
@ -51,20 +51,20 @@ RectWithSize intersect_rect(RectWithSize a, RectWithSize b) {
|
||||||
// The transformed vertex function that always covers the whole clip area,
|
// The transformed vertex function that always covers the whole clip area,
|
||||||
// which is the intersection of all clip instances of a given primitive
|
// which is the intersection of all clip instances of a given primitive
|
||||||
ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
|
ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
|
||||||
ClipScrollNode scroll_node,
|
Transform transform,
|
||||||
ClipArea area) {
|
ClipArea area) {
|
||||||
vec2 device_pos = area.screen_origin + aPosition.xy * area.common_data.task_rect.size;
|
vec2 device_pos = area.screen_origin + aPosition.xy * area.common_data.task_rect.size;
|
||||||
vec2 actual_pos = device_pos;
|
vec2 actual_pos = device_pos;
|
||||||
|
|
||||||
if (scroll_node.is_axis_aligned) {
|
if (transform.is_axis_aligned) {
|
||||||
vec4 snap_positions = compute_snap_positions(
|
vec4 snap_positions = compute_snap_positions(
|
||||||
scroll_node.transform,
|
transform.m,
|
||||||
local_clip_rect
|
local_clip_rect
|
||||||
);
|
);
|
||||||
|
|
||||||
vec2 snap_offsets = compute_snap_offset_impl(
|
vec2 snap_offsets = compute_snap_offset_impl(
|
||||||
device_pos,
|
device_pos,
|
||||||
scroll_node.transform,
|
transform.m,
|
||||||
local_clip_rect,
|
local_clip_rect,
|
||||||
RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy),
|
RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy),
|
||||||
snap_positions,
|
snap_positions,
|
||||||
|
@ -81,7 +81,7 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
|
||||||
if (area.local_space) {
|
if (area.local_space) {
|
||||||
node_pos = vec4(actual_pos / uDevicePixelRatio, 0.0, 1.0);
|
node_pos = vec4(actual_pos / uDevicePixelRatio, 0.0, 1.0);
|
||||||
} else {
|
} else {
|
||||||
node_pos = get_node_pos(actual_pos / uDevicePixelRatio, scroll_node);
|
node_pos = get_node_pos(actual_pos / uDevicePixelRatio, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute the point position inside the scroll node, in CSS space
|
// compute the point position inside the scroll node, in CSS space
|
||||||
|
|
|
@ -41,12 +41,12 @@ BoxShadowData fetch_data(ivec2 address) {
|
||||||
void main(void) {
|
void main(void) {
|
||||||
ClipMaskInstance cmi = fetch_clip_item();
|
ClipMaskInstance cmi = fetch_clip_item();
|
||||||
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
||||||
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
|
Transform transform = fetch_transform(cmi.transform_id);
|
||||||
BoxShadowData bs_data = fetch_data(cmi.clip_data_address);
|
BoxShadowData bs_data = fetch_data(cmi.clip_data_address);
|
||||||
ImageResource res = fetch_image_resource_direct(cmi.resource_address);
|
ImageResource res = fetch_image_resource_direct(cmi.resource_address);
|
||||||
|
|
||||||
ClipVertexInfo vi = write_clip_tile_vertex(bs_data.dest_rect,
|
ClipVertexInfo vi = write_clip_tile_vertex(bs_data.dest_rect,
|
||||||
scroll_node,
|
transform,
|
||||||
area);
|
area);
|
||||||
|
|
||||||
vLayer = res.layer;
|
vLayer = res.layer;
|
||||||
|
|
|
@ -26,13 +26,13 @@ ImageMaskData fetch_mask_data(ivec2 address) {
|
||||||
void main(void) {
|
void main(void) {
|
||||||
ClipMaskInstance cmi = fetch_clip_item();
|
ClipMaskInstance cmi = fetch_clip_item();
|
||||||
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
||||||
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
|
Transform transform = fetch_transform(cmi.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_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(local_rect,
|
ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
|
||||||
scroll_node,
|
transform,
|
||||||
area);
|
area);
|
||||||
|
|
||||||
vPos = vi.local_pos;
|
vPos = vi.local_pos;
|
||||||
|
|
|
@ -43,11 +43,11 @@ LineDecorationData fetch_data(ivec2 address) {
|
||||||
void main(void) {
|
void main(void) {
|
||||||
ClipMaskInstance cmi = fetch_clip_item();
|
ClipMaskInstance cmi = fetch_clip_item();
|
||||||
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
||||||
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
|
Transform transform = fetch_transform(cmi.transform_id);
|
||||||
LineDecorationData data = fetch_data(cmi.clip_data_address);
|
LineDecorationData data = fetch_data(cmi.clip_data_address);
|
||||||
|
|
||||||
ClipVertexInfo vi = write_clip_tile_vertex(data.local_rect,
|
ClipVertexInfo vi = write_clip_tile_vertex(data.local_rect,
|
||||||
scroll_node,
|
transform,
|
||||||
area);
|
area);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,11 @@ ClipData fetch_clip(ivec2 address) {
|
||||||
void main(void) {
|
void main(void) {
|
||||||
ClipMaskInstance cmi = fetch_clip_item();
|
ClipMaskInstance cmi = fetch_clip_item();
|
||||||
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
ClipArea area = fetch_clip_area(cmi.render_task_address);
|
||||||
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id);
|
Transform transform = fetch_transform(cmi.transform_id);
|
||||||
ClipData clip = fetch_clip(cmi.clip_data_address);
|
ClipData clip = fetch_clip(cmi.clip_data_address);
|
||||||
RectWithSize local_rect = clip.rect.rect;
|
RectWithSize local_rect = clip.rect.rect;
|
||||||
|
|
||||||
ClipVertexInfo vi = write_clip_tile_vertex(local_rect, scroll_node, area);
|
ClipVertexInfo vi = write_clip_tile_vertex(local_rect, transform, area);
|
||||||
vPos = vi.local_pos;
|
vPos = vi.local_pos;
|
||||||
|
|
||||||
vClipMode = clip.rect.mode.x;
|
vClipMode = clip.rect.mode.x;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include rect,clip_scroll,render_task,resource_cache,snap,transform
|
#include rect,render_task,resource_cache,snap,transform
|
||||||
|
|
||||||
#define EXTEND_MODE_CLAMP 0
|
#define EXTEND_MODE_CLAMP 0
|
||||||
#define EXTEND_MODE_REPEAT 1
|
#define EXTEND_MODE_REPEAT 1
|
||||||
|
@ -32,11 +32,6 @@ varying vec3 vClipMaskUv;
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
|
|
||||||
#define VECS_PER_LOCAL_CLIP_RECT 1
|
|
||||||
#define VECS_PER_PRIM_HEADER 2
|
|
||||||
#define VECS_PER_TEXT_RUN 3
|
|
||||||
#define VECS_PER_GRADIENT_STOP 2
|
|
||||||
|
|
||||||
#define COLOR_MODE_FROM_PASS 0
|
#define COLOR_MODE_FROM_PASS 0
|
||||||
#define COLOR_MODE_ALPHA 1
|
#define COLOR_MODE_ALPHA 1
|
||||||
#define COLOR_MODE_SUBPX_CONST_COLOR 2
|
#define COLOR_MODE_SUBPX_CONST_COLOR 2
|
||||||
|
@ -47,16 +42,46 @@ varying vec3 vClipMaskUv;
|
||||||
#define COLOR_MODE_BITMAP 7
|
#define COLOR_MODE_BITMAP 7
|
||||||
#define COLOR_MODE_COLOR_BITMAP 8
|
#define COLOR_MODE_COLOR_BITMAP 8
|
||||||
|
|
||||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sLocalClipRects;
|
uniform HIGHP_SAMPLER_FLOAT sampler2D sPrimitiveHeadersF;
|
||||||
|
uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI;
|
||||||
|
|
||||||
// Instanced attributes
|
// Instanced attributes
|
||||||
in ivec4 aData0;
|
in ivec4 aData;
|
||||||
in ivec4 aData1;
|
|
||||||
|
|
||||||
RectWithSize fetch_clip_chain_rect(int index) {
|
#define VECS_PER_PRIM_HEADER_F 2
|
||||||
ivec2 uv = get_fetch_uv(index, VECS_PER_LOCAL_CLIP_RECT);
|
#define VECS_PER_PRIM_HEADER_I 2
|
||||||
vec4 rect = TEXEL_FETCH(sLocalClipRects, uv, 0, ivec2(0, 0));
|
|
||||||
return RectWithSize(rect.xy, rect.zw);
|
struct PrimitiveHeader {
|
||||||
|
RectWithSize local_rect;
|
||||||
|
RectWithSize local_clip_rect;
|
||||||
|
float z;
|
||||||
|
int specific_prim_address;
|
||||||
|
int render_task_index;
|
||||||
|
int clip_task_index;
|
||||||
|
int transform_id;
|
||||||
|
ivec3 user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
PrimitiveHeader fetch_prim_header(int index) {
|
||||||
|
PrimitiveHeader ph;
|
||||||
|
|
||||||
|
ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F);
|
||||||
|
vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0));
|
||||||
|
vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0));
|
||||||
|
ph.local_rect = RectWithSize(local_rect.xy, local_rect.zw);
|
||||||
|
ph.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
|
||||||
|
|
||||||
|
ivec2 uv_i = get_fetch_uv(index, VECS_PER_PRIM_HEADER_I);
|
||||||
|
ivec4 data0 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(0, 0));
|
||||||
|
ivec4 data1 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(1, 0));
|
||||||
|
ph.z = float(data0.x);
|
||||||
|
ph.render_task_index = data0.y;
|
||||||
|
ph.specific_prim_address = data0.z;
|
||||||
|
ph.clip_task_index = data0.w;
|
||||||
|
ph.transform_id = data1.x;
|
||||||
|
ph.user_data = data1.yzw;
|
||||||
|
|
||||||
|
return ph;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VertexInfo {
|
struct VertexInfo {
|
||||||
|
@ -69,7 +94,7 @@ struct VertexInfo {
|
||||||
VertexInfo write_vertex(RectWithSize instance_rect,
|
VertexInfo write_vertex(RectWithSize instance_rect,
|
||||||
RectWithSize local_clip_rect,
|
RectWithSize local_clip_rect,
|
||||||
float z,
|
float z,
|
||||||
ClipScrollNode scroll_node,
|
Transform transform,
|
||||||
PictureTask task,
|
PictureTask task,
|
||||||
RectWithSize snap_rect) {
|
RectWithSize snap_rect) {
|
||||||
|
|
||||||
|
@ -82,13 +107,13 @@ VertexInfo write_vertex(RectWithSize instance_rect,
|
||||||
/// Compute the snapping offset.
|
/// Compute the snapping offset.
|
||||||
vec2 snap_offset = compute_snap_offset(
|
vec2 snap_offset = compute_snap_offset(
|
||||||
clamped_local_pos,
|
clamped_local_pos,
|
||||||
scroll_node.transform,
|
transform.m,
|
||||||
snap_rect,
|
snap_rect,
|
||||||
vec2(0.5)
|
vec2(0.5)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Transform the current vertex to world space.
|
// Transform the current vertex to world space.
|
||||||
vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0);
|
vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
|
||||||
|
|
||||||
// Convert the world positions to device pixel space.
|
// Convert the world positions to device pixel space.
|
||||||
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
|
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
|
||||||
|
@ -135,7 +160,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
|
||||||
RectWithSize local_clip_rect,
|
RectWithSize local_clip_rect,
|
||||||
vec4 clip_edge_mask,
|
vec4 clip_edge_mask,
|
||||||
float z,
|
float z,
|
||||||
ClipScrollNode scroll_node,
|
Transform transform,
|
||||||
PictureTask task,
|
PictureTask task,
|
||||||
bool do_perspective_interpolation) {
|
bool do_perspective_interpolation) {
|
||||||
// Calculate a clip rect from local_rect + local clip
|
// Calculate a clip rect from local_rect + local clip
|
||||||
|
@ -168,7 +193,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
|
||||||
vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy;
|
vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy;
|
||||||
|
|
||||||
// Transform the current vertex to the world cpace.
|
// Transform the current vertex to the world cpace.
|
||||||
vec4 world_pos = scroll_node.transform * vec4(local_pos, 0.0, 1.0);
|
vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0);
|
||||||
|
|
||||||
// Convert the world positions to device pixel space.
|
// Convert the world positions to device pixel space.
|
||||||
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
|
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
|
||||||
|
|
|
@ -44,10 +44,10 @@ struct SplitCompositeInstance {
|
||||||
SplitCompositeInstance fetch_composite_instance() {
|
SplitCompositeInstance fetch_composite_instance() {
|
||||||
SplitCompositeInstance ci;
|
SplitCompositeInstance ci;
|
||||||
|
|
||||||
ci.render_task_index = aData0.x;
|
ci.render_task_index = aData.x;
|
||||||
ci.src_task_index = aData0.y;
|
ci.src_task_index = aData.y;
|
||||||
ci.polygons_address = aData0.z;
|
ci.polygons_address = aData.z;
|
||||||
ci.z = float(aData0.w);
|
ci.z = float(aData.w);
|
||||||
|
|
||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ varying vec4 vUvClip;
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
|
|
||||||
|
#define VECS_PER_TEXT_RUN 3
|
||||||
|
|
||||||
struct Glyph {
|
struct Glyph {
|
||||||
vec2 offset;
|
vec2 offset;
|
||||||
};
|
};
|
||||||
|
@ -57,94 +59,16 @@ TextRun fetch_text_run(int address) {
|
||||||
return TextRun(data[0], data[1], data[2].xy);
|
return TextRun(data[0], data[1], data[2].xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrimitiveInstance {
|
|
||||||
int prim_address;
|
|
||||||
int specific_prim_address;
|
|
||||||
int render_task_index;
|
|
||||||
int clip_task_index;
|
|
||||||
int scroll_node_id;
|
|
||||||
int clip_chain_rect_index;
|
|
||||||
int z;
|
|
||||||
int user_data0;
|
|
||||||
int user_data1;
|
|
||||||
int user_data2;
|
|
||||||
};
|
|
||||||
|
|
||||||
PrimitiveInstance fetch_prim_instance() {
|
|
||||||
PrimitiveInstance pi;
|
|
||||||
|
|
||||||
pi.prim_address = aData0.x;
|
|
||||||
pi.specific_prim_address = pi.prim_address + VECS_PER_PRIM_HEADER;
|
|
||||||
pi.render_task_index = aData0.y % 0x10000;
|
|
||||||
pi.clip_task_index = aData0.y / 0x10000;
|
|
||||||
pi.clip_chain_rect_index = aData0.z;
|
|
||||||
pi.scroll_node_id = aData0.w;
|
|
||||||
pi.z = aData1.x;
|
|
||||||
pi.user_data0 = aData1.y;
|
|
||||||
pi.user_data1 = aData1.z;
|
|
||||||
pi.user_data2 = aData1.w;
|
|
||||||
|
|
||||||
return pi;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Primitive {
|
|
||||||
ClipScrollNode scroll_node;
|
|
||||||
ClipArea clip_area;
|
|
||||||
PictureTask task;
|
|
||||||
RectWithSize local_rect;
|
|
||||||
RectWithSize local_clip_rect;
|
|
||||||
int specific_prim_address;
|
|
||||||
int user_data0;
|
|
||||||
int user_data1;
|
|
||||||
int user_data2;
|
|
||||||
float z;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PrimitiveGeometry {
|
|
||||||
RectWithSize local_rect;
|
|
||||||
RectWithSize local_clip_rect;
|
|
||||||
};
|
|
||||||
|
|
||||||
PrimitiveGeometry fetch_primitive_geometry(int address) {
|
|
||||||
vec4 geom[2] = fetch_from_resource_cache_2(address);
|
|
||||||
return PrimitiveGeometry(RectWithSize(geom[0].xy, geom[0].zw),
|
|
||||||
RectWithSize(geom[1].xy, geom[1].zw));
|
|
||||||
}
|
|
||||||
|
|
||||||
Primitive load_primitive() {
|
|
||||||
PrimitiveInstance pi = fetch_prim_instance();
|
|
||||||
|
|
||||||
Primitive prim;
|
|
||||||
|
|
||||||
prim.scroll_node = fetch_clip_scroll_node(pi.scroll_node_id);
|
|
||||||
prim.clip_area = fetch_clip_area(pi.clip_task_index);
|
|
||||||
prim.task = fetch_picture_task(pi.render_task_index);
|
|
||||||
|
|
||||||
RectWithSize clip_chain_rect = fetch_clip_chain_rect(pi.clip_chain_rect_index);
|
|
||||||
|
|
||||||
PrimitiveGeometry geom = fetch_primitive_geometry(pi.prim_address);
|
|
||||||
prim.local_rect = geom.local_rect;
|
|
||||||
prim.local_clip_rect = intersect_rects(clip_chain_rect, geom.local_clip_rect);
|
|
||||||
|
|
||||||
prim.specific_prim_address = pi.specific_prim_address;
|
|
||||||
prim.user_data0 = pi.user_data0;
|
|
||||||
prim.user_data1 = pi.user_data1;
|
|
||||||
prim.user_data2 = pi.user_data2;
|
|
||||||
prim.z = float(pi.z);
|
|
||||||
|
|
||||||
return prim;
|
|
||||||
}
|
|
||||||
|
|
||||||
VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||||
RectWithSize local_clip_rect,
|
RectWithSize local_clip_rect,
|
||||||
float z,
|
float z,
|
||||||
ClipScrollNode scroll_node,
|
Transform transform,
|
||||||
PictureTask task,
|
PictureTask task,
|
||||||
vec2 text_offset,
|
vec2 text_offset,
|
||||||
RectWithSize snap_rect,
|
RectWithSize snap_rect,
|
||||||
vec2 snap_bias) {
|
vec2 snap_bias) {
|
||||||
// Transform the current vertex to world space.
|
// Transform the current vertex to world space.
|
||||||
vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0);
|
vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
|
||||||
|
|
||||||
// Convert the world positions to device pixel space.
|
// Convert the world positions to device pixel space.
|
||||||
float device_scale = uDevicePixelRatio / world_pos.w;
|
float device_scale = uDevicePixelRatio / world_pos.w;
|
||||||
|
@ -159,13 +83,13 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||||
bool remove_subpx_offset = true;
|
bool remove_subpx_offset = true;
|
||||||
#else
|
#else
|
||||||
// Compute the snapping offset only if the scroll node transform is axis-aligned.
|
// Compute the snapping offset only if the scroll node transform is axis-aligned.
|
||||||
bool remove_subpx_offset = scroll_node.is_axis_aligned;
|
bool remove_subpx_offset = transform.is_axis_aligned;
|
||||||
#endif
|
#endif
|
||||||
if (remove_subpx_offset) {
|
if (remove_subpx_offset) {
|
||||||
// Ensure the transformed text offset does not contain a subpixel translation
|
// Ensure the transformed text offset does not contain a subpixel translation
|
||||||
// such that glyph snapping is stable for equivalent glyph subpixel positions.
|
// such that glyph snapping is stable for equivalent glyph subpixel positions.
|
||||||
vec2 world_text_offset = mat2(scroll_node.transform) * text_offset;
|
vec2 world_text_offset = mat2(transform.m) * text_offset;
|
||||||
vec2 device_text_pos = (scroll_node.transform[3].xy + world_text_offset) * device_scale;
|
vec2 device_text_pos = (transform.m[3].xy + world_text_offset) * device_scale;
|
||||||
final_pos += floor(device_text_pos + 0.5) - device_text_pos;
|
final_pos += floor(device_text_pos + 0.5) - device_text_pos;
|
||||||
|
|
||||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||||
|
@ -177,7 +101,7 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||||
#else
|
#else
|
||||||
// The transformed text offset has already been snapped, so remove it from the transform
|
// The transformed text offset has already been snapped, so remove it from the transform
|
||||||
// when snapping the glyph.
|
// when snapping the glyph.
|
||||||
mat4 snap_transform = scroll_node.transform;
|
mat4 snap_transform = transform.m;
|
||||||
snap_transform[3].xy = -world_text_offset;
|
snap_transform[3].xy = -world_text_offset;
|
||||||
final_pos += compute_snap_offset(
|
final_pos += compute_snap_offset(
|
||||||
clamped_local_pos,
|
clamped_local_pos,
|
||||||
|
@ -201,31 +125,37 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
Primitive prim = load_primitive();
|
int prim_header_address = aData.x;
|
||||||
TextRun text = fetch_text_run(prim.specific_prim_address);
|
int glyph_index = aData.y;
|
||||||
|
int resource_address = aData.z;
|
||||||
|
int subpx_dir = aData.w >> 16;
|
||||||
|
int color_mode = aData.w & 0xffff;
|
||||||
|
|
||||||
int glyph_index = prim.user_data0;
|
PrimitiveHeader ph = fetch_prim_header(prim_header_address);
|
||||||
int resource_address = prim.user_data1;
|
|
||||||
int subpx_dir = prim.user_data2 >> 16;
|
Transform transform = fetch_transform(ph.transform_id);
|
||||||
int color_mode = prim.user_data2 & 0xffff;
|
ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
|
||||||
|
PictureTask task = fetch_picture_task(ph.render_task_index);
|
||||||
|
|
||||||
|
TextRun text = fetch_text_run(ph.specific_prim_address);
|
||||||
|
|
||||||
if (color_mode == COLOR_MODE_FROM_PASS) {
|
if (color_mode == COLOR_MODE_FROM_PASS) {
|
||||||
color_mode = uMode;
|
color_mode = uMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
|
Glyph glyph = fetch_glyph(ph.specific_prim_address, glyph_index);
|
||||||
GlyphResource res = fetch_glyph_resource(resource_address);
|
GlyphResource res = fetch_glyph_resource(resource_address);
|
||||||
|
|
||||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||||
// Transform from local space to glyph space.
|
// Transform from local space to glyph space.
|
||||||
mat2 transform = mat2(prim.scroll_node.transform) * uDevicePixelRatio;
|
mat2 glyph_transform = mat2(transform.m) * uDevicePixelRatio;
|
||||||
|
|
||||||
// Compute the glyph rect in glyph space.
|
// Compute the glyph rect in glyph space.
|
||||||
RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset),
|
RectWithSize glyph_rect = RectWithSize(res.offset + glyph_transform * (text.offset + glyph.offset),
|
||||||
res.uv_rect.zw - res.uv_rect.xy);
|
res.uv_rect.zw - res.uv_rect.xy);
|
||||||
|
|
||||||
// Transform the glyph rect back to local space.
|
// Transform the glyph rect back to local space.
|
||||||
mat2 inv = inverse(transform);
|
mat2 inv = inverse(glyph_transform);
|
||||||
RectWithSize local_rect = transform_rect(glyph_rect, inv);
|
RectWithSize local_rect = transform_rect(glyph_rect, inv);
|
||||||
|
|
||||||
// Select the corner of the glyph's local space rect that we are processing.
|
// Select the corner of the glyph's local space rect that we are processing.
|
||||||
|
@ -234,9 +164,9 @@ void main(void) {
|
||||||
// If the glyph's local rect would fit inside the local clip rect, then select a corner from
|
// If the glyph's local rect would fit inside the local clip rect, then select a corner from
|
||||||
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
|
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
|
||||||
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
|
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
|
||||||
local_pos = rect_inside_rect(local_rect, prim.local_clip_rect) ?
|
local_pos = rect_inside_rect(local_rect, ph.local_clip_rect) ?
|
||||||
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
|
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
|
||||||
clamp_rect(local_pos, prim.local_clip_rect);
|
clamp_rect(local_pos, ph.local_clip_rect);
|
||||||
#else
|
#else
|
||||||
// Scale from glyph space to local space.
|
// Scale from glyph space to local space.
|
||||||
float scale = res.scale / uDevicePixelRatio;
|
float scale = res.scale / uDevicePixelRatio;
|
||||||
|
@ -249,7 +179,7 @@ void main(void) {
|
||||||
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
|
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
|
||||||
|
|
||||||
// Clamp to the local clip rect.
|
// Clamp to the local clip rect.
|
||||||
local_pos = clamp_rect(local_pos, prim.local_clip_rect);
|
local_pos = clamp_rect(local_pos, ph.local_clip_rect);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vec2 snap_bias;
|
vec2 snap_bias;
|
||||||
|
@ -278,22 +208,22 @@ void main(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexInfo vi = write_text_vertex(local_pos,
|
VertexInfo vi = write_text_vertex(local_pos,
|
||||||
prim.local_clip_rect,
|
ph.local_clip_rect,
|
||||||
prim.z,
|
ph.z,
|
||||||
prim.scroll_node,
|
transform,
|
||||||
prim.task,
|
task,
|
||||||
text.offset,
|
text.offset,
|
||||||
glyph_rect,
|
glyph_rect,
|
||||||
snap_bias);
|
snap_bias);
|
||||||
|
|
||||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||||
vec2 f = (transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
|
vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
|
||||||
vUvClip = vec4(f, 1.0 - f);
|
vUvClip = vec4(f, 1.0 - f);
|
||||||
#else
|
#else
|
||||||
vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size;
|
vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
write_clip(vi.screen_pos, prim.clip_area);
|
write_clip(vi.screen_pos, clip_area);
|
||||||
|
|
||||||
switch (color_mode) {
|
switch (color_mode) {
|
||||||
case COLOR_MODE_ALPHA:
|
case COLOR_MODE_ALPHA:
|
||||||
|
|
|
@ -8,7 +8,7 @@ vec4 compute_snap_positions(mat4 transform, RectWithSize snap_rect) {
|
||||||
// Ensure that the snap rect is at *least* one device pixel in size.
|
// Ensure that the snap rect is at *least* one device pixel in size.
|
||||||
// TODO(gw): It's not clear to me that this is "correct". Specifically,
|
// TODO(gw): It's not clear to me that this is "correct". Specifically,
|
||||||
// how should it interact with sub-pixel snap rects when there
|
// how should it interact with sub-pixel snap rects when there
|
||||||
// is a scroll_node transform with scale present? But it does fix
|
// is a transform with scale present? But it does fix
|
||||||
// the test cases we have in Servo that are failing without it
|
// the test cases we have in Servo that are failing without it
|
||||||
// and seem better than not having this at all.
|
// and seem better than not having this at all.
|
||||||
snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio));
|
snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio));
|
||||||
|
@ -41,7 +41,7 @@ vec2 compute_snap_offset_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute a snapping offset in world space (adjusted to pixel ratio),
|
// Compute a snapping offset in world space (adjusted to pixel ratio),
|
||||||
// given local position on the scroll_node and a snap rectangle.
|
// given local position on the transform and a snap rectangle.
|
||||||
vec2 compute_snap_offset(vec2 local_pos,
|
vec2 compute_snap_offset(vec2 local_pos,
|
||||||
mat4 transform,
|
mat4 transform,
|
||||||
RectWithSize snap_rect,
|
RectWithSize snap_rect,
|
||||||
|
|
|
@ -6,10 +6,89 @@ flat varying vec4 vTransformBounds;
|
||||||
|
|
||||||
#ifdef WR_VERTEX_SHADER
|
#ifdef WR_VERTEX_SHADER
|
||||||
|
|
||||||
|
#define VECS_PER_TRANSFORM 8
|
||||||
|
uniform HIGHP_SAMPLER_FLOAT sampler2D sTransformPalette;
|
||||||
|
|
||||||
void init_transform_vs(vec4 local_bounds) {
|
void init_transform_vs(vec4 local_bounds) {
|
||||||
vTransformBounds = local_bounds;
|
vTransformBounds = local_bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Transform {
|
||||||
|
mat4 m;
|
||||||
|
mat4 inv_m;
|
||||||
|
bool is_axis_aligned;
|
||||||
|
};
|
||||||
|
|
||||||
|
Transform fetch_transform(int id) {
|
||||||
|
Transform transform;
|
||||||
|
|
||||||
|
transform.is_axis_aligned = (id >> 24) == 0;
|
||||||
|
int index = id & 0x00ffffff;
|
||||||
|
|
||||||
|
// Create a UV base coord for each 8 texels.
|
||||||
|
// This is required because trying to use an offset
|
||||||
|
// of more than 8 texels doesn't work on some versions
|
||||||
|
// of OSX.
|
||||||
|
ivec2 uv = get_fetch_uv(index, VECS_PER_TRANSFORM);
|
||||||
|
ivec2 uv0 = ivec2(uv.x + 0, uv.y);
|
||||||
|
|
||||||
|
transform.m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(0, 0));
|
||||||
|
transform.m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(1, 0));
|
||||||
|
transform.m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(2, 0));
|
||||||
|
transform.m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(3, 0));
|
||||||
|
|
||||||
|
transform.inv_m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(4, 0));
|
||||||
|
transform.inv_m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(5, 0));
|
||||||
|
transform.inv_m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(6, 0));
|
||||||
|
transform.inv_m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(7, 0));
|
||||||
|
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the intersection of the plane (set up by "normal" and "point")
|
||||||
|
// with the ray (set up by "ray_origin" and "ray_dir"),
|
||||||
|
// writing the resulting scaler into "t".
|
||||||
|
bool ray_plane(vec3 normal, vec3 pt, vec3 ray_origin, vec3 ray_dir, out float t)
|
||||||
|
{
|
||||||
|
float denom = dot(normal, ray_dir);
|
||||||
|
if (abs(denom) > 1e-6) {
|
||||||
|
vec3 d = pt - ray_origin;
|
||||||
|
t = dot(d, normal) / denom;
|
||||||
|
return t >= 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the inverse transform "inv_transform"
|
||||||
|
// to the reference point "ref" in CSS space,
|
||||||
|
// producing a local point on a Transform plane,
|
||||||
|
// set by a base point "a" and a normal "n".
|
||||||
|
vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
|
||||||
|
vec3 p = vec3(ref, -10000.0);
|
||||||
|
vec3 d = vec3(0, 0, 1.0);
|
||||||
|
|
||||||
|
float t = 0.0;
|
||||||
|
// get an intersection of the Transform plane with Z axis vector,
|
||||||
|
// originated from the "ref" point
|
||||||
|
ray_plane(n, a, p, d, t);
|
||||||
|
float z = p.z + d.z * t; // Z of the visible point on the Transform
|
||||||
|
|
||||||
|
vec4 r = inv_transform * vec4(ref, z, 1.0);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a CSS space position, transform it back into the Transform space.
|
||||||
|
vec4 get_node_pos(vec2 pos, Transform transform) {
|
||||||
|
// get a point on the scroll node plane
|
||||||
|
vec4 ah = transform.m * vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
vec3 a = ah.xyz / ah.w;
|
||||||
|
|
||||||
|
// get the normal to the scroll node plane
|
||||||
|
vec3 n = transpose(mat3(transform.inv_m)) * vec3(0.0, 0.0, 1.0);
|
||||||
|
return untransform(pos, n, a, transform.inv_m);
|
||||||
|
}
|
||||||
|
|
||||||
#endif //WR_VERTEX_SHADER
|
#endif //WR_VERTEX_SHADER
|
||||||
|
|
||||||
#ifdef WR_FRAGMENT_SHADER
|
#ifdef WR_FRAGMENT_SHADER
|
||||||
|
|
|
@ -11,10 +11,10 @@ use clip_scroll_tree::{CoordinateSystemId};
|
||||||
use euclid::{TypedTransform3D, vec3};
|
use euclid::{TypedTransform3D, vec3};
|
||||||
use glyph_rasterizer::GlyphFormat;
|
use glyph_rasterizer::GlyphFormat;
|
||||||
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
|
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
|
||||||
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex};
|
use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders};
|
||||||
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, SplitCompositeInstance};
|
use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
|
||||||
use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance, ZBufferId};
|
use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance};
|
||||||
use gpu_types::ZBufferIdGenerator;
|
use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
|
||||||
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
||||||
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
|
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
|
||||||
use plane_split::{BspSplitter, Polygon, Splitter};
|
use plane_split::{BspSplitter, Polygon, Splitter};
|
||||||
|
@ -29,7 +29,7 @@ use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
|
||||||
use scene::FilterOpHelpers;
|
use scene::FilterOpHelpers;
|
||||||
use std::{usize, f32, i32};
|
use std::{usize, f32, i32};
|
||||||
use tiling::{RenderTargetContext};
|
use tiling::{RenderTargetContext};
|
||||||
use util::{MatrixHelpers, TransformedRectKind};
|
use util::{TransformedRectKind};
|
||||||
|
|
||||||
// Special sentinel value recognized by the shader. It is considered to be
|
// Special sentinel value recognized by the shader. It is considered to be
|
||||||
// a dummy task that doesn't mask out anything.
|
// a dummy task that doesn't mask out anything.
|
||||||
|
@ -455,7 +455,7 @@ impl AlphaBatchBuilder {
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
render_tasks: &RenderTaskTree,
|
render_tasks: &RenderTaskTree,
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
z_generator: &mut ZBufferIdGenerator,
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
let task_address = render_tasks.get_task_address(task_id);
|
let task_address = render_tasks.get_task_address(task_id);
|
||||||
|
|
||||||
|
@ -476,10 +476,10 @@ impl AlphaBatchBuilder {
|
||||||
// Add each run in this picture to the batch.
|
// Add each run in this picture to the batch.
|
||||||
for run in &pic.runs {
|
for run in &pic.runs {
|
||||||
let scroll_node = &ctx.clip_scroll_tree.nodes[run.clip_and_scroll.scroll_node_id.0];
|
let scroll_node = &ctx.clip_scroll_tree.nodes[run.clip_and_scroll.scroll_node_id.0];
|
||||||
let scroll_id = scroll_node.node_data_index;
|
let transform_id = ctx.transforms.get_id(scroll_node.transform_index);
|
||||||
self.add_run_to_batch(
|
self.add_run_to_batch(
|
||||||
run,
|
run,
|
||||||
scroll_id,
|
transform_id,
|
||||||
ctx,
|
ctx,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
|
@ -488,7 +488,7 @@ impl AlphaBatchBuilder {
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
&mut splitter,
|
&mut splitter,
|
||||||
content_origin,
|
content_origin,
|
||||||
z_generator,
|
prim_headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ impl AlphaBatchBuilder {
|
||||||
task_address,
|
task_address,
|
||||||
source_task_address,
|
source_task_address,
|
||||||
gpu_address,
|
gpu_address,
|
||||||
z_generator.next(),
|
prim_headers.z_generator.next(),
|
||||||
);
|
);
|
||||||
|
|
||||||
batch.push(PrimitiveInstance::from(instance));
|
batch.push(PrimitiveInstance::from(instance));
|
||||||
|
@ -539,7 +539,7 @@ impl AlphaBatchBuilder {
|
||||||
fn add_run_to_batch(
|
fn add_run_to_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
run: &PrimitiveRun,
|
run: &PrimitiveRun,
|
||||||
scroll_id: ClipScrollNodeIndex,
|
transform_id: TransformPaletteId,
|
||||||
ctx: &RenderTargetContext,
|
ctx: &RenderTargetContext,
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
render_tasks: &RenderTaskTree,
|
render_tasks: &RenderTaskTree,
|
||||||
|
@ -548,7 +548,7 @@ impl AlphaBatchBuilder {
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
splitter: &mut BspSplitter<f64, WorldPixel>,
|
splitter: &mut BspSplitter<f64, WorldPixel>,
|
||||||
content_origin: DeviceIntPoint,
|
content_origin: DeviceIntPoint,
|
||||||
z_generator: &mut ZBufferIdGenerator,
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
for i in 0 .. run.count {
|
for i in 0 .. run.count {
|
||||||
let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
|
let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
|
||||||
|
@ -556,8 +556,7 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
if metadata.screen_rect.is_some() {
|
if metadata.screen_rect.is_some() {
|
||||||
self.add_prim_to_batch(
|
self.add_prim_to_batch(
|
||||||
metadata.clip_chain_rect_index,
|
transform_id,
|
||||||
scroll_id,
|
|
||||||
prim_index,
|
prim_index,
|
||||||
ctx,
|
ctx,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
|
@ -567,7 +566,7 @@ impl AlphaBatchBuilder {
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
splitter,
|
splitter,
|
||||||
content_origin,
|
content_origin,
|
||||||
z_generator,
|
prim_headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -579,8 +578,7 @@ impl AlphaBatchBuilder {
|
||||||
// in that picture are being drawn into the same target.
|
// in that picture are being drawn into the same target.
|
||||||
fn add_prim_to_batch(
|
fn add_prim_to_batch(
|
||||||
&mut self,
|
&mut self,
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
transform_id: TransformPaletteId,
|
||||||
scroll_id: ClipScrollNodeIndex,
|
|
||||||
prim_index: PrimitiveIndex,
|
prim_index: PrimitiveIndex,
|
||||||
ctx: &RenderTargetContext,
|
ctx: &RenderTargetContext,
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
|
@ -590,18 +588,16 @@ impl AlphaBatchBuilder {
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
splitter: &mut BspSplitter<f64, WorldPixel>,
|
splitter: &mut BspSplitter<f64, WorldPixel>,
|
||||||
content_origin: DeviceIntPoint,
|
content_origin: DeviceIntPoint,
|
||||||
z_generator: &mut ZBufferIdGenerator,
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
let z = z_generator.next();
|
|
||||||
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
|
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
|
||||||
#[cfg(debug_assertions)] //TODO: why is this needed?
|
#[cfg(debug_assertions)] //TODO: why is this needed?
|
||||||
debug_assert_eq!(prim_metadata.prepared_frame_id, render_tasks.frame_id());
|
debug_assert_eq!(prim_metadata.prepared_frame_id, render_tasks.frame_id());
|
||||||
|
|
||||||
let scroll_node = &ctx.node_data[scroll_id.0 as usize];
|
|
||||||
// TODO(gw): Calculating this for every primitive is a bit
|
// TODO(gw): Calculating this for every primitive is a bit
|
||||||
// wasteful. We should probably cache this in
|
// wasteful. We should probably cache this in
|
||||||
// the scroll node...
|
// the scroll node...
|
||||||
let transform_kind = scroll_node.transform.transform_kind();
|
let transform_kind = transform_id.transform_kind();
|
||||||
|
|
||||||
let screen_rect = prim_metadata.screen_rect.expect("bug");
|
let screen_rect = prim_metadata.screen_rect.expect("bug");
|
||||||
let task_relative_bounding_rect = DeviceIntRect::new(
|
let task_relative_bounding_rect = DeviceIntRect::new(
|
||||||
|
@ -648,6 +644,15 @@ impl AlphaBatchBuilder {
|
||||||
BlendMode::None
|
BlendMode::None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let prim_header = PrimitiveHeader {
|
||||||
|
local_rect: prim_metadata.local_rect,
|
||||||
|
local_clip_rect: prim_metadata.combined_local_clip_rect,
|
||||||
|
task_address,
|
||||||
|
specific_prim_address: prim_cache_address,
|
||||||
|
clip_task_address,
|
||||||
|
transform_id,
|
||||||
|
};
|
||||||
|
|
||||||
match prim_metadata.prim_kind {
|
match prim_metadata.prim_kind {
|
||||||
PrimitiveKind::Brush => {
|
PrimitiveKind::Brush => {
|
||||||
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
|
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
|
||||||
|
@ -701,23 +706,19 @@ impl AlphaBatchBuilder {
|
||||||
textures,
|
textures,
|
||||||
);
|
);
|
||||||
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, [
|
||||||
|
uv_rect_address.as_int(),
|
||||||
|
(ShaderColorMode::ColorBitmap as i32) << 16 |
|
||||||
|
RasterizationSpace::Screen as i32,
|
||||||
|
0,
|
||||||
|
]);
|
||||||
|
|
||||||
let instance = BrushInstance {
|
let instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::empty(),
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
brush_flags: BrushFlags::empty(),
|
brush_flags: BrushFlags::empty(),
|
||||||
user_data: [
|
clip_task_address,
|
||||||
uv_rect_address.as_int(),
|
|
||||||
(ShaderColorMode::ColorBitmap as i32) << 16 |
|
|
||||||
RasterizationSpace::Screen as i32,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
batch.push(PrimitiveInstance::from(instance));
|
batch.push(PrimitiveInstance::from(instance));
|
||||||
false
|
false
|
||||||
|
@ -727,7 +728,7 @@ impl AlphaBatchBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilterOp::DropShadow(..) => {
|
FilterOp::DropShadow(offset, ..) => {
|
||||||
// Draw an instance of the shadow first, following by the content.
|
// Draw an instance of the shadow first, following by the content.
|
||||||
|
|
||||||
// Both the shadow and the content get drawn as a brush image.
|
// Both the shadow and the content get drawn as a brush image.
|
||||||
|
@ -768,33 +769,44 @@ impl AlphaBatchBuilder {
|
||||||
// Get the GPU cache address of the extra data handle.
|
// Get the GPU cache address of the extra data handle.
|
||||||
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_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::ColorBitmap 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 {
|
let shadow_instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index: shadow_prim_header_index,
|
||||||
prim_address: shadow_prim_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::empty(),
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
brush_flags: BrushFlags::empty(),
|
brush_flags: BrushFlags::empty(),
|
||||||
user_data: [
|
|
||||||
shadow_uv_rect_address,
|
|
||||||
(ShaderColorMode::Alpha as i32) << 16 |
|
|
||||||
RasterizationSpace::Screen as i32,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let content_instance = BrushInstance {
|
let content_instance = BrushInstance {
|
||||||
prim_address: prim_cache_address,
|
prim_header_index: content_prim_header_index,
|
||||||
user_data: [
|
clip_task_address,
|
||||||
content_uv_rect_address,
|
segment_index: 0,
|
||||||
(ShaderColorMode::ColorBitmap as i32) << 16 |
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
RasterizationSpace::Screen as i32,
|
brush_flags: BrushFlags::empty(),
|
||||||
0,
|
|
||||||
],
|
|
||||||
..shadow_instance
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.batch_list
|
self.batch_list
|
||||||
|
@ -856,22 +868,18 @@ impl AlphaBatchBuilder {
|
||||||
|
|
||||||
let cache_task_id = surface.resolve_render_task_id();
|
let cache_task_id = surface.resolve_render_task_id();
|
||||||
let cache_task_address = render_tasks.get_task_address(cache_task_id);
|
let cache_task_address = render_tasks.get_task_address(cache_task_id);
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, [
|
||||||
|
cache_task_address.0 as i32,
|
||||||
|
filter_mode,
|
||||||
|
user_data,
|
||||||
|
]);
|
||||||
|
|
||||||
let instance = BrushInstance {
|
let instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::empty(),
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
brush_flags: BrushFlags::empty(),
|
brush_flags: BrushFlags::empty(),
|
||||||
user_data: [
|
|
||||||
cache_task_address.0 as i32,
|
|
||||||
filter_mode,
|
|
||||||
user_data,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
||||||
|
@ -907,22 +915,18 @@ impl AlphaBatchBuilder {
|
||||||
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
||||||
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
|
let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
|
||||||
let source_task_address = render_tasks.get_task_address(cache_task_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 {
|
let instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::empty(),
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
brush_flags: BrushFlags::empty(),
|
brush_flags: BrushFlags::empty(),
|
||||||
user_data: [
|
|
||||||
mode as u32 as i32,
|
|
||||||
backdrop_task_address.0 as i32,
|
|
||||||
source_task_address.0 as i32,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
batch.push(PrimitiveInstance::from(instance));
|
batch.push(PrimitiveInstance::from(instance));
|
||||||
|
@ -950,23 +954,19 @@ impl AlphaBatchBuilder {
|
||||||
let uv_rect_address = render_tasks[cache_task_id]
|
let uv_rect_address = render_tasks[cache_task_id]
|
||||||
.get_texture_address(gpu_cache)
|
.get_texture_address(gpu_cache)
|
||||||
.as_int();
|
.as_int();
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, [
|
||||||
|
uv_rect_address,
|
||||||
|
(ShaderColorMode::ColorBitmap as i32) << 16 |
|
||||||
|
RasterizationSpace::Screen as i32,
|
||||||
|
0,
|
||||||
|
]);
|
||||||
|
|
||||||
let instance = BrushInstance {
|
let instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::empty(),
|
edge_flags: EdgeAaSegmentMask::empty(),
|
||||||
brush_flags: BrushFlags::empty(),
|
brush_flags: BrushFlags::empty(),
|
||||||
user_data: [
|
|
||||||
uv_rect_address,
|
|
||||||
(ShaderColorMode::ColorBitmap as i32) << 16 |
|
|
||||||
RasterizationSpace::Screen as i32,
|
|
||||||
0,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
batch.push(PrimitiveInstance::from(instance));
|
batch.push(PrimitiveInstance::from(instance));
|
||||||
false
|
false
|
||||||
|
@ -986,7 +986,7 @@ impl AlphaBatchBuilder {
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
z_generator,
|
prim_headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -999,18 +999,21 @@ impl AlphaBatchBuilder {
|
||||||
request.with_tile(tile.tile_offset),
|
request.with_tile(tile.tile_offset),
|
||||||
) {
|
) {
|
||||||
let prim_cache_address = gpu_cache.get_address(&tile.handle);
|
let prim_cache_address = gpu_cache.get_address(&tile.handle);
|
||||||
|
let prim_header = PrimitiveHeader {
|
||||||
|
specific_prim_address: prim_cache_address,
|
||||||
|
local_rect: tile.local_rect,
|
||||||
|
local_clip_rect: tile.local_clip_rect,
|
||||||
|
..prim_header
|
||||||
|
};
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, user_data);
|
||||||
|
|
||||||
self.add_image_tile_to_batch(
|
self.add_image_tile_to_batch(
|
||||||
batch_kind,
|
batch_kind,
|
||||||
specified_blend_mode,
|
specified_blend_mode,
|
||||||
textures,
|
textures,
|
||||||
clip_chain_rect_index,
|
prim_header_index,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
&task_relative_bounding_rect,
|
&task_relative_bounding_rect,
|
||||||
prim_cache_address,
|
|
||||||
scroll_id,
|
|
||||||
task_address,
|
|
||||||
z,
|
|
||||||
user_data,
|
|
||||||
tile.edge_flags
|
tile.edge_flags
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1023,13 +1026,11 @@ impl AlphaBatchBuilder {
|
||||||
BrushBatchKind::LinearGradient,
|
BrushBatchKind::LinearGradient,
|
||||||
specified_blend_mode,
|
specified_blend_mode,
|
||||||
&task_relative_bounding_rect,
|
&task_relative_bounding_rect,
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
task_address,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
&mut self.batch_list,
|
&mut self.batch_list,
|
||||||
|
&prim_header,
|
||||||
|
prim_headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
BrushKind::RadialGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
|
BrushKind::RadialGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
|
||||||
|
@ -1039,13 +1040,11 @@ impl AlphaBatchBuilder {
|
||||||
BrushBatchKind::RadialGradient,
|
BrushBatchKind::RadialGradient,
|
||||||
specified_blend_mode,
|
specified_blend_mode,
|
||||||
&task_relative_bounding_rect,
|
&task_relative_bounding_rect,
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
task_address,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
&mut self.batch_list,
|
&mut self.batch_list,
|
||||||
|
&prim_header,
|
||||||
|
prim_headers,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1054,6 +1053,8 @@ impl AlphaBatchBuilder {
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
) {
|
) {
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, user_data);
|
||||||
|
|
||||||
self.add_brush_to_batch(
|
self.add_brush_to_batch(
|
||||||
brush,
|
brush,
|
||||||
prim_metadata,
|
prim_metadata,
|
||||||
|
@ -1061,16 +1062,11 @@ impl AlphaBatchBuilder {
|
||||||
specified_blend_mode,
|
specified_blend_mode,
|
||||||
non_segmented_blend_mode,
|
non_segmented_blend_mode,
|
||||||
textures,
|
textures,
|
||||||
clip_chain_rect_index,
|
prim_header_index,
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
&task_relative_bounding_rect,
|
&task_relative_bounding_rect,
|
||||||
prim_cache_address,
|
|
||||||
scroll_id,
|
|
||||||
task_address,
|
|
||||||
transform_kind,
|
transform_kind,
|
||||||
z,
|
|
||||||
render_tasks,
|
render_tasks,
|
||||||
user_data,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1080,17 +1076,13 @@ impl AlphaBatchBuilder {
|
||||||
let text_cpu =
|
let text_cpu =
|
||||||
&ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0];
|
&ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0];
|
||||||
|
|
||||||
let font = text_cpu.get_font(
|
let subpx_dir = text_cpu.used_font.get_subpx_dir();
|
||||||
ctx.device_pixel_scale,
|
|
||||||
scroll_node.transform,
|
|
||||||
);
|
|
||||||
let subpx_dir = font.get_subpx_dir();
|
|
||||||
|
|
||||||
let glyph_fetch_buffer = &mut self.glyph_fetch_buffer;
|
let glyph_fetch_buffer = &mut self.glyph_fetch_buffer;
|
||||||
let batch_list = &mut self.batch_list;
|
let batch_list = &mut self.batch_list;
|
||||||
|
|
||||||
ctx.resource_cache.fetch_glyphs(
|
ctx.resource_cache.fetch_glyphs(
|
||||||
font,
|
text_cpu.used_font.clone(),
|
||||||
&text_cpu.glyph_keys,
|
&text_cpu.glyph_keys,
|
||||||
glyph_fetch_buffer,
|
glyph_fetch_buffer,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
|
@ -1117,7 +1109,7 @@ impl AlphaBatchBuilder {
|
||||||
let (blend_mode, color_mode) = match glyph_format {
|
let (blend_mode, color_mode) = match glyph_format {
|
||||||
GlyphFormat::Subpixel |
|
GlyphFormat::Subpixel |
|
||||||
GlyphFormat::TransformedSubpixel => {
|
GlyphFormat::TransformedSubpixel => {
|
||||||
if text_cpu.font.bg_color.a != 0 {
|
if text_cpu.used_font.bg_color.a != 0 {
|
||||||
(
|
(
|
||||||
BlendMode::SubpixelWithBgColor,
|
BlendMode::SubpixelWithBgColor,
|
||||||
ShaderColorMode::FromRenderPassMode,
|
ShaderColorMode::FromRenderPassMode,
|
||||||
|
@ -1129,7 +1121,7 @@ impl AlphaBatchBuilder {
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()),
|
BlendMode::SubpixelConstantTextColor(text_cpu.used_font.color.into()),
|
||||||
ShaderColorMode::SubpixelConstantTextColor,
|
ShaderColorMode::SubpixelConstantTextColor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1155,15 +1147,11 @@ impl AlphaBatchBuilder {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, [0; 3]);
|
||||||
let key = BatchKey::new(kind, blend_mode, textures);
|
let key = BatchKey::new(kind, blend_mode, textures);
|
||||||
let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
|
||||||
let base_instance = GlyphInstance::new(
|
let base_instance = GlyphInstance::new(
|
||||||
prim_cache_address,
|
prim_header_index,
|
||||||
task_address,
|
|
||||||
clip_task_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
z,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for glyph in glyphs {
|
for glyph in glyphs {
|
||||||
|
@ -1185,27 +1173,17 @@ impl AlphaBatchBuilder {
|
||||||
batch_kind: BrushBatchKind,
|
batch_kind: BrushBatchKind,
|
||||||
blend_mode: BlendMode,
|
blend_mode: BlendMode,
|
||||||
textures: BatchTextures,
|
textures: BatchTextures,
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
prim_header_index: PrimitiveHeaderIndex,
|
||||||
clip_task_address: RenderTaskAddress,
|
clip_task_address: RenderTaskAddress,
|
||||||
task_relative_bounding_rect: &DeviceIntRect,
|
task_relative_bounding_rect: &DeviceIntRect,
|
||||||
prim_cache_address: GpuCacheAddress,
|
|
||||||
scroll_id: ClipScrollNodeIndex,
|
|
||||||
task_address: RenderTaskAddress,
|
|
||||||
z: ZBufferId,
|
|
||||||
user_data: [i32; 3],
|
|
||||||
edge_flags: EdgeAaSegmentMask,
|
edge_flags: EdgeAaSegmentMask,
|
||||||
) {
|
) {
|
||||||
let base_instance = BrushInstance {
|
let base_instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags,
|
edge_flags,
|
||||||
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
||||||
user_data,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.batch_list.add_bounding_rect(task_relative_bounding_rect);
|
self.batch_list.add_bounding_rect(task_relative_bounding_rect);
|
||||||
|
@ -1227,28 +1205,18 @@ impl AlphaBatchBuilder {
|
||||||
alpha_blend_mode: BlendMode,
|
alpha_blend_mode: BlendMode,
|
||||||
non_segmented_blend_mode: BlendMode,
|
non_segmented_blend_mode: BlendMode,
|
||||||
textures: BatchTextures,
|
textures: BatchTextures,
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
prim_header_index: PrimitiveHeaderIndex,
|
||||||
clip_task_address: RenderTaskAddress,
|
clip_task_address: RenderTaskAddress,
|
||||||
task_relative_bounding_rect: &DeviceIntRect,
|
task_relative_bounding_rect: &DeviceIntRect,
|
||||||
prim_cache_address: GpuCacheAddress,
|
|
||||||
scroll_id: ClipScrollNodeIndex,
|
|
||||||
task_address: RenderTaskAddress,
|
|
||||||
transform_kind: TransformedRectKind,
|
transform_kind: TransformedRectKind,
|
||||||
z: ZBufferId,
|
|
||||||
render_tasks: &RenderTaskTree,
|
render_tasks: &RenderTaskTree,
|
||||||
user_data: [i32; 3],
|
|
||||||
) {
|
) {
|
||||||
let base_instance = BrushInstance {
|
let base_instance = BrushInstance {
|
||||||
picture_address: task_address,
|
prim_header_index,
|
||||||
prim_address: prim_cache_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
clip_task_address,
|
||||||
z,
|
|
||||||
segment_index: 0,
|
segment_index: 0,
|
||||||
edge_flags: EdgeAaSegmentMask::all(),
|
edge_flags: EdgeAaSegmentMask::all(),
|
||||||
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
||||||
user_data,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.batch_list.add_bounding_rect(task_relative_bounding_rect);
|
self.batch_list.add_bounding_rect(task_relative_bounding_rect);
|
||||||
|
@ -1326,13 +1294,11 @@ fn add_gradient_tiles(
|
||||||
kind: BrushBatchKind,
|
kind: BrushBatchKind,
|
||||||
blend_mode: BlendMode,
|
blend_mode: BlendMode,
|
||||||
task_relative_bounding_rect: &DeviceIntRect,
|
task_relative_bounding_rect: &DeviceIntRect,
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
|
||||||
scroll_id: ClipScrollNodeIndex,
|
|
||||||
task_address: RenderTaskAddress,
|
|
||||||
clip_task_address: RenderTaskAddress,
|
clip_task_address: RenderTaskAddress,
|
||||||
z: ZBufferId,
|
|
||||||
gpu_cache: &GpuCache,
|
gpu_cache: &GpuCache,
|
||||||
batch_list: &mut BatchList,
|
batch_list: &mut BatchList,
|
||||||
|
base_prim_header: &PrimitiveHeader,
|
||||||
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
batch_list.add_bounding_rect(task_relative_bounding_rect);
|
batch_list.add_bounding_rect(task_relative_bounding_rect);
|
||||||
let batch = batch_list.get_suitable_batch(
|
let batch = batch_list.get_suitable_batch(
|
||||||
|
@ -1346,24 +1312,22 @@ fn add_gradient_tiles(
|
||||||
|
|
||||||
let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
|
let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
|
||||||
|
|
||||||
let base_instance = BrushInstance {
|
|
||||||
picture_address: task_address,
|
|
||||||
prim_address: GpuCacheAddress::invalid(),
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
clip_task_address,
|
|
||||||
z,
|
|
||||||
segment_index: 0,
|
|
||||||
edge_flags: EdgeAaSegmentMask::all(),
|
|
||||||
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
|
||||||
user_data,
|
|
||||||
};
|
|
||||||
|
|
||||||
for tile in visible_tiles {
|
for tile in visible_tiles {
|
||||||
|
let prim_header = PrimitiveHeader {
|
||||||
|
specific_prim_address: gpu_cache.get_address(&tile.handle),
|
||||||
|
local_rect: tile.local_rect,
|
||||||
|
local_clip_rect: tile.local_clip_rect,
|
||||||
|
..*base_prim_header
|
||||||
|
};
|
||||||
|
let prim_header_index = prim_headers.push(&prim_header, user_data);
|
||||||
|
|
||||||
batch.push(PrimitiveInstance::from(
|
batch.push(PrimitiveInstance::from(
|
||||||
BrushInstance {
|
BrushInstance {
|
||||||
prim_address: gpu_cache.get_address(&tile.handle),
|
prim_header_index,
|
||||||
..base_instance
|
clip_task_address,
|
||||||
|
segment_index: 0,
|
||||||
|
edge_flags: EdgeAaSegmentMask::all(),
|
||||||
|
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1783,7 +1747,7 @@ impl ClipBatcher {
|
||||||
) {
|
) {
|
||||||
let instance = ClipMaskInstance {
|
let instance = ClipMaskInstance {
|
||||||
render_task_address: task_address,
|
render_task_address: task_address,
|
||||||
scroll_node_data_index: ClipScrollNodeIndex(0),
|
transform_id: TransformPaletteId::identity(),
|
||||||
segment: 0,
|
segment: 0,
|
||||||
clip_data_address,
|
clip_data_address,
|
||||||
resource_address: GpuCacheAddress::invalid(),
|
resource_address: GpuCacheAddress::invalid(),
|
||||||
|
@ -1800,12 +1764,13 @@ impl ClipBatcher {
|
||||||
resource_cache: &ResourceCache,
|
resource_cache: &ResourceCache,
|
||||||
gpu_cache: &GpuCache,
|
gpu_cache: &GpuCache,
|
||||||
clip_store: &ClipStore,
|
clip_store: &ClipStore,
|
||||||
|
transforms: &TransformPalette,
|
||||||
) {
|
) {
|
||||||
let mut coordinate_system_id = coordinate_system_id;
|
let mut coordinate_system_id = coordinate_system_id;
|
||||||
for work_item in clips.iter() {
|
for work_item in clips.iter() {
|
||||||
let instance = ClipMaskInstance {
|
let instance = ClipMaskInstance {
|
||||||
render_task_address: task_address,
|
render_task_address: task_address,
|
||||||
scroll_node_data_index: work_item.scroll_node_data_index,
|
transform_id: transforms.get_id(work_item.transform_index),
|
||||||
segment: 0,
|
segment: 0,
|
||||||
clip_data_address: GpuCacheAddress::invalid(),
|
clip_data_address: GpuCacheAddress::invalid(),
|
||||||
resource_address: GpuCacheAddress::invalid(),
|
resource_address: GpuCacheAddress::invalid(),
|
||||||
|
|
|
@ -7,11 +7,11 @@ use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D, L
|
||||||
use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle};
|
use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle};
|
||||||
use border::{ensure_no_corner_overlap};
|
use border::{ensure_no_corner_overlap};
|
||||||
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
|
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
|
||||||
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId};
|
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformIndex};
|
||||||
use ellipse::Ellipse;
|
use ellipse::Ellipse;
|
||||||
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
|
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
|
||||||
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
||||||
use gpu_types::{BoxShadowStretchMode, ClipScrollNodeIndex};
|
use gpu_types::{BoxShadowStretchMode};
|
||||||
use prim_store::{ClipData, ImageMaskData};
|
use prim_store::{ClipData, ImageMaskData};
|
||||||
use render_task::to_cache_size;
|
use render_task::to_cache_size;
|
||||||
use resource_cache::{ImageRequest, ResourceCache};
|
use resource_cache::{ImageRequest, ResourceCache};
|
||||||
|
@ -625,7 +625,7 @@ impl Iterator for ClipChainNodeIter {
|
||||||
#[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 struct ClipWorkItem {
|
pub struct ClipWorkItem {
|
||||||
pub scroll_node_data_index: ClipScrollNodeIndex,
|
pub transform_index: TransformIndex,
|
||||||
pub clip_sources: ClipSourcesWeakHandle,
|
pub clip_sources: ClipSourcesWeakHandle,
|
||||||
pub coordinate_system_id: CoordinateSystemId,
|
pub coordinate_system_id: CoordinateSystemId,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,10 @@ use api::{LayoutVector2D, LayoutTransform, PipelineId, PropertyBinding};
|
||||||
use api::{ScrollClamping, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
|
use api::{ScrollClamping, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
|
||||||
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
|
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
|
||||||
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
|
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
|
||||||
use clip_scroll_tree::TransformUpdateState;
|
use clip_scroll_tree::{TransformUpdateState, TransformIndex};
|
||||||
use euclid::SideOffsets2D;
|
use euclid::SideOffsets2D;
|
||||||
use gpu_cache::GpuCache;
|
use gpu_cache::GpuCache;
|
||||||
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
|
use gpu_types::{TransformData, TransformPalette};
|
||||||
use resource_cache::ResourceCache;
|
use resource_cache::ResourceCache;
|
||||||
use scene::SceneProperties;
|
use scene::SceneProperties;
|
||||||
use util::{LayoutToWorldFastTransform, LayoutFastTransform};
|
use util::{LayoutToWorldFastTransform, LayoutFastTransform};
|
||||||
|
@ -46,9 +46,26 @@ impl StickyFrameInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NodeType {
|
pub enum SpatialNodeKind {
|
||||||
|
/// A special kind of node that adjusts its position based on the position
|
||||||
|
/// of its parent node and a given set of sticky positioning offset bounds.
|
||||||
|
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
|
||||||
|
/// https://www.w3.org/TR/css-position-3/#sticky-pos
|
||||||
|
StickyFrame(StickyFrameInfo),
|
||||||
|
|
||||||
|
/// Transforms it's content, but doesn't clip it. Can also be adjusted
|
||||||
|
/// by scroll events or setting scroll offsets.
|
||||||
|
ScrollFrame(ScrollFrameInfo),
|
||||||
|
|
||||||
/// A reference frame establishes a new coordinate space in the tree.
|
/// A reference frame establishes a new coordinate space in the tree.
|
||||||
ReferenceFrame(ReferenceFrameInfo),
|
ReferenceFrame(ReferenceFrameInfo),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum NodeType {
|
||||||
|
Spatial {
|
||||||
|
kind: SpatialNodeKind,
|
||||||
|
},
|
||||||
|
|
||||||
/// Other nodes just do clipping, but no transformation.
|
/// Other nodes just do clipping, but no transformation.
|
||||||
Clip {
|
Clip {
|
||||||
|
@ -61,16 +78,6 @@ pub enum NodeType {
|
||||||
clip_chain_node: Option<ClipChainNode>,
|
clip_chain_node: Option<ClipChainNode>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Transforms it's content, but doesn't clip it. Can also be adjusted
|
|
||||||
/// by scroll events or setting scroll offsets.
|
|
||||||
ScrollFrame(ScrollFrameInfo),
|
|
||||||
|
|
||||||
/// A special kind of node that adjusts its position based on the position
|
|
||||||
/// of its parent node and a given set of sticky positioning offset bounds.
|
|
||||||
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
|
|
||||||
/// https://www.w3.org/TR/css-position-3/#sticky-pos
|
|
||||||
StickyFrame(StickyFrameInfo),
|
|
||||||
|
|
||||||
/// An empty node, used to pad the ClipScrollTree's array of nodes so that
|
/// An empty node, used to pad the ClipScrollTree's array of nodes so that
|
||||||
/// we can immediately use each assigned ClipScrollNodeIndex. After display
|
/// we can immediately use each assigned ClipScrollNodeIndex. After display
|
||||||
/// list flattening this node type should never be used.
|
/// list flattening this node type should never be used.
|
||||||
|
@ -80,7 +87,7 @@ pub enum NodeType {
|
||||||
impl NodeType {
|
impl NodeType {
|
||||||
fn is_reference_frame(&self) -> bool {
|
fn is_reference_frame(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
NodeType::ReferenceFrame(_) => true,
|
NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(_), .. } => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,16 +133,18 @@ pub struct ClipScrollNode {
|
||||||
/// reference frame transforms.
|
/// reference frame transforms.
|
||||||
pub coordinate_system_relative_transform: LayoutFastTransform,
|
pub coordinate_system_relative_transform: LayoutFastTransform,
|
||||||
|
|
||||||
/// A linear ID / index of this clip-scroll node. Used as a reference to
|
/// The index of the spatial node that provides positioning information for this node.
|
||||||
/// pass to shaders, to allow them to fetch a given clip-scroll node.
|
/// For reference frames, scroll and sticky frames it is a unique identfier.
|
||||||
pub node_data_index: GPUClipScrollNodeIndex,
|
/// For clip nodes, this is the nearest ancestor spatial node.
|
||||||
|
pub transform_index: TransformIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipScrollNode {
|
impl ClipScrollNode {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
parent_index: Option<ClipScrollNodeIndex>,
|
parent_index: Option<ClipScrollNodeIndex>,
|
||||||
node_type: NodeType
|
node_type: NodeType,
|
||||||
|
transform_index: TransformIndex,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ClipScrollNode {
|
ClipScrollNode {
|
||||||
world_viewport_transform: LayoutToWorldFastTransform::identity(),
|
world_viewport_transform: LayoutToWorldFastTransform::identity(),
|
||||||
|
@ -148,12 +157,17 @@ impl ClipScrollNode {
|
||||||
invertible: true,
|
invertible: true,
|
||||||
coordinate_system_id: CoordinateSystemId(0),
|
coordinate_system_id: CoordinateSystemId(0),
|
||||||
coordinate_system_relative_transform: LayoutFastTransform::identity(),
|
coordinate_system_relative_transform: LayoutFastTransform::identity(),
|
||||||
node_data_index: GPUClipScrollNodeIndex(0),
|
transform_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> ClipScrollNode {
|
pub fn empty() -> ClipScrollNode {
|
||||||
Self::new(PipelineId::dummy(), None, NodeType::Empty)
|
Self::new(
|
||||||
|
PipelineId::dummy(),
|
||||||
|
None,
|
||||||
|
NodeType::Empty,
|
||||||
|
TransformIndex(0),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_scroll_frame(
|
pub fn new_scroll_frame(
|
||||||
|
@ -163,18 +177,26 @@ impl ClipScrollNode {
|
||||||
frame_rect: &LayoutRect,
|
frame_rect: &LayoutRect,
|
||||||
content_size: &LayoutSize,
|
content_size: &LayoutSize,
|
||||||
scroll_sensitivity: ScrollSensitivity,
|
scroll_sensitivity: ScrollSensitivity,
|
||||||
|
transform_index: TransformIndex,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let node_type = NodeType::ScrollFrame(ScrollFrameInfo::new(
|
let node_type = NodeType::Spatial {
|
||||||
*frame_rect,
|
kind: SpatialNodeKind::ScrollFrame(ScrollFrameInfo::new(
|
||||||
scroll_sensitivity,
|
*frame_rect,
|
||||||
LayoutSize::new(
|
scroll_sensitivity,
|
||||||
(content_size.width - frame_rect.size.width).max(0.0),
|
LayoutSize::new(
|
||||||
(content_size.height - frame_rect.size.height).max(0.0)
|
(content_size.width - frame_rect.size.width).max(0.0),
|
||||||
),
|
(content_size.height - frame_rect.size.height).max(0.0)
|
||||||
external_id,
|
),
|
||||||
));
|
external_id,
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
|
||||||
Self::new(pipeline_id, Some(parent_index), node_type)
|
Self::new(
|
||||||
|
pipeline_id,
|
||||||
|
Some(parent_index),
|
||||||
|
node_type,
|
||||||
|
transform_index,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_reference_frame(
|
pub fn new_reference_frame(
|
||||||
|
@ -183,6 +205,7 @@ impl ClipScrollNode {
|
||||||
source_perspective: Option<LayoutTransform>,
|
source_perspective: Option<LayoutTransform>,
|
||||||
origin_in_parent_reference_frame: LayoutVector2D,
|
origin_in_parent_reference_frame: LayoutVector2D,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
|
transform_index: TransformIndex,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let identity = LayoutTransform::identity();
|
let identity = LayoutTransform::identity();
|
||||||
let source_perspective = source_perspective.map_or_else(
|
let source_perspective = source_perspective.map_or_else(
|
||||||
|
@ -194,16 +217,31 @@ impl ClipScrollNode {
|
||||||
origin_in_parent_reference_frame,
|
origin_in_parent_reference_frame,
|
||||||
invertible: true,
|
invertible: true,
|
||||||
};
|
};
|
||||||
Self::new(pipeline_id, parent_index, NodeType::ReferenceFrame(info))
|
Self::new(
|
||||||
|
pipeline_id,
|
||||||
|
parent_index,
|
||||||
|
NodeType::Spatial {
|
||||||
|
kind: SpatialNodeKind::ReferenceFrame(info),
|
||||||
|
},
|
||||||
|
transform_index,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_sticky_frame(
|
pub fn new_sticky_frame(
|
||||||
parent_index: ClipScrollNodeIndex,
|
parent_index: ClipScrollNodeIndex,
|
||||||
sticky_frame_info: StickyFrameInfo,
|
sticky_frame_info: StickyFrameInfo,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
|
transform_index: TransformIndex,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let node_type = NodeType::StickyFrame(sticky_frame_info);
|
let node_type = NodeType::Spatial {
|
||||||
Self::new(pipeline_id, Some(parent_index), node_type)
|
kind: SpatialNodeKind::StickyFrame(sticky_frame_info),
|
||||||
|
};
|
||||||
|
Self::new(
|
||||||
|
pipeline_id,
|
||||||
|
Some(parent_index),
|
||||||
|
node_type,
|
||||||
|
transform_index,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,7 +251,7 @@ impl ClipScrollNode {
|
||||||
|
|
||||||
pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) {
|
pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) {
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType::ScrollFrame(ref mut scrolling) => {
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => {
|
||||||
*scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info);
|
*scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info);
|
||||||
}
|
}
|
||||||
_ if old_scroll_info.offset != LayoutVector2D::zero() => {
|
_ if old_scroll_info.offset != LayoutVector2D::zero() => {
|
||||||
|
@ -229,7 +267,7 @@ impl ClipScrollNode {
|
||||||
let scrollable_height = scrollable_size.height;
|
let scrollable_height = scrollable_size.height;
|
||||||
|
|
||||||
let scrolling = match self.node_type {
|
let scrolling = match self.node_type {
|
||||||
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => scrolling,
|
||||||
_ => {
|
_ => {
|
||||||
warn!("Tried to scroll a non-scroll node.");
|
warn!("Tried to scroll a non-scroll node.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -265,29 +303,32 @@ impl ClipScrollNode {
|
||||||
self.world_viewport_transform = LayoutToWorldFastTransform::identity();
|
self.world_viewport_transform = LayoutToWorldFastTransform::identity();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) {
|
pub fn push_gpu_data(
|
||||||
if !self.invertible {
|
&mut self,
|
||||||
node_data.push(ClipScrollNodeData::invalid());
|
transform_palette: &mut TransformPalette,
|
||||||
return;
|
) {
|
||||||
}
|
if let NodeType::Spatial { .. } = self.node_type {
|
||||||
|
if !self.invertible {
|
||||||
let inv_transform = match self.world_content_transform.inverse() {
|
transform_palette.set(self.transform_index, TransformData::invalid());
|
||||||
Some(inverted) => inverted.to_transform(),
|
|
||||||
None => {
|
|
||||||
node_data.push(ClipScrollNodeData::invalid());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let data = ClipScrollNodeData {
|
let inv_transform = match self.world_content_transform.inverse() {
|
||||||
transform: self.world_content_transform.into(),
|
Some(inverted) => inverted.to_transform(),
|
||||||
inv_transform,
|
None => {
|
||||||
transform_kind: self.transform_kind as u32 as f32,
|
transform_palette.set(self.transform_index, TransformData::invalid());
|
||||||
padding: [0.0; 3],
|
return;
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Write the data that will be made available to the GPU for this node.
|
let data = TransformData {
|
||||||
node_data.push(data);
|
transform: self.world_content_transform.into(),
|
||||||
|
inv_transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the data that will be made available to the GPU for this node.
|
||||||
|
transform_palette.set(self.transform_index, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(
|
pub fn update(
|
||||||
|
@ -320,7 +361,7 @@ impl ClipScrollNode {
|
||||||
// For non-reference-frames we assume that they will produce only additional
|
// For non-reference-frames we assume that they will produce only additional
|
||||||
// translations which should be invertible.
|
// translations which should be invertible.
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType::ReferenceFrame(info) if !info.invertible => {
|
NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(info), .. } if !info.invertible => {
|
||||||
self.mark_uninvertible();
|
self.mark_uninvertible();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +388,7 @@ impl ClipScrollNode {
|
||||||
clip_chains: &mut [ClipChain],
|
clip_chains: &mut [ClipChain],
|
||||||
) {
|
) {
|
||||||
let (clip_sources_handle, clip_chain_index, stored_clip_chain_node) = match self.node_type {
|
let (clip_sources_handle, clip_chain_index, stored_clip_chain_node) = match self.node_type {
|
||||||
NodeType::Clip { ref handle, clip_chain_index, ref mut clip_chain_node } =>
|
NodeType::Clip { ref handle, clip_chain_index, ref mut clip_chain_node, .. } =>
|
||||||
(handle, clip_chain_index, clip_chain_node),
|
(handle, clip_chain_index, clip_chain_node),
|
||||||
_ => {
|
_ => {
|
||||||
self.invertible = true;
|
self.invertible = true;
|
||||||
|
@ -378,7 +419,7 @@ impl ClipScrollNode {
|
||||||
|
|
||||||
let new_node = ClipChainNode {
|
let new_node = ClipChainNode {
|
||||||
work_item: ClipWorkItem {
|
work_item: ClipWorkItem {
|
||||||
scroll_node_data_index: self.node_data_index,
|
transform_index: self.transform_index,
|
||||||
clip_sources: clip_sources_handle.weak(),
|
clip_sources: clip_sources_handle.weak(),
|
||||||
coordinate_system_id: state.current_coordinate_system_id,
|
coordinate_system_id: state.current_coordinate_system_id,
|
||||||
},
|
},
|
||||||
|
@ -442,9 +483,8 @@ impl ClipScrollNode {
|
||||||
self.coordinate_system_relative_transform =
|
self.coordinate_system_relative_transform =
|
||||||
state.coordinate_system_relative_transform.offset(added_offset);
|
state.coordinate_system_relative_transform.offset(added_offset);
|
||||||
|
|
||||||
match self.node_type {
|
if let NodeType::Spatial { kind: SpatialNodeKind::StickyFrame(ref mut info), .. } = self.node_type {
|
||||||
NodeType::StickyFrame(ref mut info) => info.current_offset = sticky_offset,
|
info.current_offset = sticky_offset;
|
||||||
_ => {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.coordinate_system_id = state.current_coordinate_system_id;
|
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||||
|
@ -457,7 +497,7 @@ impl ClipScrollNode {
|
||||||
scene_properties: &SceneProperties,
|
scene_properties: &SceneProperties,
|
||||||
) {
|
) {
|
||||||
let info = match self.node_type {
|
let info = match self.node_type {
|
||||||
NodeType::ReferenceFrame(ref mut info) => info,
|
NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(ref mut info), .. } => info,
|
||||||
_ => unreachable!("Called update_transform_for_reference_frame on non-ReferenceFrame"),
|
_ => unreachable!("Called update_transform_for_reference_frame on non-ReferenceFrame"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -505,7 +545,7 @@ impl ClipScrollNode {
|
||||||
viewport_rect: &LayoutRect,
|
viewport_rect: &LayoutRect,
|
||||||
) -> LayoutVector2D {
|
) -> LayoutVector2D {
|
||||||
let info = match self.node_type {
|
let info = match self.node_type {
|
||||||
NodeType::StickyFrame(ref info) => info,
|
NodeType::Spatial { kind: SpatialNodeKind::StickyFrame(ref info), .. } => info,
|
||||||
_ => return LayoutVector2D::zero(),
|
_ => return LayoutVector2D::zero(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -619,45 +659,48 @@ impl ClipScrollNode {
|
||||||
// between us and the parent reference frame. If we are a reference frame,
|
// between us and the parent reference frame. If we are a reference frame,
|
||||||
// we need to reset both these values.
|
// we need to reset both these values.
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType::ReferenceFrame(ref info) => {
|
NodeType::Spatial { ref kind, .. } => {
|
||||||
state.parent_reference_frame_transform = self.world_viewport_transform;
|
match *kind {
|
||||||
state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
|
SpatialNodeKind::StickyFrame(ref info) => {
|
||||||
state.coordinate_system_relative_transform =
|
// We don't translate the combined rect by the sticky offset, because sticky
|
||||||
self.coordinate_system_relative_transform.clone();
|
// offsets actually adjust the node position itself, whereas scroll offsets
|
||||||
let translation = -info.origin_in_parent_reference_frame;
|
// only apply to contents inside the node.
|
||||||
state.nearest_scrolling_ancestor_viewport =
|
state.parent_accumulated_scroll_offset =
|
||||||
state.nearest_scrolling_ancestor_viewport
|
info.current_offset + state.parent_accumulated_scroll_offset;
|
||||||
.translate(&translation);
|
}
|
||||||
|
SpatialNodeKind::ScrollFrame(ref scrolling) => {
|
||||||
|
state.parent_accumulated_scroll_offset =
|
||||||
|
scrolling.offset + state.parent_accumulated_scroll_offset;
|
||||||
|
state.nearest_scrolling_ancestor_offset = scrolling.offset;
|
||||||
|
state.nearest_scrolling_ancestor_viewport = scrolling.viewport_rect;
|
||||||
|
}
|
||||||
|
SpatialNodeKind::ReferenceFrame(ref info) => {
|
||||||
|
state.parent_reference_frame_transform = self.world_viewport_transform;
|
||||||
|
state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
|
||||||
|
state.coordinate_system_relative_transform =
|
||||||
|
self.coordinate_system_relative_transform.clone();
|
||||||
|
let translation = -info.origin_in_parent_reference_frame;
|
||||||
|
state.nearest_scrolling_ancestor_viewport =
|
||||||
|
state.nearest_scrolling_ancestor_viewport
|
||||||
|
.translate(&translation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NodeType::Clip{ .. } => { }
|
NodeType::Clip{ .. } => { }
|
||||||
NodeType::ScrollFrame(ref scrolling) => {
|
|
||||||
state.parent_accumulated_scroll_offset =
|
|
||||||
scrolling.offset + state.parent_accumulated_scroll_offset;
|
|
||||||
state.nearest_scrolling_ancestor_offset = scrolling.offset;
|
|
||||||
state.nearest_scrolling_ancestor_viewport = scrolling.viewport_rect;
|
|
||||||
}
|
|
||||||
NodeType::StickyFrame(ref info) => {
|
|
||||||
// We don't translate the combined rect by the sticky offset, because sticky
|
|
||||||
// offsets actually adjust the node position itself, whereas scroll offsets
|
|
||||||
// only apply to contents inside the node.
|
|
||||||
state.parent_accumulated_scroll_offset =
|
|
||||||
info.current_offset + state.parent_accumulated_scroll_offset;
|
|
||||||
}
|
|
||||||
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scrollable_size(&self) -> LayoutSize {
|
pub fn scrollable_size(&self) -> LayoutSize {
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType:: ScrollFrame(state) => state.scrollable_size,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(state), .. } => state.scrollable_size,
|
||||||
_ => LayoutSize::zero(),
|
_ => LayoutSize::zero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn scroll(&mut self, scroll_location: ScrollLocation) -> bool {
|
pub fn scroll(&mut self, scroll_location: ScrollLocation) -> bool {
|
||||||
let scrolling = match self.node_type {
|
let scrolling = match self.node_type {
|
||||||
NodeType::ScrollFrame(ref mut scrolling) => scrolling,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => scrolling,
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -707,14 +750,14 @@ impl ClipScrollNode {
|
||||||
|
|
||||||
pub fn scroll_offset(&self) -> LayoutVector2D {
|
pub fn scroll_offset(&self) -> LayoutVector2D {
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType::ScrollFrame(ref scrolling) => scrolling.offset,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref scrolling), .. } => scrolling.offset,
|
||||||
_ => LayoutVector2D::zero(),
|
_ => LayoutVector2D::zero(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool {
|
pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool {
|
||||||
match self.node_type {
|
match self.node_type {
|
||||||
NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } if info.external_id == Some(external_id) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
|
|
||||||
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
|
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
|
||||||
use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
|
use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
|
||||||
use api::WorldPoint;
|
use api::{LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
|
||||||
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
|
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
|
||||||
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo};
|
use clip_scroll_node::{ClipScrollNode, NodeType, SpatialNodeKind, ScrollFrameInfo, StickyFrameInfo};
|
||||||
use gpu_cache::GpuCache;
|
use gpu_cache::GpuCache;
|
||||||
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData};
|
use gpu_types::TransformPalette;
|
||||||
use internal_types::{FastHashMap, FastHashSet};
|
use internal_types::{FastHashMap, FastHashSet};
|
||||||
use print_tree::{PrintTree, PrintTreePrinter};
|
use print_tree::{PrintTree, PrintTreePrinter};
|
||||||
use resource_cache::ResourceCache;
|
use resource_cache::ResourceCache;
|
||||||
|
@ -29,6 +29,15 @@ pub struct CoordinateSystemId(pub u32);
|
||||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||||
pub struct ClipScrollNodeIndex(pub usize);
|
pub struct ClipScrollNodeIndex(pub usize);
|
||||||
|
|
||||||
|
// Used to index the smaller subset of nodes in the CST that define
|
||||||
|
// new transform / positioning.
|
||||||
|
// TODO(gw): In the future if we split the CST into a positioning and
|
||||||
|
// clipping tree, this can be tidied up a bit.
|
||||||
|
#[derive(Copy, Debug, Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct TransformIndex(pub u32);
|
||||||
|
|
||||||
const ROOT_REFERENCE_FRAME_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(0);
|
const ROOT_REFERENCE_FRAME_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(0);
|
||||||
const TOPMOST_SCROLL_NODE_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(1);
|
const TOPMOST_SCROLL_NODE_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(1);
|
||||||
|
|
||||||
|
@ -70,14 +79,13 @@ pub struct ClipScrollTree {
|
||||||
|
|
||||||
pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayoutPoint, ScrollClamping)>,
|
pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayoutPoint, ScrollClamping)>,
|
||||||
|
|
||||||
/// The current frame id, used for giving a unique id to all new dynamically
|
|
||||||
/// added frames and clips. The ClipScrollTree increments this by one every
|
|
||||||
/// time a new dynamic frame is created.
|
|
||||||
current_new_node_item: u64,
|
|
||||||
|
|
||||||
/// A set of pipelines which should be discarded the next time this
|
/// A set of pipelines which should be discarded the next time this
|
||||||
/// tree is drained.
|
/// tree is drained.
|
||||||
pub pipelines_to_discard: FastHashSet<PipelineId>,
|
pub pipelines_to_discard: FastHashSet<PipelineId>,
|
||||||
|
|
||||||
|
/// The number of nodes in the CST that are spatial. Currently, this is all
|
||||||
|
/// nodes that are not clip nodes.
|
||||||
|
spatial_node_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -112,8 +120,8 @@ impl ClipScrollTree {
|
||||||
clip_chains_descriptors: Vec::new(),
|
clip_chains_descriptors: Vec::new(),
|
||||||
clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())],
|
clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())],
|
||||||
pending_scroll_offsets: FastHashMap::default(),
|
pending_scroll_offsets: FastHashMap::default(),
|
||||||
current_new_node_item: 1,
|
|
||||||
pipelines_to_discard: FastHashSet::default(),
|
pipelines_to_discard: FastHashSet::default(),
|
||||||
|
spatial_node_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +144,7 @@ impl ClipScrollTree {
|
||||||
pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
|
pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
for node in &self.nodes {
|
for node in &self.nodes {
|
||||||
if let NodeType::ScrollFrame(info) = node.node_type {
|
if let NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } = node.node_type {
|
||||||
if let Some(id) = info.external_id {
|
if let Some(id) = info.external_id {
|
||||||
result.push(ScrollNodeState { id, scroll_offset: info.offset })
|
result.push(ScrollNodeState { id, scroll_offset: info.offset })
|
||||||
}
|
}
|
||||||
|
@ -146,8 +154,6 @@ impl ClipScrollTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drain(&mut self) -> ScrollStates {
|
pub fn drain(&mut self) -> ScrollStates {
|
||||||
self.current_new_node_item = 1;
|
|
||||||
|
|
||||||
let mut scroll_states = FastHashMap::default();
|
let mut scroll_states = FastHashMap::default();
|
||||||
for old_node in &mut self.nodes.drain(..) {
|
for old_node in &mut self.nodes.drain(..) {
|
||||||
if self.pipelines_to_discard.contains(&old_node.pipeline_id) {
|
if self.pipelines_to_discard.contains(&old_node.pipeline_id) {
|
||||||
|
@ -155,13 +161,14 @@ impl ClipScrollTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
match old_node.node_type {
|
match old_node.node_type {
|
||||||
NodeType::ScrollFrame(info) if info.external_id.is_some() => {
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } if info.external_id.is_some() => {
|
||||||
scroll_states.insert(info.external_id.unwrap(), info);
|
scroll_states.insert(info.external_id.unwrap(), info);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.spatial_node_count = 0;
|
||||||
self.pipelines_to_discard.clear();
|
self.pipelines_to_discard.clear();
|
||||||
self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())];
|
self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())];
|
||||||
self.clip_chains_descriptors.clear();
|
self.clip_chains_descriptors.clear();
|
||||||
|
@ -195,7 +202,7 @@ impl ClipScrollTree {
|
||||||
|
|
||||||
let node = &self.nodes[index.0];
|
let node = &self.nodes[index.0];
|
||||||
match node.node_type {
|
match node.node_type {
|
||||||
NodeType::ScrollFrame(state) if state.sensitive_to_input_events() => index,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(state), .. } if state.sensitive_to_input_events() => index,
|
||||||
_ => self.find_nearest_scrolling_ancestor(node.parent)
|
_ => self.find_nearest_scrolling_ancestor(node.parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,40 +227,41 @@ impl ClipScrollTree {
|
||||||
resource_cache: &mut ResourceCache,
|
resource_cache: &mut ResourceCache,
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
pan: WorldPoint,
|
pan: WorldPoint,
|
||||||
node_data: &mut Vec<ClipScrollNodeData>,
|
|
||||||
scene_properties: &SceneProperties,
|
scene_properties: &SceneProperties,
|
||||||
) {
|
) -> TransformPalette {
|
||||||
if self.nodes.is_empty() {
|
let mut transform_palette = TransformPalette::new(self.spatial_node_count);
|
||||||
return;
|
|
||||||
|
if !self.nodes.is_empty() {
|
||||||
|
self.clip_chains[0] = ClipChain::empty(screen_rect);
|
||||||
|
|
||||||
|
let root_reference_frame_index = self.root_reference_frame_index();
|
||||||
|
let mut state = TransformUpdateState {
|
||||||
|
parent_reference_frame_transform: LayoutVector2D::new(pan.x, pan.y).into(),
|
||||||
|
parent_accumulated_scroll_offset: LayoutVector2D::zero(),
|
||||||
|
nearest_scrolling_ancestor_offset: LayoutVector2D::zero(),
|
||||||
|
nearest_scrolling_ancestor_viewport: LayoutRect::zero(),
|
||||||
|
parent_clip_chain_index: ClipChainIndex(0),
|
||||||
|
current_coordinate_system_id: CoordinateSystemId::root(),
|
||||||
|
coordinate_system_relative_transform: LayoutFastTransform::identity(),
|
||||||
|
invertible: true,
|
||||||
|
};
|
||||||
|
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
|
||||||
|
self.update_node(
|
||||||
|
root_reference_frame_index,
|
||||||
|
&mut state,
|
||||||
|
&mut next_coordinate_system_id,
|
||||||
|
device_pixel_scale,
|
||||||
|
clip_store,
|
||||||
|
resource_cache,
|
||||||
|
gpu_cache,
|
||||||
|
&mut transform_palette,
|
||||||
|
scene_properties,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.build_clip_chains(screen_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clip_chains[0] = ClipChain::empty(screen_rect);
|
transform_palette
|
||||||
|
|
||||||
let root_reference_frame_index = self.root_reference_frame_index();
|
|
||||||
let mut state = TransformUpdateState {
|
|
||||||
parent_reference_frame_transform: LayoutVector2D::new(pan.x, pan.y).into(),
|
|
||||||
parent_accumulated_scroll_offset: LayoutVector2D::zero(),
|
|
||||||
nearest_scrolling_ancestor_offset: LayoutVector2D::zero(),
|
|
||||||
nearest_scrolling_ancestor_viewport: LayoutRect::zero(),
|
|
||||||
parent_clip_chain_index: ClipChainIndex(0),
|
|
||||||
current_coordinate_system_id: CoordinateSystemId::root(),
|
|
||||||
coordinate_system_relative_transform: LayoutFastTransform::identity(),
|
|
||||||
invertible: true,
|
|
||||||
};
|
|
||||||
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
|
|
||||||
self.update_node(
|
|
||||||
root_reference_frame_index,
|
|
||||||
&mut state,
|
|
||||||
&mut next_coordinate_system_id,
|
|
||||||
device_pixel_scale,
|
|
||||||
clip_store,
|
|
||||||
resource_cache,
|
|
||||||
gpu_cache,
|
|
||||||
node_data,
|
|
||||||
scene_properties,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.build_clip_chains(screen_rect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_node(
|
fn update_node(
|
||||||
|
@ -265,7 +273,7 @@ impl ClipScrollTree {
|
||||||
clip_store: &mut ClipStore,
|
clip_store: &mut ClipStore,
|
||||||
resource_cache: &mut ResourceCache,
|
resource_cache: &mut ResourceCache,
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
gpu_node_data: &mut Vec<ClipScrollNodeData>,
|
transform_palette: &mut TransformPalette,
|
||||||
scene_properties: &SceneProperties,
|
scene_properties: &SceneProperties,
|
||||||
) {
|
) {
|
||||||
// TODO(gw): This is an ugly borrow check workaround to clone these.
|
// TODO(gw): This is an ugly borrow check workaround to clone these.
|
||||||
|
@ -277,9 +285,6 @@ impl ClipScrollTree {
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
// We set this early so that we can use it to populate the ClipChain.
|
|
||||||
node.node_data_index = GPUClipScrollNodeIndex(gpu_node_data.len() as u32);
|
|
||||||
|
|
||||||
node.update(
|
node.update(
|
||||||
&mut state,
|
&mut state,
|
||||||
next_coordinate_system_id,
|
next_coordinate_system_id,
|
||||||
|
@ -291,7 +296,7 @@ impl ClipScrollTree {
|
||||||
&mut self.clip_chains,
|
&mut self.clip_chains,
|
||||||
);
|
);
|
||||||
|
|
||||||
node.push_gpu_node_data(gpu_node_data);
|
node.push_gpu_data(transform_palette);
|
||||||
|
|
||||||
if node.children.is_empty() {
|
if node.children.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -310,7 +315,7 @@ impl ClipScrollTree {
|
||||||
clip_store,
|
clip_store,
|
||||||
resource_cache,
|
resource_cache,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
gpu_node_data,
|
transform_palette,
|
||||||
scene_properties,
|
scene_properties,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +351,7 @@ impl ClipScrollTree {
|
||||||
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
|
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
|
||||||
for node in &mut self.nodes {
|
for node in &mut self.nodes {
|
||||||
let external_id = match node.node_type {
|
let external_id = match node.node_type {
|
||||||
NodeType::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ) => id,
|
NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ), .. } => id,
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -360,6 +365,13 @@ impl ClipScrollTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate the next valid TransformIndex for the CST.
|
||||||
|
fn next_transform_index(&mut self) -> TransformIndex {
|
||||||
|
let transform_index = TransformIndex(self.spatial_node_count as u32);
|
||||||
|
self.spatial_node_count += 1;
|
||||||
|
transform_index
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_clip_node(
|
pub fn add_clip_node(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: ClipScrollNodeIndex,
|
index: ClipScrollNodeIndex,
|
||||||
|
@ -368,12 +380,65 @@ impl ClipScrollTree {
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
) -> ClipChainIndex {
|
) -> ClipChainIndex {
|
||||||
let clip_chain_index = self.allocate_clip_chain();
|
let clip_chain_index = self.allocate_clip_chain();
|
||||||
let node_type = NodeType::Clip { handle, clip_chain_index, clip_chain_node: None };
|
let transform_index = self.nodes[parent_index.0].transform_index;
|
||||||
let node = ClipScrollNode::new(pipeline_id, Some(parent_index), node_type);
|
|
||||||
|
let node_type = NodeType::Clip {
|
||||||
|
handle,
|
||||||
|
clip_chain_index,
|
||||||
|
clip_chain_node: None,
|
||||||
|
};
|
||||||
|
let node = ClipScrollNode::new(
|
||||||
|
pipeline_id,
|
||||||
|
Some(parent_index),
|
||||||
|
node_type,
|
||||||
|
transform_index,
|
||||||
|
);
|
||||||
self.add_node(node, index);
|
self.add_node(node, index);
|
||||||
clip_chain_index
|
clip_chain_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_scroll_frame(
|
||||||
|
&mut self,
|
||||||
|
index: ClipScrollNodeIndex,
|
||||||
|
parent_index: ClipScrollNodeIndex,
|
||||||
|
external_id: Option<ExternalScrollId>,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
frame_rect: &LayoutRect,
|
||||||
|
content_size: &LayoutSize,
|
||||||
|
scroll_sensitivity: ScrollSensitivity,
|
||||||
|
) {
|
||||||
|
let node = ClipScrollNode::new_scroll_frame(
|
||||||
|
pipeline_id,
|
||||||
|
parent_index,
|
||||||
|
external_id,
|
||||||
|
frame_rect,
|
||||||
|
content_size,
|
||||||
|
scroll_sensitivity,
|
||||||
|
self.next_transform_index(),
|
||||||
|
);
|
||||||
|
self.add_node(node, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_reference_frame(
|
||||||
|
&mut self,
|
||||||
|
index: ClipScrollNodeIndex,
|
||||||
|
parent_index: Option<ClipScrollNodeIndex>,
|
||||||
|
source_transform: Option<PropertyBinding<LayoutTransform>>,
|
||||||
|
source_perspective: Option<LayoutTransform>,
|
||||||
|
origin_in_parent_reference_frame: LayoutVector2D,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
) {
|
||||||
|
let node = ClipScrollNode::new_reference_frame(
|
||||||
|
parent_index,
|
||||||
|
source_transform,
|
||||||
|
source_perspective,
|
||||||
|
origin_in_parent_reference_frame,
|
||||||
|
pipeline_id,
|
||||||
|
self.next_transform_index(),
|
||||||
|
);
|
||||||
|
self.add_node(node, index);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_sticky_frame(
|
pub fn add_sticky_frame(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: ClipScrollNodeIndex,
|
index: ClipScrollNodeIndex,
|
||||||
|
@ -381,7 +446,12 @@ impl ClipScrollTree {
|
||||||
sticky_frame_info: StickyFrameInfo,
|
sticky_frame_info: StickyFrameInfo,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
) {
|
) {
|
||||||
let node = ClipScrollNode::new_sticky_frame(parent_index, sticky_frame_info, pipeline_id);
|
let node = ClipScrollNode::new_sticky_frame(
|
||||||
|
parent_index,
|
||||||
|
sticky_frame_info,
|
||||||
|
pipeline_id,
|
||||||
|
self.next_transform_index(),
|
||||||
|
);
|
||||||
self.add_node(node, index);
|
self.add_node(node, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,6 +506,26 @@ impl ClipScrollTree {
|
||||||
) {
|
) {
|
||||||
let node = &self.nodes[index.0];
|
let node = &self.nodes[index.0];
|
||||||
match node.node_type {
|
match node.node_type {
|
||||||
|
NodeType::Spatial { ref kind, .. } => {
|
||||||
|
match *kind {
|
||||||
|
SpatialNodeKind::StickyFrame(ref sticky_frame_info) => {
|
||||||
|
pt.new_level(format!("StickyFrame"));
|
||||||
|
pt.add_item(format!("index: {:?}", index));
|
||||||
|
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
|
||||||
|
}
|
||||||
|
SpatialNodeKind::ScrollFrame(scrolling_info) => {
|
||||||
|
pt.new_level(format!("ScrollFrame"));
|
||||||
|
pt.add_item(format!("index: {:?}", index));
|
||||||
|
pt.add_item(format!("viewport: {:?}", scrolling_info.viewport_rect));
|
||||||
|
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
|
||||||
|
pt.add_item(format!("scroll offset: {:?}", scrolling_info.offset));
|
||||||
|
}
|
||||||
|
SpatialNodeKind::ReferenceFrame(ref info) => {
|
||||||
|
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
|
||||||
|
pt.add_item(format!("index: {:?}", index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
NodeType::Clip { ref handle, .. } => {
|
NodeType::Clip { ref handle, .. } => {
|
||||||
pt.new_level("Clip".to_owned());
|
pt.new_level("Clip".to_owned());
|
||||||
|
|
||||||
|
@ -447,22 +537,6 @@ impl ClipScrollTree {
|
||||||
}
|
}
|
||||||
pt.end_level();
|
pt.end_level();
|
||||||
}
|
}
|
||||||
NodeType::ReferenceFrame(ref info) => {
|
|
||||||
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
|
|
||||||
pt.add_item(format!("index: {:?}", index));
|
|
||||||
}
|
|
||||||
NodeType::ScrollFrame(scrolling_info) => {
|
|
||||||
pt.new_level(format!("ScrollFrame"));
|
|
||||||
pt.add_item(format!("index: {:?}", index));
|
|
||||||
pt.add_item(format!("viewport: {:?}", scrolling_info.viewport_rect));
|
|
||||||
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
|
|
||||||
pt.add_item(format!("scroll offset: {:?}", scrolling_info.offset));
|
|
||||||
}
|
|
||||||
NodeType::StickyFrame(ref sticky_frame_info) => {
|
|
||||||
pt.new_level(format!("StickyFrame"));
|
|
||||||
pt.add_item(format!("index: {:?}", index));
|
|
||||||
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
|
|
||||||
}
|
|
||||||
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use super::shader_source;
|
use super::super::shader_source;
|
||||||
use api::{ColorF, ImageFormat};
|
use api::{ColorF, ImageFormat};
|
||||||
use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
|
use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
|
||||||
use api::TextureTarget;
|
use api::TextureTarget;
|
||||||
|
@ -2234,6 +2234,11 @@ impl Device {
|
||||||
external: gl::RGBA,
|
external: gl::RGBA,
|
||||||
pixel_type: gl::FLOAT,
|
pixel_type: gl::FLOAT,
|
||||||
},
|
},
|
||||||
|
ImageFormat::RGBAI32 => FormatDesc {
|
||||||
|
internal: gl::RGBA32I as _,
|
||||||
|
external: gl::RGBA_INTEGER,
|
||||||
|
pixel_type: gl::INT,
|
||||||
|
},
|
||||||
ImageFormat::RG8 => FormatDesc {
|
ImageFormat::RG8 => FormatDesc {
|
||||||
internal: gl::RG8 as _,
|
internal: gl::RG8 as _,
|
||||||
external: gl::RG,
|
external: gl::RG,
|
||||||
|
@ -2360,6 +2365,7 @@ impl<'a> UploadTarget<'a> {
|
||||||
ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE),
|
ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE),
|
||||||
ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
|
ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
|
||||||
ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
|
ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
|
||||||
|
ImageFormat::RGBAI32 => (gl::RGBA_INTEGER, 16, gl::INT),
|
||||||
};
|
};
|
||||||
|
|
||||||
let row_length = match chunk.stride {
|
let row_length = match chunk.stride {
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
mod gl;
|
||||||
|
|
||||||
|
pub use self::gl::*;
|
|
@ -14,10 +14,10 @@ use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, S
|
||||||
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
|
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
|
||||||
use api::{TransformStyle, YuvColorSpace, YuvData};
|
use api::{TransformStyle, YuvColorSpace, YuvData};
|
||||||
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
|
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
|
||||||
use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo};
|
use clip_scroll_node::{NodeType, SpatialNodeKind, StickyFrameInfo};
|
||||||
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
|
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
|
||||||
use euclid::{SideOffsets2D, vec2};
|
use euclid::vec2;
|
||||||
use frame_builder::{FrameBuilder, FrameBuilderConfig};
|
use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
|
||||||
use glyph_rasterizer::FontInstance;
|
use glyph_rasterizer::FontInstance;
|
||||||
use gpu_cache::GpuCacheHandle;
|
use gpu_cache::GpuCacheHandle;
|
||||||
use gpu_types::BrushFlags;
|
use gpu_types::BrushFlags;
|
||||||
|
@ -628,8 +628,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
SpecificDisplayItem::Gradient(ref info) => {
|
SpecificDisplayItem::Gradient(ref info) => {
|
||||||
self.add_gradient(
|
let brush_kind = self.create_brush_kind_for_gradient(
|
||||||
clip_and_scroll,
|
|
||||||
&prim_info,
|
&prim_info,
|
||||||
info.gradient.start_point,
|
info.gradient.start_point,
|
||||||
info.gradient.end_point,
|
info.gradient.end_point,
|
||||||
|
@ -638,10 +637,11 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
info.tile_size,
|
info.tile_size,
|
||||||
info.tile_spacing,
|
info.tile_spacing,
|
||||||
);
|
);
|
||||||
|
let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None));
|
||||||
|
self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim);
|
||||||
}
|
}
|
||||||
SpecificDisplayItem::RadialGradient(ref info) => {
|
SpecificDisplayItem::RadialGradient(ref info) => {
|
||||||
self.add_radial_gradient(
|
let brush_kind = self.create_brush_kind_for_radial_gradient(
|
||||||
clip_and_scroll,
|
|
||||||
&prim_info,
|
&prim_info,
|
||||||
info.gradient.center,
|
info.gradient.center,
|
||||||
info.gradient.start_offset * info.gradient.radius.width,
|
info.gradient.start_offset * info.gradient.radius.width,
|
||||||
|
@ -652,6 +652,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
info.tile_size,
|
info.tile_size,
|
||||||
info.tile_spacing,
|
info.tile_spacing,
|
||||||
);
|
);
|
||||||
|
let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None));
|
||||||
|
self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim);
|
||||||
}
|
}
|
||||||
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
|
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
|
||||||
let bounds = box_shadow_info
|
let bounds = box_shadow_info
|
||||||
|
@ -875,6 +877,10 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
|
|
||||||
if container.is_visible() {
|
if container.is_visible() {
|
||||||
let prim_index = self.create_primitive(info, clip_sources, container);
|
let prim_index = self.create_primitive(info, clip_sources, container);
|
||||||
|
if cfg!(debug_assertions) && ChasePrimitive::LocalRect(info.rect) == self.config.chase_primitive {
|
||||||
|
println!("Chasing {:?}", prim_index);
|
||||||
|
self.prim_store.chase_id = Some(prim_index);
|
||||||
|
}
|
||||||
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
|
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
|
||||||
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
|
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
|
||||||
}
|
}
|
||||||
|
@ -1197,14 +1203,15 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
origin_in_parent_reference_frame: LayoutVector2D,
|
origin_in_parent_reference_frame: LayoutVector2D,
|
||||||
) -> ClipScrollNodeIndex {
|
) -> ClipScrollNodeIndex {
|
||||||
let index = self.id_to_index_mapper.get_node_index(reference_frame_id);
|
let index = self.id_to_index_mapper.get_node_index(reference_frame_id);
|
||||||
let node = ClipScrollNode::new_reference_frame(
|
let parent_index = parent_id.map(|id| self.id_to_index_mapper.get_node_index(id));
|
||||||
parent_id.map(|id| self.id_to_index_mapper.get_node_index(id)),
|
self.clip_scroll_tree.add_reference_frame(
|
||||||
|
index,
|
||||||
|
parent_index,
|
||||||
source_transform,
|
source_transform,
|
||||||
source_perspective,
|
source_perspective,
|
||||||
origin_in_parent_reference_frame,
|
origin_in_parent_reference_frame,
|
||||||
pipeline_id,
|
pipeline_id,
|
||||||
);
|
);
|
||||||
self.clip_scroll_tree.add_node(node, index);
|
|
||||||
self.reference_frame_stack.push((reference_frame_id, index));
|
self.reference_frame_stack.push((reference_frame_id, index));
|
||||||
|
|
||||||
match parent_id {
|
match parent_id {
|
||||||
|
@ -1227,7 +1234,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round();
|
let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round();
|
||||||
let root_id = self.clip_scroll_tree.root_reference_frame_index();
|
let root_id = self.clip_scroll_tree.root_reference_frame_index();
|
||||||
let root_node = &mut self.clip_scroll_tree.nodes[root_id.0];
|
let root_node = &mut self.clip_scroll_tree.nodes[root_id.0];
|
||||||
if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type {
|
if let NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(ref mut info), .. } = root_node.node_type {
|
||||||
info.resolved_transform =
|
info.resolved_transform =
|
||||||
LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into();
|
LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into();
|
||||||
}
|
}
|
||||||
|
@ -1290,16 +1297,15 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
scroll_sensitivity: ScrollSensitivity,
|
scroll_sensitivity: ScrollSensitivity,
|
||||||
) -> ClipScrollNodeIndex {
|
) -> ClipScrollNodeIndex {
|
||||||
let node_index = self.id_to_index_mapper.get_node_index(new_node_id);
|
let node_index = self.id_to_index_mapper.get_node_index(new_node_id);
|
||||||
let node = ClipScrollNode::new_scroll_frame(
|
self.clip_scroll_tree.add_scroll_frame(
|
||||||
pipeline_id,
|
node_index,
|
||||||
self.id_to_index_mapper.get_node_index(parent_id),
|
self.id_to_index_mapper.get_node_index(parent_id),
|
||||||
external_id,
|
external_id,
|
||||||
|
pipeline_id,
|
||||||
frame_rect,
|
frame_rect,
|
||||||
content_size,
|
content_size,
|
||||||
scroll_sensitivity,
|
scroll_sensitivity,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.clip_scroll_tree.add_node(node, node_index);
|
|
||||||
self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
|
self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
|
||||||
node_index
|
node_index
|
||||||
}
|
}
|
||||||
|
@ -1492,51 +1498,6 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
gradient_stops: ItemRange<GradientStop>,
|
gradient_stops: ItemRange<GradientStop>,
|
||||||
) {
|
) {
|
||||||
let rect = info.rect;
|
let rect = info.rect;
|
||||||
let create_segments = |outset: SideOffsets2D<f32>| {
|
|
||||||
// Calculate the modified rect as specific by border-image-outset
|
|
||||||
let origin = LayoutPoint::new(rect.origin.x - outset.left, rect.origin.y - outset.top);
|
|
||||||
let size = LayoutSize::new(
|
|
||||||
rect.size.width + outset.left + outset.right,
|
|
||||||
rect.size.height + outset.top + outset.bottom,
|
|
||||||
);
|
|
||||||
let rect = LayoutRect::new(origin, size);
|
|
||||||
|
|
||||||
let tl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y);
|
|
||||||
let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
|
|
||||||
|
|
||||||
let tr_outer = LayoutPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
|
|
||||||
let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
|
|
||||||
|
|
||||||
let bl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
|
|
||||||
let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
|
|
||||||
|
|
||||||
let br_outer = LayoutPoint::new(
|
|
||||||
rect.origin.x + rect.size.width,
|
|
||||||
rect.origin.y + rect.size.height,
|
|
||||||
);
|
|
||||||
let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
|
|
||||||
|
|
||||||
// Build the list of gradient segments
|
|
||||||
vec![
|
|
||||||
// Top left
|
|
||||||
LayoutRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
|
|
||||||
// Top right
|
|
||||||
LayoutRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
|
|
||||||
// Bottom right
|
|
||||||
LayoutRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
|
|
||||||
// Bottom left
|
|
||||||
LayoutRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
|
|
||||||
// Top
|
|
||||||
LayoutRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
|
|
||||||
// Bottom
|
|
||||||
LayoutRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
|
|
||||||
// Left
|
|
||||||
LayoutRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
|
|
||||||
// Right
|
|
||||||
LayoutRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
match border_item.details {
|
match border_item.details {
|
||||||
BorderDetails::NinePatch(ref border) => {
|
BorderDetails::NinePatch(ref border) => {
|
||||||
// Calculate the modified rect as specific by border-image-outset
|
// Calculate the modified rect as specific by border-image-outset
|
||||||
|
@ -1701,70 +1662,55 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
clip_mask_kind: BrushClipMaskKind::Unknown,
|
clip_mask_kind: BrushClipMaskKind::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
let prim = PrimitiveContainer::Brush(match border.source {
|
let brush_kind = match border.source {
|
||||||
NinePatchBorderSource::Image(image_key) => {
|
NinePatchBorderSource::Image(image_key) => {
|
||||||
let source = BorderSource::Image(ImageRequest {
|
BrushKind::Border {
|
||||||
key: image_key,
|
source: BorderSource::Image(ImageRequest {
|
||||||
rendering: ImageRendering::Auto,
|
key: image_key,
|
||||||
tile: None,
|
rendering: ImageRendering::Auto,
|
||||||
});
|
tile: None,
|
||||||
|
})
|
||||||
BrushPrimitive::new(
|
}
|
||||||
BrushKind::Border {
|
}
|
||||||
source
|
NinePatchBorderSource::Gradient(gradient) => {
|
||||||
},
|
self.create_brush_kind_for_gradient(
|
||||||
Some(descriptor),
|
&info,
|
||||||
|
gradient.start_point,
|
||||||
|
gradient.end_point,
|
||||||
|
gradient_stops,
|
||||||
|
gradient.extend_mode,
|
||||||
|
LayoutSize::new(border.height as f32, border.width as f32),
|
||||||
|
LayoutSize::zero(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
});
|
NinePatchBorderSource::RadialGradient(gradient) => {
|
||||||
|
self.create_brush_kind_for_radial_gradient(
|
||||||
|
&info,
|
||||||
|
gradient.center,
|
||||||
|
gradient.start_offset * gradient.radius.width,
|
||||||
|
gradient.end_offset * gradient.radius.width,
|
||||||
|
gradient.radius.width / gradient.radius.height,
|
||||||
|
gradient_stops,
|
||||||
|
gradient.extend_mode,
|
||||||
|
LayoutSize::new(border.height as f32, border.width as f32),
|
||||||
|
LayoutSize::zero(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let prim = PrimitiveContainer::Brush(
|
||||||
|
BrushPrimitive::new(brush_kind, Some(descriptor))
|
||||||
|
);
|
||||||
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
|
self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
|
||||||
}
|
}
|
||||||
BorderDetails::Normal(ref border) => {
|
BorderDetails::Normal(ref border) => {
|
||||||
self.add_normal_border(info, border, &border_item.widths, clip_and_scroll);
|
self.add_normal_border(info, border, &border_item.widths, clip_and_scroll);
|
||||||
}
|
}
|
||||||
BorderDetails::Gradient(ref border) => for segment in create_segments(border.outset) {
|
|
||||||
let segment_rel = segment.origin - rect.origin;
|
|
||||||
let mut info = info.clone();
|
|
||||||
info.rect = segment;
|
|
||||||
|
|
||||||
self.add_gradient(
|
|
||||||
clip_and_scroll,
|
|
||||||
&info,
|
|
||||||
border.gradient.start_point - segment_rel,
|
|
||||||
border.gradient.end_point - segment_rel,
|
|
||||||
gradient_stops,
|
|
||||||
border.gradient.extend_mode,
|
|
||||||
segment.size,
|
|
||||||
LayoutSize::zero(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
BorderDetails::RadialGradient(ref border) => {
|
|
||||||
for segment in create_segments(border.outset) {
|
|
||||||
let segment_rel = segment.origin - rect.origin;
|
|
||||||
let mut info = info.clone();
|
|
||||||
info.rect = segment;
|
|
||||||
|
|
||||||
self.add_radial_gradient(
|
|
||||||
clip_and_scroll,
|
|
||||||
&info,
|
|
||||||
border.gradient.center - segment_rel,
|
|
||||||
border.gradient.start_offset * border.gradient.radius.width,
|
|
||||||
border.gradient.end_offset * border.gradient.radius.width,
|
|
||||||
border.gradient.radius.width / border.gradient.radius.height,
|
|
||||||
gradient_stops,
|
|
||||||
border.gradient.extend_mode,
|
|
||||||
segment.size,
|
|
||||||
LayoutSize::zero(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_gradient(
|
pub fn create_brush_kind_for_gradient(
|
||||||
&mut self,
|
&mut self,
|
||||||
clip_and_scroll: ScrollNodeAndClipChain,
|
|
||||||
info: &LayoutPrimitiveInfo,
|
info: &LayoutPrimitiveInfo,
|
||||||
start_point: LayoutPoint,
|
start_point: LayoutPoint,
|
||||||
end_point: LayoutPoint,
|
end_point: LayoutPoint,
|
||||||
|
@ -1772,13 +1718,9 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
extend_mode: ExtendMode,
|
extend_mode: ExtendMode,
|
||||||
stretch_size: LayoutSize,
|
stretch_size: LayoutSize,
|
||||||
mut tile_spacing: LayoutSize,
|
mut tile_spacing: LayoutSize,
|
||||||
) {
|
) -> BrushKind {
|
||||||
let mut prim_rect = info.rect;
|
let mut prim_rect = info.rect;
|
||||||
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
|
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
|
||||||
let info = LayoutPrimitiveInfo {
|
|
||||||
rect: prim_rect,
|
|
||||||
.. *info
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
|
// Try to ensure that if the gradient is specified in reverse, then so long as the stops
|
||||||
// are also supplied in reverse that the rendered result will be equivalent. To do this,
|
// are also supplied in reverse that the rendered result will be equivalent. To do this,
|
||||||
|
@ -1798,29 +1740,21 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
(start_point, end_point)
|
(start_point, end_point)
|
||||||
};
|
};
|
||||||
|
|
||||||
let prim = BrushPrimitive::new(
|
BrushKind::LinearGradient {
|
||||||
BrushKind::LinearGradient {
|
stops_range: stops,
|
||||||
stops_range: stops,
|
extend_mode,
|
||||||
extend_mode,
|
reverse_stops,
|
||||||
reverse_stops,
|
start_point: sp,
|
||||||
start_point: sp,
|
end_point: ep,
|
||||||
end_point: ep,
|
stops_handle: GpuCacheHandle::new(),
|
||||||
stops_handle: GpuCacheHandle::new(),
|
stretch_size,
|
||||||
stretch_size,
|
tile_spacing,
|
||||||
tile_spacing,
|
visible_tiles: Vec::new(),
|
||||||
visible_tiles: Vec::new(),
|
}
|
||||||
},
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
let prim = PrimitiveContainer::Brush(prim);
|
|
||||||
|
|
||||||
self.add_primitive(clip_and_scroll, &info, Vec::new(), prim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_radial_gradient(
|
pub fn create_brush_kind_for_radial_gradient(
|
||||||
&mut self,
|
&mut self,
|
||||||
clip_and_scroll: ScrollNodeAndClipChain,
|
|
||||||
info: &LayoutPrimitiveInfo,
|
info: &LayoutPrimitiveInfo,
|
||||||
center: LayoutPoint,
|
center: LayoutPoint,
|
||||||
start_radius: f32,
|
start_radius: f32,
|
||||||
|
@ -1830,36 +1764,22 @@ impl<'a> DisplayListFlattener<'a> {
|
||||||
extend_mode: ExtendMode,
|
extend_mode: ExtendMode,
|
||||||
stretch_size: LayoutSize,
|
stretch_size: LayoutSize,
|
||||||
mut tile_spacing: LayoutSize,
|
mut tile_spacing: LayoutSize,
|
||||||
) {
|
) -> BrushKind {
|
||||||
let mut prim_rect = info.rect;
|
let mut prim_rect = info.rect;
|
||||||
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
|
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
|
||||||
let info = LayoutPrimitiveInfo {
|
|
||||||
rect: prim_rect,
|
|
||||||
.. *info
|
|
||||||
};
|
|
||||||
|
|
||||||
let prim = BrushPrimitive::new(
|
BrushKind::RadialGradient {
|
||||||
BrushKind::RadialGradient {
|
stops_range: stops,
|
||||||
stops_range: stops,
|
extend_mode,
|
||||||
extend_mode,
|
center,
|
||||||
center,
|
start_radius,
|
||||||
start_radius,
|
end_radius,
|
||||||
end_radius,
|
ratio_xy,
|
||||||
ratio_xy,
|
stops_handle: GpuCacheHandle::new(),
|
||||||
stops_handle: GpuCacheHandle::new(),
|
stretch_size,
|
||||||
stretch_size,
|
tile_spacing,
|
||||||
tile_spacing,
|
visible_tiles: Vec::new(),
|
||||||
visible_tiles: Vec::new(),
|
}
|
||||||
},
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.add_primitive(
|
|
||||||
clip_and_scroll,
|
|
||||||
&info,
|
|
||||||
Vec::new(),
|
|
||||||
PrimitiveContainer::Brush(prim),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_text(
|
pub fn add_text(
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
use api::{BuiltDisplayList, ColorF, DeviceIntPoint, DeviceIntRect, DevicePixelScale};
|
use api::{BuiltDisplayList, ColorF, DeviceIntPoint, DeviceIntRect, DevicePixelScale};
|
||||||
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode};
|
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode};
|
||||||
use api::{LayoutRect, LayoutSize, PipelineId, WorldPoint};
|
use api::{LayoutPoint, LayoutRect, LayoutSize, PipelineId, WorldPoint};
|
||||||
use clip::{ClipChain, ClipStore};
|
use clip::{ClipChain, ClipStore};
|
||||||
use clip_scroll_node::{ClipScrollNode};
|
use clip_scroll_node::{ClipScrollNode};
|
||||||
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
|
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
|
||||||
use display_list_flattener::{DisplayListFlattener};
|
use display_list_flattener::{DisplayListFlattener};
|
||||||
use gpu_cache::GpuCache;
|
use gpu_cache::GpuCache;
|
||||||
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, UvRectKind};
|
use gpu_types::{PrimitiveHeaders, TransformData, UvRectKind};
|
||||||
use hit_test::{HitTester, HitTestingRun};
|
use hit_test::{HitTester, HitTestingRun};
|
||||||
use internal_types::{FastHashMap};
|
use internal_types::{FastHashMap};
|
||||||
use picture::PictureSurface;
|
use picture::PictureSurface;
|
||||||
|
@ -24,7 +24,22 @@ use std::{mem, f32};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
|
use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
|
||||||
use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
|
use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
|
||||||
use util::{self, MaxRect, WorldToLayoutFastTransform};
|
use util::{self, WorldToLayoutFastTransform};
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub enum ChasePrimitive {
|
||||||
|
Nothing,
|
||||||
|
LocalRect(LayoutRect),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ChasePrimitive {
|
||||||
|
fn default() -> Self {
|
||||||
|
ChasePrimitive::Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
@ -34,6 +49,7 @@ pub struct FrameBuilderConfig {
|
||||||
pub default_font_render_mode: FontRenderMode,
|
pub default_font_render_mode: FontRenderMode,
|
||||||
pub dual_source_blending_is_supported: bool,
|
pub dual_source_blending_is_supported: bool,
|
||||||
pub dual_source_blending_is_enabled: bool,
|
pub dual_source_blending_is_enabled: bool,
|
||||||
|
pub chase_primitive: ChasePrimitive,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder structure for `tiling::Frame`
|
/// A builder structure for `tiling::Frame`
|
||||||
|
@ -56,14 +72,14 @@ pub struct FrameBuildingContext<'a> {
|
||||||
pub pipelines: &'a FastHashMap<PipelineId, Arc<ScenePipeline>>,
|
pub pipelines: &'a FastHashMap<PipelineId, Arc<ScenePipeline>>,
|
||||||
pub screen_rect: DeviceIntRect,
|
pub screen_rect: DeviceIntRect,
|
||||||
pub clip_scroll_tree: &'a ClipScrollTree,
|
pub clip_scroll_tree: &'a ClipScrollTree,
|
||||||
pub node_data: &'a [ClipScrollNodeData],
|
pub transforms: &'a [TransformData],
|
||||||
|
pub max_local_clip: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FrameBuildingState<'a> {
|
pub struct FrameBuildingState<'a> {
|
||||||
pub render_tasks: &'a mut RenderTaskTree,
|
pub render_tasks: &'a mut RenderTaskTree,
|
||||||
pub profile_counters: &'a mut FrameProfileCounters,
|
pub profile_counters: &'a mut FrameProfileCounters,
|
||||||
pub clip_store: &'a mut ClipStore,
|
pub clip_store: &'a mut ClipStore,
|
||||||
pub local_clip_rects: &'a mut Vec<LayoutRect>,
|
|
||||||
pub resource_cache: &'a mut ResourceCache,
|
pub resource_cache: &'a mut ResourceCache,
|
||||||
pub gpu_cache: &'a mut GpuCache,
|
pub gpu_cache: &'a mut GpuCache,
|
||||||
pub special_render_passes: &'a mut SpecialRenderPasses,
|
pub special_render_passes: &'a mut SpecialRenderPasses,
|
||||||
|
@ -99,19 +115,19 @@ impl PictureState {
|
||||||
pub struct PrimitiveRunContext<'a> {
|
pub struct PrimitiveRunContext<'a> {
|
||||||
pub clip_chain: &'a ClipChain,
|
pub clip_chain: &'a ClipChain,
|
||||||
pub scroll_node: &'a ClipScrollNode,
|
pub scroll_node: &'a ClipScrollNode,
|
||||||
pub clip_chain_rect_index: ClipChainRectIndex,
|
pub local_clip_rect: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PrimitiveRunContext<'a> {
|
impl<'a> PrimitiveRunContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
clip_chain: &'a ClipChain,
|
clip_chain: &'a ClipChain,
|
||||||
scroll_node: &'a ClipScrollNode,
|
scroll_node: &'a ClipScrollNode,
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
local_clip_rect: LayoutRect,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
PrimitiveRunContext {
|
PrimitiveRunContext {
|
||||||
clip_chain,
|
clip_chain,
|
||||||
scroll_node,
|
scroll_node,
|
||||||
clip_chain_rect_index,
|
local_clip_rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +148,7 @@ impl FrameBuilder {
|
||||||
default_font_render_mode: FontRenderMode::Mono,
|
default_font_render_mode: FontRenderMode::Mono,
|
||||||
dual_source_blending_is_enabled: true,
|
dual_source_blending_is_enabled: true,
|
||||||
dual_source_blending_is_supported: false,
|
dual_source_blending_is_supported: false,
|
||||||
|
chase_primitive: ChasePrimitive::Nothing,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,8 +186,7 @@ impl FrameBuilder {
|
||||||
profile_counters: &mut FrameProfileCounters,
|
profile_counters: &mut FrameProfileCounters,
|
||||||
device_pixel_scale: DevicePixelScale,
|
device_pixel_scale: DevicePixelScale,
|
||||||
scene_properties: &SceneProperties,
|
scene_properties: &SceneProperties,
|
||||||
local_clip_rects: &mut Vec<LayoutRect>,
|
transforms: &[TransformData],
|
||||||
node_data: &[ClipScrollNodeData],
|
|
||||||
) -> Option<RenderTaskId> {
|
) -> Option<RenderTaskId> {
|
||||||
profile_scope!("cull");
|
profile_scope!("cull");
|
||||||
|
|
||||||
|
@ -187,6 +203,8 @@ impl FrameBuilder {
|
||||||
.expect("No display list?")
|
.expect("No display list?")
|
||||||
.display_list;
|
.display_list;
|
||||||
|
|
||||||
|
const MAX_CLIP_COORD: f32 = 1.0e9;
|
||||||
|
|
||||||
let frame_context = FrameBuildingContext {
|
let frame_context = FrameBuildingContext {
|
||||||
scene_id: self.scene_id,
|
scene_id: self.scene_id,
|
||||||
device_pixel_scale,
|
device_pixel_scale,
|
||||||
|
@ -194,14 +212,17 @@ impl FrameBuilder {
|
||||||
pipelines,
|
pipelines,
|
||||||
screen_rect: self.screen_rect.to_i32(),
|
screen_rect: self.screen_rect.to_i32(),
|
||||||
clip_scroll_tree,
|
clip_scroll_tree,
|
||||||
node_data,
|
transforms,
|
||||||
|
max_local_clip: LayoutRect::new(
|
||||||
|
LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
|
||||||
|
LayoutSize::new(2.0 * MAX_CLIP_COORD, 2.0 * MAX_CLIP_COORD),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut frame_state = FrameBuildingState {
|
let mut frame_state = FrameBuildingState {
|
||||||
render_tasks,
|
render_tasks,
|
||||||
profile_counters,
|
profile_counters,
|
||||||
clip_store: &mut self.clip_store,
|
clip_store: &mut self.clip_store,
|
||||||
local_clip_rects,
|
|
||||||
resource_cache,
|
resource_cache,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
special_render_passes,
|
special_render_passes,
|
||||||
|
@ -301,20 +322,13 @@ impl FrameBuilder {
|
||||||
resource_cache.begin_frame(frame_id);
|
resource_cache.begin_frame(frame_id);
|
||||||
gpu_cache.begin_frame();
|
gpu_cache.begin_frame();
|
||||||
|
|
||||||
let mut node_data = Vec::with_capacity(clip_scroll_tree.nodes.len());
|
let transform_palette = clip_scroll_tree.update_tree(
|
||||||
let total_prim_runs =
|
|
||||||
self.prim_store.pictures.iter().fold(1, |count, pic| count + pic.runs.len());
|
|
||||||
let mut clip_chain_local_clip_rects = Vec::with_capacity(total_prim_runs);
|
|
||||||
clip_chain_local_clip_rects.push(LayoutRect::max_rect());
|
|
||||||
|
|
||||||
clip_scroll_tree.update_tree(
|
|
||||||
&self.screen_rect.to_i32(),
|
&self.screen_rect.to_i32(),
|
||||||
device_pixel_scale,
|
device_pixel_scale,
|
||||||
&mut self.clip_store,
|
&mut self.clip_store,
|
||||||
resource_cache,
|
resource_cache,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
pan,
|
pan,
|
||||||
&mut node_data,
|
|
||||||
scene_properties,
|
scene_properties,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -335,8 +349,7 @@ impl FrameBuilder {
|
||||||
&mut profile_counters,
|
&mut profile_counters,
|
||||||
device_pixel_scale,
|
device_pixel_scale,
|
||||||
scene_properties,
|
scene_properties,
|
||||||
&mut clip_chain_local_clip_rects,
|
&transform_palette.transforms,
|
||||||
&node_data,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
resource_cache.block_until_all_resources_added(gpu_cache,
|
resource_cache.block_until_all_resources_added(gpu_cache,
|
||||||
|
@ -369,6 +382,7 @@ impl FrameBuilder {
|
||||||
|
|
||||||
let mut deferred_resolves = vec![];
|
let mut deferred_resolves = vec![];
|
||||||
let mut has_texture_cache_tasks = false;
|
let mut has_texture_cache_tasks = false;
|
||||||
|
let mut prim_headers = PrimitiveHeaders::new();
|
||||||
let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
|
let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
|
||||||
self.config.dual_source_blending_is_supported;
|
self.config.dual_source_blending_is_supported;
|
||||||
|
|
||||||
|
@ -379,7 +393,7 @@ impl FrameBuilder {
|
||||||
resource_cache,
|
resource_cache,
|
||||||
clip_scroll_tree,
|
clip_scroll_tree,
|
||||||
use_dual_source_blending,
|
use_dual_source_blending,
|
||||||
node_data: &node_data,
|
transforms: &transform_palette,
|
||||||
};
|
};
|
||||||
|
|
||||||
pass.build(
|
pass.build(
|
||||||
|
@ -388,6 +402,7 @@ impl FrameBuilder {
|
||||||
&mut render_tasks,
|
&mut render_tasks,
|
||||||
&mut deferred_resolves,
|
&mut deferred_resolves,
|
||||||
&self.clip_store,
|
&self.clip_store,
|
||||||
|
&mut prim_headers,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind {
|
if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind {
|
||||||
|
@ -409,13 +424,13 @@ impl FrameBuilder {
|
||||||
layer,
|
layer,
|
||||||
profile_counters,
|
profile_counters,
|
||||||
passes,
|
passes,
|
||||||
node_data,
|
transform_palette: transform_palette.transforms,
|
||||||
clip_chain_local_clip_rects,
|
|
||||||
render_tasks,
|
render_tasks,
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
gpu_cache_frame_id,
|
gpu_cache_frame_id,
|
||||||
has_been_rendered: false,
|
has_been_rendered: false,
|
||||||
has_texture_cache_tasks,
|
has_texture_cache_tasks,
|
||||||
|
prim_headers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,25 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use api::{DevicePoint, DeviceSize, DeviceRect, LayoutToWorldTransform};
|
use api::{DevicePoint, DeviceSize, DeviceRect, LayoutRect, LayoutToWorldTransform};
|
||||||
use api::{PremultipliedColorF, WorldToLayoutTransform};
|
use api::{PremultipliedColorF, WorldToLayoutTransform};
|
||||||
|
use clip_scroll_tree::TransformIndex;
|
||||||
use gpu_cache::{GpuCacheAddress, GpuDataRequest};
|
use gpu_cache::{GpuCacheAddress, GpuDataRequest};
|
||||||
use prim_store::{VECS_PER_SEGMENT, EdgeAaSegmentMask};
|
use prim_store::{EdgeAaSegmentMask};
|
||||||
use render_task::RenderTaskAddress;
|
use render_task::RenderTaskAddress;
|
||||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
use util::{MatrixHelpers, TransformedRectKind};
|
||||||
|
|
||||||
// Contains type that must exactly match the same structures declared in GLSL.
|
// Contains type that must exactly match the same structures declared in GLSL.
|
||||||
|
|
||||||
const INT_BITS: usize = 31; //TODO: convert to unsigned
|
|
||||||
const CLIP_CHAIN_RECT_BITS: usize = 22;
|
|
||||||
const SEGMENT_BITS: usize = INT_BITS - CLIP_CHAIN_RECT_BITS;
|
|
||||||
// The guard ensures (at compile time) that the designated number of bits cover
|
|
||||||
// the maximum supported segment count for the texture width.
|
|
||||||
const _SEGMENT_GUARD: usize = (1 << SEGMENT_BITS) * VECS_PER_SEGMENT - MAX_VERTEX_TEXTURE_WIDTH;
|
|
||||||
const EDGE_FLAG_BITS: usize = 4;
|
|
||||||
const BRUSH_FLAG_BITS: usize = 4;
|
|
||||||
const CLIP_SCROLL_INDEX_BITS: usize = INT_BITS - EDGE_FLAG_BITS - BRUSH_FLAG_BITS;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct ZBufferId(i32);
|
pub struct ZBufferId(i32);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
pub struct ZBufferIdGenerator {
|
pub struct ZBufferIdGenerator {
|
||||||
next: i32,
|
next: i32,
|
||||||
}
|
}
|
||||||
|
@ -119,7 +115,7 @@ pub struct BorderInstance {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ClipMaskInstance {
|
pub struct ClipMaskInstance {
|
||||||
pub render_task_address: RenderTaskAddress,
|
pub render_task_address: RenderTaskAddress,
|
||||||
pub scroll_node_data_index: ClipScrollNodeIndex,
|
pub transform_id: TransformPaletteId,
|
||||||
pub segment: i32,
|
pub segment: i32,
|
||||||
pub clip_data_address: GpuCacheAddress,
|
pub clip_data_address: GpuCacheAddress,
|
||||||
pub resource_address: GpuCacheAddress,
|
pub resource_address: GpuCacheAddress,
|
||||||
|
@ -135,50 +131,124 @@ pub struct ClipMaskBorderCornerDotDash {
|
||||||
pub dot_dash_data: [f32; 8],
|
pub dot_dash_data: [f32; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
// 32 bytes per instance should be enough for anyone!
|
// 16 bytes per instance should be enough for anyone!
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[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 struct PrimitiveInstance {
|
pub struct PrimitiveInstance {
|
||||||
data: [i32; 8],
|
data: [i32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct PrimitiveHeaderIndex(pub i32);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct PrimitiveHeaders {
|
||||||
|
// The integer-type headers for a primitive.
|
||||||
|
pub headers_int: Vec<PrimitiveHeaderI>,
|
||||||
|
// The float-type headers for a primitive.
|
||||||
|
pub headers_float: Vec<PrimitiveHeaderF>,
|
||||||
|
// Used to generated a unique z-buffer value per primitive.
|
||||||
|
pub z_generator: ZBufferIdGenerator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrimitiveHeaders {
|
||||||
|
pub fn new() -> PrimitiveHeaders {
|
||||||
|
PrimitiveHeaders {
|
||||||
|
headers_int: Vec::new(),
|
||||||
|
headers_float: Vec::new(),
|
||||||
|
z_generator: ZBufferIdGenerator::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new primitive header.
|
||||||
|
pub fn push(
|
||||||
|
&mut self,
|
||||||
|
prim_header: &PrimitiveHeader,
|
||||||
|
user_data: [i32; 3],
|
||||||
|
) -> PrimitiveHeaderIndex {
|
||||||
|
debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
|
||||||
|
let id = self.headers_float.len();
|
||||||
|
|
||||||
|
self.headers_float.push(PrimitiveHeaderF {
|
||||||
|
local_rect: prim_header.local_rect,
|
||||||
|
local_clip_rect: prim_header.local_clip_rect,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.headers_int.push(PrimitiveHeaderI {
|
||||||
|
z: self.z_generator.next(),
|
||||||
|
task_address: prim_header.task_address,
|
||||||
|
specific_prim_address: prim_header.specific_prim_address.as_int(),
|
||||||
|
clip_task_address: prim_header.clip_task_address,
|
||||||
|
transform_id: prim_header.transform_id,
|
||||||
|
user_data,
|
||||||
|
});
|
||||||
|
|
||||||
|
PrimitiveHeaderIndex(id as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a convenience type used to make it easier to pass
|
||||||
|
// the common parts around during batching.
|
||||||
|
pub struct PrimitiveHeader {
|
||||||
|
pub local_rect: LayoutRect,
|
||||||
|
pub local_clip_rect: LayoutRect,
|
||||||
|
pub task_address: RenderTaskAddress,
|
||||||
|
pub specific_prim_address: GpuCacheAddress,
|
||||||
|
pub clip_task_address: RenderTaskAddress,
|
||||||
|
pub transform_id: TransformPaletteId,
|
||||||
|
}
|
||||||
|
|
||||||
|
// f32 parts of a primitive header
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct PrimitiveHeaderF {
|
||||||
|
pub local_rect: LayoutRect,
|
||||||
|
pub local_clip_rect: LayoutRect,
|
||||||
|
}
|
||||||
|
|
||||||
|
// i32 parts of a primitive header
|
||||||
|
// TODO(gw): Compress parts of these down to u16
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
|
pub struct PrimitiveHeaderI {
|
||||||
|
pub z: ZBufferId,
|
||||||
|
pub task_address: RenderTaskAddress,
|
||||||
|
pub specific_prim_address: i32,
|
||||||
|
pub clip_task_address: RenderTaskAddress,
|
||||||
|
pub transform_id: TransformPaletteId,
|
||||||
|
pub user_data: [i32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlyphInstance {
|
pub struct GlyphInstance {
|
||||||
pub specific_prim_address: GpuCacheAddress,
|
pub prim_header_index: PrimitiveHeaderIndex,
|
||||||
pub task_address: RenderTaskAddress,
|
|
||||||
pub clip_task_address: RenderTaskAddress,
|
|
||||||
pub clip_chain_rect_index: ClipChainRectIndex,
|
|
||||||
pub scroll_id: ClipScrollNodeIndex,
|
|
||||||
pub z: ZBufferId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlyphInstance {
|
impl GlyphInstance {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
specific_prim_address: GpuCacheAddress,
|
prim_header_index: PrimitiveHeaderIndex,
|
||||||
task_address: RenderTaskAddress,
|
|
||||||
clip_task_address: RenderTaskAddress,
|
|
||||||
clip_chain_rect_index: ClipChainRectIndex,
|
|
||||||
scroll_id: ClipScrollNodeIndex,
|
|
||||||
z: ZBufferId,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
GlyphInstance {
|
GlyphInstance {
|
||||||
specific_prim_address,
|
prim_header_index,
|
||||||
task_address,
|
|
||||||
clip_task_address,
|
|
||||||
clip_chain_rect_index,
|
|
||||||
scroll_id,
|
|
||||||
z,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(gw): Some of these fields can be moved to the primitive
|
||||||
|
// header since they are constant, and some can be
|
||||||
|
// compressed to a smaller size.
|
||||||
pub fn build(&self, data0: i32, data1: i32, data2: i32) -> PrimitiveInstance {
|
pub fn build(&self, data0: i32, data1: i32, data2: i32) -> PrimitiveInstance {
|
||||||
PrimitiveInstance {
|
PrimitiveInstance {
|
||||||
data: [
|
data: [
|
||||||
self.specific_prim_address.as_int(),
|
self.prim_header_index.0 as i32,
|
||||||
self.task_address.0 as i32 | (self.clip_task_address.0 as i32) << 16,
|
|
||||||
self.clip_chain_rect_index.0 as i32,
|
|
||||||
self.scroll_id.0 as i32,
|
|
||||||
self.z.0,
|
|
||||||
data0,
|
data0,
|
||||||
data1,
|
data1,
|
||||||
data2,
|
data2,
|
||||||
|
@ -218,10 +288,6 @@ impl From<SplitCompositeInstance> for PrimitiveInstance {
|
||||||
instance.src_task_address.0 as i32,
|
instance.src_task_address.0 as i32,
|
||||||
instance.polygons_address.as_int(),
|
instance.polygons_address.as_int(),
|
||||||
instance.z.0,
|
instance.z.0,
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,80 +309,141 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gw): While we are converting things over, we
|
// TODO(gw): Some of these fields can be moved to the primitive
|
||||||
// need to have the instance be the same
|
// header since they are constant, and some can be
|
||||||
// size as an old PrimitiveInstance. In the
|
// compressed to a smaller size.
|
||||||
// future, we can compress this vertex
|
|
||||||
// format a lot - e.g. z, render task
|
|
||||||
// addresses etc can reasonably become
|
|
||||||
// a u16 type.
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct BrushInstance {
|
pub struct BrushInstance {
|
||||||
pub picture_address: RenderTaskAddress,
|
pub prim_header_index: PrimitiveHeaderIndex,
|
||||||
pub prim_address: GpuCacheAddress,
|
|
||||||
pub clip_chain_rect_index: ClipChainRectIndex,
|
|
||||||
pub scroll_id: ClipScrollNodeIndex,
|
|
||||||
pub clip_task_address: RenderTaskAddress,
|
pub clip_task_address: RenderTaskAddress,
|
||||||
pub z: ZBufferId,
|
|
||||||
pub segment_index: i32,
|
pub segment_index: i32,
|
||||||
pub edge_flags: EdgeAaSegmentMask,
|
pub edge_flags: EdgeAaSegmentMask,
|
||||||
pub brush_flags: BrushFlags,
|
pub brush_flags: BrushFlags,
|
||||||
pub user_data: [i32; 3],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BrushInstance> for PrimitiveInstance {
|
impl From<BrushInstance> for PrimitiveInstance {
|
||||||
fn from(instance: BrushInstance) -> Self {
|
fn from(instance: BrushInstance) -> Self {
|
||||||
debug_assert_eq!(0, instance.clip_chain_rect_index.0 >> CLIP_CHAIN_RECT_BITS);
|
|
||||||
debug_assert_eq!(0, instance.scroll_id.0 >> CLIP_SCROLL_INDEX_BITS);
|
|
||||||
debug_assert_eq!(0, instance.segment_index >> SEGMENT_BITS);
|
|
||||||
PrimitiveInstance {
|
PrimitiveInstance {
|
||||||
data: [
|
data: [
|
||||||
instance.picture_address.0 as i32 | (instance.clip_task_address.0 as i32) << 16,
|
instance.prim_header_index.0,
|
||||||
instance.prim_address.as_int(),
|
instance.clip_task_address.0 as i32,
|
||||||
instance.clip_chain_rect_index.0 as i32 | (instance.segment_index << CLIP_CHAIN_RECT_BITS),
|
instance.segment_index |
|
||||||
instance.z.0,
|
((instance.edge_flags.bits() as i32) << 16) |
|
||||||
instance.scroll_id.0 as i32 |
|
((instance.brush_flags.bits() as i32) << 24),
|
||||||
((instance.edge_flags.bits() as i32) << CLIP_SCROLL_INDEX_BITS) |
|
0,
|
||||||
((instance.brush_flags.bits() as i32) << (CLIP_SCROLL_INDEX_BITS + EDGE_FLAG_BITS)),
|
|
||||||
instance.user_data[0],
|
|
||||||
instance.user_data[1],
|
|
||||||
instance.user_data[2],
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Represents the information about a transform palette
|
||||||
|
// entry that is passed to shaders. It includes an index
|
||||||
|
// into the transform palette, and a set of flags. The
|
||||||
|
// only flag currently used determines whether the
|
||||||
|
// transform is axis-aligned (and this should have
|
||||||
|
// pixel snapping applied).
|
||||||
#[derive(Copy, Debug, Clone, PartialEq)]
|
#[derive(Copy, Debug, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ClipScrollNodeIndex(pub u32);
|
pub struct TransformPaletteId(pub u32);
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl TransformPaletteId {
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
// Get the palette ID for an identity transform.
|
||||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
pub fn identity() -> TransformPaletteId {
|
||||||
#[repr(C)]
|
TransformPaletteId(0)
|
||||||
pub struct ClipScrollNodeData {
|
}
|
||||||
pub transform: LayoutToWorldTransform,
|
|
||||||
pub inv_transform: WorldToLayoutTransform,
|
|
||||||
pub transform_kind: f32,
|
|
||||||
pub padding: [f32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ClipScrollNodeData {
|
// Extract the transform kind from the id.
|
||||||
pub fn invalid() -> Self {
|
pub fn transform_kind(&self) -> TransformedRectKind {
|
||||||
ClipScrollNodeData {
|
if (self.0 >> 24) == 0 {
|
||||||
transform: LayoutToWorldTransform::identity(),
|
TransformedRectKind::AxisAligned
|
||||||
inv_transform: WorldToLayoutTransform::identity(),
|
} else {
|
||||||
transform_kind: 0.0,
|
TransformedRectKind::Complex
|
||||||
padding: [0.0; 3],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Debug, Clone, PartialEq)]
|
// The GPU data payload for a transform palette entry.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ClipChainRectIndex(pub usize);
|
pub struct TransformData {
|
||||||
|
pub transform: LayoutToWorldTransform,
|
||||||
|
pub inv_transform: WorldToLayoutTransform,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransformData {
|
||||||
|
pub fn invalid() -> Self {
|
||||||
|
TransformData {
|
||||||
|
transform: LayoutToWorldTransform::identity(),
|
||||||
|
inv_transform: WorldToLayoutTransform::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra data stored about each transform palette entry.
|
||||||
|
pub struct TransformMetadata {
|
||||||
|
pub transform_kind: TransformedRectKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stores a contiguous list of TransformData structs, that
|
||||||
|
// are ready for upload to the GPU.
|
||||||
|
// TODO(gw): For now, this only stores the complete local
|
||||||
|
// to world transform for each spatial node. In
|
||||||
|
// the future, the transform palette will support
|
||||||
|
// specifying a coordinate system that the transform
|
||||||
|
// should be relative to.
|
||||||
|
pub struct TransformPalette {
|
||||||
|
pub transforms: Vec<TransformData>,
|
||||||
|
metadata: Vec<TransformMetadata>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransformPalette {
|
||||||
|
pub fn new(spatial_node_count: usize) -> TransformPalette {
|
||||||
|
TransformPalette {
|
||||||
|
transforms: Vec::with_capacity(spatial_node_count),
|
||||||
|
metadata: Vec::with_capacity(spatial_node_count),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the local -> world transform for a given spatial
|
||||||
|
// node in the transform palette.
|
||||||
|
pub fn set(
|
||||||
|
&mut self,
|
||||||
|
index: TransformIndex,
|
||||||
|
data: TransformData,
|
||||||
|
) {
|
||||||
|
let index = index.0 as usize;
|
||||||
|
|
||||||
|
// Pad the vectors out if they are not long enough to
|
||||||
|
// account for this index. This can occur, for instance,
|
||||||
|
// when we stop recursing down the CST due to encountering
|
||||||
|
// a node with an invalid transform.
|
||||||
|
while index >= self.transforms.len() {
|
||||||
|
self.transforms.push(TransformData::invalid());
|
||||||
|
self.metadata.push(TransformMetadata {
|
||||||
|
transform_kind: TransformedRectKind::AxisAligned,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the transform itself, along with metadata about it.
|
||||||
|
self.metadata[index] = TransformMetadata {
|
||||||
|
transform_kind: data.transform.transform_kind(),
|
||||||
|
};
|
||||||
|
self.transforms[index] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a transform palette id for the given spatial node.
|
||||||
|
// TODO(gw): In the future, it will be possible to specify
|
||||||
|
// a coordinate system id here, to allow retrieving
|
||||||
|
// transforms in the local space of a given spatial node.
|
||||||
|
pub fn get_id(&self, index: TransformIndex) -> TransformPaletteId {
|
||||||
|
let transform_kind = self.metadata[index.0 as usize].transform_kind as u32;
|
||||||
|
TransformPaletteId(index.0 | (transform_kind << 24))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Texture cache resources can be either a simple rect, or define
|
// Texture cache resources can be either a simple rect, or define
|
||||||
// a polygon within a rect by specifying a UV coordinate for each
|
// a polygon within a rect by specifying a UV coordinate for each
|
||||||
|
|
|
@ -182,6 +182,7 @@ pub extern crate webrender_api;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
|
pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
|
||||||
pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources};
|
pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources};
|
||||||
|
pub use frame_builder::ChasePrimitive;
|
||||||
pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
|
pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
|
||||||
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
|
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
|
||||||
pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};
|
pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};
|
||||||
|
|
|
@ -276,7 +276,7 @@ impl PicturePrimitive {
|
||||||
self.can_draw_directly_to_parent_surface()
|
self.can_draw_directly_to_parent_surface()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_render_inner(
|
pub fn prepare_for_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
prim_index: PrimitiveIndex,
|
prim_index: PrimitiveIndex,
|
||||||
prim_metadata: &mut PrimitiveMetadata,
|
prim_metadata: &mut PrimitiveMetadata,
|
||||||
|
@ -489,16 +489,9 @@ impl PicturePrimitive {
|
||||||
// that writes a brush primitive header.
|
// that writes a brush primitive header.
|
||||||
|
|
||||||
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
||||||
// local_rect
|
|
||||||
// clip_rect
|
|
||||||
// [brush specific data]
|
// [brush specific data]
|
||||||
// [segment_rect, segment data]
|
// [segment_rect, segment data]
|
||||||
let shadow_rect = prim_metadata.local_rect.translate(&offset);
|
let shadow_rect = prim_metadata.local_rect.translate(&offset);
|
||||||
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
|
|
||||||
|
|
||||||
// local_rect, clip_rect
|
|
||||||
request.push(shadow_rect);
|
|
||||||
request.push(shadow_clip_rect);
|
|
||||||
|
|
||||||
// ImageBrush colors
|
// ImageBrush colors
|
||||||
request.push(color.premultiplied());
|
request.push(color.premultiplied());
|
||||||
|
@ -592,27 +585,6 @@ impl PicturePrimitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare_for_render(
|
|
||||||
&mut self,
|
|
||||||
prim_index: PrimitiveIndex,
|
|
||||||
prim_metadata: &mut PrimitiveMetadata,
|
|
||||||
prim_run_context: &PrimitiveRunContext,
|
|
||||||
pic_state_for_children: PictureState,
|
|
||||||
pic_state: &mut PictureState,
|
|
||||||
frame_context: &FrameBuildingContext,
|
|
||||||
frame_state: &mut FrameBuildingState,
|
|
||||||
) {
|
|
||||||
self.prepare_for_render_inner(
|
|
||||||
prim_index,
|
|
||||||
prim_metadata,
|
|
||||||
prim_run_context,
|
|
||||||
pic_state_for_children,
|
|
||||||
pic_state,
|
|
||||||
frame_context,
|
|
||||||
frame_state,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate a single screen-space UV for a picture.
|
// Calculate a single screen-space UV for a picture.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
|
use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF};
|
||||||
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode};
|
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode};
|
||||||
use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset};
|
use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset};
|
||||||
use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
|
use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
|
||||||
|
@ -20,7 +20,7 @@ use frame_builder::PrimitiveRunContext;
|
||||||
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
|
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, ClipChainRectIndex};
|
use gpu_types::BrushFlags;
|
||||||
use image::{for_each_tile, for_each_repetition};
|
use image::{for_each_tile, for_each_repetition};
|
||||||
use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
|
use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
@ -50,7 +50,7 @@ impl ScrollNodeAndClipChain {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
scroll_node_id: ClipScrollNodeIndex,
|
scroll_node_id: ClipScrollNodeIndex,
|
||||||
clip_chain_index: ClipChainIndex
|
clip_chain_index: ClipChainIndex
|
||||||
) -> ScrollNodeAndClipChain {
|
) -> Self {
|
||||||
ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
|
ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,17 @@ pub struct PrimitiveRun {
|
||||||
pub clip_and_scroll: ScrollNodeAndClipChain,
|
pub clip_and_scroll: ScrollNodeAndClipChain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PrimitiveRun {
|
||||||
|
pub fn is_chasing(&self, index: Option<PrimitiveIndex>) -> bool {
|
||||||
|
match index {
|
||||||
|
Some(id) if cfg!(debug_assertions) => {
|
||||||
|
self.base_prim_index <= id && id.0 < self.base_prim_index.0 + self.count
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct PrimitiveOpacity {
|
pub struct PrimitiveOpacity {
|
||||||
pub is_opaque: bool,
|
pub is_opaque: bool,
|
||||||
|
@ -174,7 +185,11 @@ pub struct PrimitiveMetadata {
|
||||||
// storing them here.
|
// storing them here.
|
||||||
pub local_rect: LayoutRect,
|
pub local_rect: LayoutRect,
|
||||||
pub local_clip_rect: LayoutRect,
|
pub local_clip_rect: LayoutRect,
|
||||||
pub clip_chain_rect_index: ClipChainRectIndex,
|
|
||||||
|
// The current combined local clip for this primitive, from
|
||||||
|
// the primitive local clip above and the current clip chain.
|
||||||
|
pub combined_local_clip_rect: LayoutRect,
|
||||||
|
|
||||||
pub is_backface_visible: bool,
|
pub is_backface_visible: bool,
|
||||||
pub screen_rect: Option<ScreenRect>,
|
pub screen_rect: Option<ScreenRect>,
|
||||||
|
|
||||||
|
@ -234,11 +249,15 @@ pub struct VisibleImageTile {
|
||||||
pub tile_offset: TileOffset,
|
pub tile_offset: TileOffset,
|
||||||
pub handle: GpuCacheHandle,
|
pub handle: GpuCacheHandle,
|
||||||
pub edge_flags: EdgeAaSegmentMask,
|
pub edge_flags: EdgeAaSegmentMask,
|
||||||
|
pub local_rect: LayoutRect,
|
||||||
|
pub local_clip_rect: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VisibleGradientTile {
|
pub struct VisibleGradientTile {
|
||||||
pub handle: GpuCacheHandle,
|
pub handle: GpuCacheHandle,
|
||||||
|
pub local_rect: LayoutRect,
|
||||||
|
pub local_clip_rect: LayoutRect,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -418,14 +437,14 @@ impl BrushPrimitive {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
kind: BrushKind,
|
kind: BrushKind,
|
||||||
segment_desc: Option<BrushSegmentDescriptor>,
|
segment_desc: Option<BrushSegmentDescriptor>,
|
||||||
) -> BrushPrimitive {
|
) -> Self {
|
||||||
BrushPrimitive {
|
BrushPrimitive {
|
||||||
kind,
|
kind,
|
||||||
segment_desc,
|
segment_desc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_picture(pic_index: PictureIndex) -> BrushPrimitive {
|
pub fn new_picture(pic_index: PictureIndex) -> Self {
|
||||||
BrushPrimitive {
|
BrushPrimitive {
|
||||||
kind: BrushKind::Picture {
|
kind: BrushKind::Picture {
|
||||||
pic_index,
|
pic_index,
|
||||||
|
@ -719,7 +738,6 @@ impl<'a> GradientGpuBlockBuilder<'a> {
|
||||||
self.fill_colors(cur_idx, GRADIENT_DATA_TABLE_END, &PremultipliedColorF::WHITE, &cur_color, &mut entries);
|
self.fill_colors(cur_idx, GRADIENT_DATA_TABLE_END, &PremultipliedColorF::WHITE, &cur_color, &mut entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fill in the last entry with the last color stop
|
// Fill in the last entry with the last color stop
|
||||||
self.fill_colors(
|
self.fill_colors(
|
||||||
GRADIENT_DATA_LAST_STOP,
|
GRADIENT_DATA_LAST_STOP,
|
||||||
|
@ -739,12 +757,12 @@ impl<'a> GradientGpuBlockBuilder<'a> {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TextRunPrimitiveCpu {
|
pub struct TextRunPrimitiveCpu {
|
||||||
pub font: FontInstance,
|
pub specified_font: FontInstance,
|
||||||
|
pub used_font: FontInstance,
|
||||||
pub offset: LayoutVector2D,
|
pub offset: LayoutVector2D,
|
||||||
pub glyph_range: ItemRange<GlyphInstance>,
|
pub glyph_range: ItemRange<GlyphInstance>,
|
||||||
pub glyph_keys: Vec<GlyphKey>,
|
pub glyph_keys: Vec<GlyphKey>,
|
||||||
pub glyph_gpu_blocks: Vec<GpuBlockData>,
|
pub glyph_gpu_blocks: Vec<GpuBlockData>,
|
||||||
pub glyph_transform: (DevicePixelScale, FontTransform),
|
|
||||||
pub shadow: bool,
|
pub shadow: bool,
|
||||||
pub glyph_raster_space: GlyphRasterSpace,
|
pub glyph_raster_space: GlyphRasterSpace,
|
||||||
}
|
}
|
||||||
|
@ -759,60 +777,97 @@ impl TextRunPrimitiveCpu {
|
||||||
glyph_raster_space: GlyphRasterSpace,
|
glyph_raster_space: GlyphRasterSpace,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
TextRunPrimitiveCpu {
|
TextRunPrimitiveCpu {
|
||||||
font,
|
specified_font: font.clone(),
|
||||||
|
used_font: font,
|
||||||
offset,
|
offset,
|
||||||
glyph_range,
|
glyph_range,
|
||||||
glyph_keys,
|
glyph_keys,
|
||||||
glyph_gpu_blocks: Vec::new(),
|
glyph_gpu_blocks: Vec::new(),
|
||||||
glyph_transform: (DevicePixelScale::new(1.0), FontTransform::identity()),
|
|
||||||
shadow,
|
shadow,
|
||||||
glyph_raster_space,
|
glyph_raster_space,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_font(
|
pub fn update_font_instance(
|
||||||
&self,
|
&mut self,
|
||||||
device_pixel_scale: DevicePixelScale,
|
device_pixel_scale: DevicePixelScale,
|
||||||
transform: LayoutToWorldTransform,
|
transform: &LayoutToWorldTransform,
|
||||||
) -> FontInstance {
|
allow_subpixel_aa: bool,
|
||||||
let mut font = self.font.clone();
|
) -> bool {
|
||||||
font.size = font.size.scale_by(device_pixel_scale.0);
|
// Get the current font size in device pixels
|
||||||
|
let device_font_size = self.specified_font.size.scale_by(device_pixel_scale.0);
|
||||||
|
|
||||||
|
// Determine if rasterizing glyphs in local or screen space.
|
||||||
// Only support transforms that can be coerced to simple 2D transforms.
|
// Only support transforms that can be coerced to simple 2D transforms.
|
||||||
if transform.has_perspective_component() ||
|
let transform_glyphs = if transform.has_perspective_component() ||
|
||||||
!transform.has_2d_inverse() ||
|
!transform.has_2d_inverse() ||
|
||||||
// Font sizes larger than the limit need to be scaled, thus can't use subpixels.
|
// Font sizes larger than the limit need to be scaled, thus can't use subpixels.
|
||||||
transform.exceeds_2d_scale(FONT_SIZE_LIMIT / font.size.to_f64_px()) ||
|
transform.exceeds_2d_scale(FONT_SIZE_LIMIT / device_font_size.to_f64_px()) ||
|
||||||
// Otherwise, ensure the font is rasterized in screen-space.
|
// Otherwise, ensure the font is rasterized in screen-space.
|
||||||
self.glyph_raster_space != GlyphRasterSpace::Screen {
|
self.glyph_raster_space != GlyphRasterSpace::Screen {
|
||||||
font.disable_subpixel_aa();
|
false
|
||||||
font.disable_subpixel_position();
|
|
||||||
} else {
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the font transform matrix (skew / scale) from the complete transform.
|
||||||
|
let font_transform = if transform_glyphs {
|
||||||
// Quantize the transform to minimize thrashing of the glyph cache.
|
// Quantize the transform to minimize thrashing of the glyph cache.
|
||||||
font.transform = FontTransform::from(&transform).quantize();
|
FontTransform::from(transform).quantize()
|
||||||
|
} else {
|
||||||
|
FontTransform::identity()
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the transform or device size is different, then the caller of
|
||||||
|
// this method needs to know to rebuild the glyphs.
|
||||||
|
let cache_dirty =
|
||||||
|
self.used_font.transform != font_transform ||
|
||||||
|
self.used_font.size != device_font_size;
|
||||||
|
|
||||||
|
// Construct used font instance from the specified font instance
|
||||||
|
self.used_font = FontInstance {
|
||||||
|
transform: font_transform,
|
||||||
|
size: device_font_size,
|
||||||
|
..self.specified_font.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// If subpixel AA is disabled due to the backing surface the glyphs
|
||||||
|
// are being drawn onto, disable it (unless we are using the
|
||||||
|
// specifial subpixel mode that estimates background color).
|
||||||
|
if !allow_subpixel_aa && self.specified_font.bg_color.a == 0 {
|
||||||
|
self.used_font.disable_subpixel_aa();
|
||||||
}
|
}
|
||||||
font
|
|
||||||
|
// If using local space glyphs, we don't want subpixel AA
|
||||||
|
// or positioning.
|
||||||
|
if !transform_glyphs {
|
||||||
|
self.used_font.disable_subpixel_aa();
|
||||||
|
self.used_font.disable_subpixel_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_for_render(
|
fn prepare_for_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
device_pixel_scale: DevicePixelScale,
|
device_pixel_scale: DevicePixelScale,
|
||||||
transform: LayoutToWorldTransform,
|
transform: &LayoutToWorldTransform,
|
||||||
allow_subpixel_aa: bool,
|
allow_subpixel_aa: bool,
|
||||||
display_list: &BuiltDisplayList,
|
display_list: &BuiltDisplayList,
|
||||||
frame_building_state: &mut FrameBuildingState,
|
frame_building_state: &mut FrameBuildingState,
|
||||||
) {
|
) {
|
||||||
if !allow_subpixel_aa && self.font.bg_color.a == 0 {
|
let cache_dirty = self.update_font_instance(
|
||||||
self.font.disable_subpixel_aa();
|
device_pixel_scale,
|
||||||
}
|
transform,
|
||||||
|
allow_subpixel_aa,
|
||||||
let font = self.get_font(device_pixel_scale, transform);
|
);
|
||||||
|
|
||||||
// Cache the glyph positions, if not in the cache already.
|
// Cache the glyph positions, if not in the cache already.
|
||||||
// TODO(gw): In the future, remove `glyph_instances`
|
// TODO(gw): In the future, remove `glyph_instances`
|
||||||
// completely, and just reference the glyphs
|
// completely, and just reference the glyphs
|
||||||
// directly from the display list.
|
// directly from the display list.
|
||||||
if self.glyph_keys.is_empty() || self.glyph_transform != (device_pixel_scale, font.transform) {
|
if self.glyph_keys.is_empty() || cache_dirty {
|
||||||
let subpx_dir = font.get_subpx_dir();
|
let subpx_dir = self.used_font.get_subpx_dir();
|
||||||
let src_glyphs = display_list.get(self.glyph_range);
|
let src_glyphs = display_list.get(self.glyph_range);
|
||||||
|
|
||||||
// TODO(gw): If we support chunks() on AuxIter
|
// TODO(gw): If we support chunks() on AuxIter
|
||||||
|
@ -820,7 +875,7 @@ impl TextRunPrimitiveCpu {
|
||||||
// be much simpler...
|
// be much simpler...
|
||||||
let mut gpu_block = [0.0; 4];
|
let mut gpu_block = [0.0; 4];
|
||||||
for (i, src) in src_glyphs.enumerate() {
|
for (i, src) in src_glyphs.enumerate() {
|
||||||
let world_offset = font.transform.transform(&src.point);
|
let world_offset = self.used_font.transform.transform(&src.point);
|
||||||
let device_offset = device_pixel_scale.transform_point(&world_offset);
|
let device_offset = device_pixel_scale.transform_point(&world_offset);
|
||||||
let key = GlyphKey::new(src.index, device_offset, subpx_dir);
|
let key = GlyphKey::new(src.index, device_offset, subpx_dir);
|
||||||
self.glyph_keys.push(key);
|
self.glyph_keys.push(key);
|
||||||
|
@ -842,12 +897,10 @@ impl TextRunPrimitiveCpu {
|
||||||
if (self.glyph_keys.len() & 1) != 0 {
|
if (self.glyph_keys.len() & 1) != 0 {
|
||||||
self.glyph_gpu_blocks.push(gpu_block.into());
|
self.glyph_gpu_blocks.push(gpu_block.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.glyph_transform = (device_pixel_scale, font.transform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frame_building_state.resource_cache
|
frame_building_state.resource_cache
|
||||||
.request_glyphs(font,
|
.request_glyphs(self.used_font.clone(),
|
||||||
&self.glyph_keys,
|
&self.glyph_keys,
|
||||||
frame_building_state.gpu_cache,
|
frame_building_state.gpu_cache,
|
||||||
frame_building_state.render_tasks,
|
frame_building_state.render_tasks,
|
||||||
|
@ -855,9 +908,9 @@ impl TextRunPrimitiveCpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
|
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
|
||||||
request.push(ColorF::from(self.font.color).premultiplied());
|
request.push(ColorF::from(self.used_font.color).premultiplied());
|
||||||
// this is the only case where we need to provide plain color to GPU
|
// this is the only case where we need to provide plain color to GPU
|
||||||
let bg_color = ColorF::from(self.font.bg_color);
|
let bg_color = ColorF::from(self.used_font.bg_color);
|
||||||
request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]);
|
request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]);
|
||||||
request.push([
|
request.push([
|
||||||
self.offset.x,
|
self.offset.x,
|
||||||
|
@ -1071,7 +1124,7 @@ impl PrimitiveContainer {
|
||||||
pub fn is_visible(&self) -> bool {
|
pub fn is_visible(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
PrimitiveContainer::TextRun(ref info) => {
|
PrimitiveContainer::TextRun(ref info) => {
|
||||||
info.font.color.a > 0
|
info.specified_font.color.a > 0
|
||||||
}
|
}
|
||||||
PrimitiveContainer::Brush(ref brush) => {
|
PrimitiveContainer::Brush(ref brush) => {
|
||||||
match brush.kind {
|
match brush.kind {
|
||||||
|
@ -1100,7 +1153,7 @@ impl PrimitiveContainer {
|
||||||
PrimitiveContainer::TextRun(ref info) => {
|
PrimitiveContainer::TextRun(ref info) => {
|
||||||
let mut font = FontInstance {
|
let mut font = FontInstance {
|
||||||
color: shadow.color.into(),
|
color: shadow.color.into(),
|
||||||
..info.font.clone()
|
..info.specified_font.clone()
|
||||||
};
|
};
|
||||||
if shadow.blur_radius > 0.0 {
|
if shadow.blur_radius > 0.0 {
|
||||||
font.disable_subpixel_aa();
|
font.disable_subpixel_aa();
|
||||||
|
@ -1146,6 +1199,9 @@ pub struct PrimitiveStore {
|
||||||
|
|
||||||
pub pictures: Vec<PicturePrimitive>,
|
pub pictures: Vec<PicturePrimitive>,
|
||||||
next_picture_id: u64,
|
next_picture_id: u64,
|
||||||
|
|
||||||
|
/// A primitive index to chase through debugging.
|
||||||
|
pub chase_id: Option<PrimitiveIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrimitiveStore {
|
impl PrimitiveStore {
|
||||||
|
@ -1157,6 +1213,8 @@ impl PrimitiveStore {
|
||||||
|
|
||||||
pictures: Vec::new(),
|
pictures: Vec::new(),
|
||||||
next_picture_id: 0,
|
next_picture_id: 0,
|
||||||
|
|
||||||
|
chase_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1168,6 +1226,8 @@ impl PrimitiveStore {
|
||||||
|
|
||||||
pictures: recycle_vec(self.pictures),
|
pictures: recycle_vec(self.pictures),
|
||||||
next_picture_id: self.next_picture_id,
|
next_picture_id: self.next_picture_id,
|
||||||
|
|
||||||
|
chase_id: self.chase_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,7 +1273,7 @@ impl PrimitiveStore {
|
||||||
clip_task_id: None,
|
clip_task_id: None,
|
||||||
local_rect: *local_rect,
|
local_rect: *local_rect,
|
||||||
local_clip_rect: *local_clip_rect,
|
local_clip_rect: *local_clip_rect,
|
||||||
clip_chain_rect_index: ClipChainRectIndex(0),
|
combined_local_clip_rect: *local_clip_rect,
|
||||||
is_backface_visible,
|
is_backface_visible,
|
||||||
screen_rect: None,
|
screen_rect: None,
|
||||||
tag,
|
tag,
|
||||||
|
@ -1495,7 +1555,7 @@ impl PrimitiveStore {
|
||||||
let transform = prim_run_context.scroll_node.world_content_transform.into();
|
let transform = prim_run_context.scroll_node.world_content_transform.into();
|
||||||
text.prepare_for_render(
|
text.prepare_for_render(
|
||||||
frame_context.device_pixel_scale,
|
frame_context.device_pixel_scale,
|
||||||
transform,
|
&transform,
|
||||||
pic_context.allow_subpixel_aa,
|
pic_context.allow_subpixel_aa,
|
||||||
pic_context.display_list,
|
pic_context.display_list,
|
||||||
frame_state,
|
frame_state,
|
||||||
|
@ -1644,7 +1704,9 @@ impl PrimitiveStore {
|
||||||
// Tighten the clip rect because decomposing the repeated image can
|
// Tighten the clip rect because decomposing the repeated image can
|
||||||
// produce primitives that are partially covering the original image
|
// produce primitives that are partially covering the original image
|
||||||
// rect and we want to clip these extra parts out.
|
// rect and we want to clip these extra parts out.
|
||||||
let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap();
|
let tight_clip_rect = metadata
|
||||||
|
.combined_local_clip_rect
|
||||||
|
.intersection(&metadata.local_rect).unwrap();
|
||||||
|
|
||||||
let visible_rect = compute_conservative_visible_rect(
|
let visible_rect = compute_conservative_visible_rect(
|
||||||
prim_run_context,
|
prim_run_context,
|
||||||
|
@ -1684,8 +1746,6 @@ impl PrimitiveStore {
|
||||||
|
|
||||||
let mut handle = GpuCacheHandle::new();
|
let mut handle = GpuCacheHandle::new();
|
||||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
|
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
|
||||||
request.push(*tile_rect);
|
|
||||||
request.push(tight_clip_rect);
|
|
||||||
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
|
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
|
||||||
request.push(PremultipliedColorF::WHITE);
|
request.push(PremultipliedColorF::WHITE);
|
||||||
request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]);
|
request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]);
|
||||||
|
@ -1696,6 +1756,8 @@ impl PrimitiveStore {
|
||||||
tile_offset,
|
tile_offset,
|
||||||
handle,
|
handle,
|
||||||
edge_flags: tile_flags & edge_flags,
|
edge_flags: tile_flags & edge_flags,
|
||||||
|
local_rect: *tile_rect,
|
||||||
|
local_clip_rect: tight_clip_rect,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1789,9 +1851,7 @@ impl PrimitiveStore {
|
||||||
prim_run_context,
|
prim_run_context,
|
||||||
frame_context,
|
frame_context,
|
||||||
frame_state,
|
frame_state,
|
||||||
&mut |rect, clip_rect, mut request| {
|
&mut |rect, mut request| {
|
||||||
request.push(*rect);
|
|
||||||
request.push(*clip_rect);
|
|
||||||
request.push([
|
request.push([
|
||||||
center.x,
|
center.x,
|
||||||
center.y,
|
center.y,
|
||||||
|
@ -1841,9 +1901,7 @@ impl PrimitiveStore {
|
||||||
prim_run_context,
|
prim_run_context,
|
||||||
frame_context,
|
frame_context,
|
||||||
frame_state,
|
frame_state,
|
||||||
&mut |rect, clip_rect, mut request| {
|
&mut |rect, mut request| {
|
||||||
request.push(*rect);
|
|
||||||
request.push(*clip_rect);
|
|
||||||
request.push([
|
request.push([
|
||||||
start_point.x,
|
start_point.x,
|
||||||
start_point.y,
|
start_point.y,
|
||||||
|
@ -1895,10 +1953,6 @@ impl PrimitiveStore {
|
||||||
|
|
||||||
// Mark this GPU resource as required for this frame.
|
// Mark this GPU resource as required for this frame.
|
||||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) {
|
if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) {
|
||||||
// has to match VECS_PER_BRUSH_PRIM
|
|
||||||
request.push(metadata.local_rect);
|
|
||||||
request.push(metadata.local_clip_rect);
|
|
||||||
|
|
||||||
match metadata.prim_kind {
|
match metadata.prim_kind {
|
||||||
PrimitiveKind::TextRun => {
|
PrimitiveKind::TextRun => {
|
||||||
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
|
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
|
||||||
|
@ -2042,11 +2096,11 @@ impl PrimitiveStore {
|
||||||
// node and the primitive, we need to get the clip rect in the
|
// node and the primitive, we need to get the clip rect in the
|
||||||
// local space of the primitive, in order to generate correct
|
// local space of the primitive, in order to generate correct
|
||||||
// local segments.
|
// local segments.
|
||||||
let local_clip_rect = if clip_item.scroll_node_data_index == prim_run_context.scroll_node.node_data_index {
|
let local_clip_rect = if clip_item.transform_index == prim_run_context.scroll_node.transform_index {
|
||||||
local_clip_rect
|
local_clip_rect
|
||||||
} else {
|
} else {
|
||||||
let clip_transform = frame_context
|
let clip_transform = frame_context
|
||||||
.node_data[clip_item.scroll_node_data_index.0 as usize]
|
.transforms[clip_item.transform_index.0 as usize]
|
||||||
.transform;
|
.transform;
|
||||||
let prim_transform = &prim_run_context.scroll_node.world_content_transform;
|
let prim_transform = &prim_run_context.scroll_node.world_content_transform;
|
||||||
let relative_transform = prim_transform
|
let relative_transform = prim_transform
|
||||||
|
@ -2193,12 +2247,19 @@ impl PrimitiveStore {
|
||||||
frame_context: &FrameBuildingContext,
|
frame_context: &FrameBuildingContext,
|
||||||
frame_state: &mut FrameBuildingState,
|
frame_state: &mut FrameBuildingState,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tupdating clip task with screen rect {:?}", prim_screen_rect);
|
||||||
|
}
|
||||||
// Reset clips from previous frames since we may clip differently each frame.
|
// Reset clips from previous frames since we may clip differently each frame.
|
||||||
self.reset_clip_task(prim_index);
|
self.reset_clip_task(prim_index);
|
||||||
|
|
||||||
let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
|
let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
|
||||||
Some(rect) => rect,
|
Some(rect) => rect,
|
||||||
None => {
|
None => {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled by the intersection with frame rect {:?}",
|
||||||
|
frame_context.screen_rect);
|
||||||
|
}
|
||||||
self.cpu_metadata[prim_index.0].screen_rect = None;
|
self.cpu_metadata[prim_index.0].screen_rect = None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2207,6 +2268,9 @@ impl PrimitiveStore {
|
||||||
let mut combined_outer_rect =
|
let mut combined_outer_rect =
|
||||||
prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect);
|
prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect);
|
||||||
let clip_chain = prim_run_context.clip_chain.nodes.clone();
|
let clip_chain = prim_run_context.clip_chain.nodes.clone();
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tbase combined outer rect {:?}", combined_outer_rect);
|
||||||
|
}
|
||||||
|
|
||||||
let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id;
|
let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id;
|
||||||
let transform = &prim_run_context.scroll_node.world_content_transform;
|
let transform = &prim_run_context.scroll_node.world_content_transform;
|
||||||
|
@ -2228,10 +2292,13 @@ impl PrimitiveStore {
|
||||||
if let Some(outer) = screen_outer_rect {
|
if let Some(outer) = screen_outer_rect {
|
||||||
combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer));
|
combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer));
|
||||||
}
|
}
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tfound extra clip with screen bounds {:?}", screen_outer_rect);
|
||||||
|
}
|
||||||
|
|
||||||
Arc::new(ClipChainNode {
|
Arc::new(ClipChainNode {
|
||||||
work_item: ClipWorkItem {
|
work_item: ClipWorkItem {
|
||||||
scroll_node_data_index: prim_run_context.scroll_node.node_data_index,
|
transform_index: prim_run_context.scroll_node.transform_index,
|
||||||
clip_sources: clip_sources.weak(),
|
clip_sources: clip_sources.weak(),
|
||||||
coordinate_system_id: prim_coordinate_system_id,
|
coordinate_system_id: prim_coordinate_system_id,
|
||||||
},
|
},
|
||||||
|
@ -2251,6 +2318,9 @@ impl PrimitiveStore {
|
||||||
let combined_outer_rect = match combined_outer_rect {
|
let combined_outer_rect = match combined_outer_rect {
|
||||||
Some(rect) if !rect.is_empty() => rect,
|
Some(rect) if !rect.is_empty() => rect,
|
||||||
_ => {
|
_ => {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled by the empty combined screen rect");
|
||||||
|
}
|
||||||
self.cpu_metadata[prim_index.0].screen_rect = None;
|
self.cpu_metadata[prim_index.0].screen_rect = None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2274,12 +2344,18 @@ impl PrimitiveStore {
|
||||||
// If we don't have any clips from other coordinate systems, the local clip
|
// If we don't have any clips from other coordinate systems, the local clip
|
||||||
// calculated from the clip chain should be sufficient to ensure proper clipping.
|
// calculated from the clip chain should be sufficient to ensure proper clipping.
|
||||||
if !has_clips_from_other_coordinate_systems {
|
if !has_clips_from_other_coordinate_systems {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tneed no task: all clips are within the coordinate system");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have filtered all clips and the screen rect isn't any smaller, we can just
|
// If we have filtered all clips and the screen rect isn't any smaller, we can just
|
||||||
// skip masking entirely.
|
// skip masking entirely.
|
||||||
if combined_outer_rect == prim_screen_rect {
|
if combined_outer_rect == prim_screen_rect {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tneed no task: combined rect is not smaller");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Otherwise we create an empty mask, but with an empty inner rect to avoid further
|
// Otherwise we create an empty mask, but with an empty inner rect to avoid further
|
||||||
|
@ -2288,7 +2364,10 @@ impl PrimitiveStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
if combined_inner_rect.contains_rect(&prim_screen_rect) {
|
if combined_inner_rect.contains_rect(&prim_screen_rect) {
|
||||||
return true;
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tneed no task: contained within the clip inner rect");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First try to render this primitive's mask using optimized brush rendering.
|
// First try to render this primitive's mask using optimized brush rendering.
|
||||||
|
@ -2302,6 +2381,9 @@ impl PrimitiveStore {
|
||||||
frame_context,
|
frame_context,
|
||||||
frame_state,
|
frame_state,
|
||||||
) {
|
) {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tsegment tasks have been created for clipping");
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2316,6 +2398,10 @@ impl PrimitiveStore {
|
||||||
);
|
);
|
||||||
|
|
||||||
let clip_task_id = frame_state.render_tasks.add(clip_task);
|
let clip_task_id = frame_state.render_tasks.add(clip_task);
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tcreated task {:?} with combined outer rect {:?}",
|
||||||
|
clip_task_id, combined_outer_rect);
|
||||||
|
}
|
||||||
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
|
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
|
||||||
pic_state.tasks.push(clip_task_id);
|
pic_state.tasks.push(clip_task_id);
|
||||||
|
|
||||||
|
@ -2341,6 +2427,9 @@ impl PrimitiveStore {
|
||||||
|
|
||||||
if !metadata.is_backface_visible &&
|
if !metadata.is_backface_visible &&
|
||||||
prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
|
prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled for not having visible back faces");
|
||||||
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2358,6 +2447,9 @@ impl PrimitiveStore {
|
||||||
let pic = &mut self.pictures[pic_index.0];
|
let pic = &mut self.pictures[pic_index.0];
|
||||||
|
|
||||||
if !pic.resolve_scene_properties(frame_context.scene_properties) {
|
if !pic.resolve_scene_properties(frame_context.scene_properties) {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled for carrying an invisible composite filter");
|
||||||
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2429,7 +2521,9 @@ impl PrimitiveStore {
|
||||||
let metadata = &mut self.cpu_metadata[prim_index.0];
|
let metadata = &mut self.cpu_metadata[prim_index.0];
|
||||||
if metadata.local_rect.size.width <= 0.0 ||
|
if metadata.local_rect.size.width <= 0.0 ||
|
||||||
metadata.local_rect.size.height <= 0.0 {
|
metadata.local_rect.size.height <= 0.0 {
|
||||||
//warn!("invalid primitive rect {:?}", metadata.local_rect);
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled for zero local rectangle");
|
||||||
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2441,14 +2535,33 @@ impl PrimitiveStore {
|
||||||
// taken into account.
|
// taken into account.
|
||||||
let local_rect = metadata.local_rect
|
let local_rect = metadata.local_rect
|
||||||
.inflate(pic_context.inflation_factor, pic_context.inflation_factor)
|
.inflate(pic_context.inflation_factor, pic_context.inflation_factor)
|
||||||
.intersection(&metadata.local_clip_rect)?;
|
.intersection(&metadata.local_clip_rect);
|
||||||
|
let local_rect = match local_rect {
|
||||||
|
Some(local_rect) => local_rect,
|
||||||
|
None => {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled for being out of the local clip rectangle: {:?}",
|
||||||
|
metadata.local_clip_rect);
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let unclipped = calculate_screen_bounding_rect(
|
let unclipped = match calculate_screen_bounding_rect(
|
||||||
&prim_run_context.scroll_node.world_content_transform,
|
&prim_run_context.scroll_node.world_content_transform,
|
||||||
&local_rect,
|
&local_rect,
|
||||||
frame_context.device_pixel_scale,
|
frame_context.device_pixel_scale,
|
||||||
None, //TODO: inflate `frame_context.screen_rect` appropriately
|
None, //TODO: inflate `frame_context.screen_rect` appropriately
|
||||||
)?;
|
) {
|
||||||
|
Some(rect) => rect,
|
||||||
|
None => {
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tculled for being behind the near plane of transform: {:?}",
|
||||||
|
prim_run_context.scroll_node.world_content_transform);
|
||||||
|
}
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let clipped = unclipped
|
let clipped = unclipped
|
||||||
.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)?;
|
.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)?;
|
||||||
|
@ -2457,7 +2570,11 @@ impl PrimitiveStore {
|
||||||
clipped,
|
clipped,
|
||||||
unclipped,
|
unclipped,
|
||||||
});
|
});
|
||||||
metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index;
|
|
||||||
|
metadata.combined_local_clip_rect = prim_run_context
|
||||||
|
.local_clip_rect
|
||||||
|
.intersection(&metadata.local_clip_rect)
|
||||||
|
.unwrap_or(LayoutRect::zero());
|
||||||
|
|
||||||
(local_rect, unclipped)
|
(local_rect, unclipped)
|
||||||
};
|
};
|
||||||
|
@ -2480,6 +2597,10 @@ impl PrimitiveStore {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
|
||||||
|
println!("\tconsidered visible and ready with local rect {:?}", local_rect);
|
||||||
|
}
|
||||||
|
|
||||||
self.prepare_prim_for_render_inner(
|
self.prepare_prim_for_render_inner(
|
||||||
prim_index,
|
prim_index,
|
||||||
prim_run_context,
|
prim_run_context,
|
||||||
|
@ -2514,6 +2635,10 @@ impl PrimitiveStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
for run in &pic_context.prim_runs {
|
for run in &pic_context.prim_runs {
|
||||||
|
if run.is_chasing(self.chase_id) {
|
||||||
|
println!("\tpreparing a run of length {} in pipeline {:?}",
|
||||||
|
run.count, pic_context.pipeline_id);
|
||||||
|
}
|
||||||
// TODO(gw): Perhaps we can restructure this to not need to create
|
// TODO(gw): Perhaps we can restructure this to not need to create
|
||||||
// a new primitive context for every run (if the hash
|
// a new primitive context for every run (if the hash
|
||||||
// lookups ever show up in a profile).
|
// lookups ever show up in a profile).
|
||||||
|
@ -2531,12 +2656,16 @@ impl PrimitiveStore {
|
||||||
pic_state.has_non_root_coord_system |= clip_chain.has_non_root_coord_system;
|
pic_state.has_non_root_coord_system |= clip_chain.has_non_root_coord_system;
|
||||||
|
|
||||||
if !scroll_node.invertible {
|
if !scroll_node.invertible {
|
||||||
debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id);
|
if run.is_chasing(self.chase_id) {
|
||||||
|
println!("\tculled for the scroll node transform being invertible");
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if clip_chain.combined_outer_screen_rect.is_empty() {
|
if clip_chain.combined_outer_screen_rect.is_empty() {
|
||||||
debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id);
|
if run.is_chasing(self.chase_id) {
|
||||||
|
println!("\tculled for out of screen bounds");
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2565,19 +2694,16 @@ impl PrimitiveStore {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let clip_chain_rect_index = match clip_chain_rect {
|
let local_clip_chain_rect = match clip_chain_rect {
|
||||||
Some(rect) if rect.is_empty() => continue,
|
Some(rect) if rect.is_empty() => continue,
|
||||||
Some(rect) => {
|
Some(rect) => rect,
|
||||||
frame_state.local_clip_rects.push(rect);
|
None => frame_context.max_local_clip,
|
||||||
ClipChainRectIndex(frame_state.local_clip_rects.len() - 1)
|
|
||||||
}
|
|
||||||
None => ClipChainRectIndex(0), // This is no clipping.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let child_prim_run_context = PrimitiveRunContext::new(
|
let child_prim_run_context = PrimitiveRunContext::new(
|
||||||
clip_chain,
|
clip_chain,
|
||||||
scroll_node,
|
scroll_node,
|
||||||
clip_chain_rect_index,
|
local_clip_chain_rect,
|
||||||
);
|
);
|
||||||
|
|
||||||
for i in 0 .. run.count {
|
for i in 0 .. run.count {
|
||||||
|
@ -2611,6 +2737,12 @@ impl PrimitiveStore {
|
||||||
result.local_rect_in_original_parent_space =
|
result.local_rect_in_original_parent_space =
|
||||||
result.local_rect_in_original_parent_space.union(&bounds);
|
result.local_rect_in_original_parent_space.union(&bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref matrix) = parent_relative_transform {
|
||||||
|
let bounds = matrix.transform_rect(&prim_local_rect);
|
||||||
|
result.local_rect_in_actual_parent_space =
|
||||||
|
result.local_rect_in_actual_parent_space.union(&bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2646,14 +2778,16 @@ fn decompose_repeated_primitive(
|
||||||
prim_run_context: &PrimitiveRunContext,
|
prim_run_context: &PrimitiveRunContext,
|
||||||
frame_context: &FrameBuildingContext,
|
frame_context: &FrameBuildingContext,
|
||||||
frame_state: &mut FrameBuildingState,
|
frame_state: &mut FrameBuildingState,
|
||||||
callback: &mut FnMut(&LayoutRect, &LayoutRect, GpuDataRequest),
|
callback: &mut FnMut(&LayoutRect, GpuDataRequest),
|
||||||
) {
|
) {
|
||||||
visible_tiles.clear();
|
visible_tiles.clear();
|
||||||
|
|
||||||
// Tighten the clip rect because decomposing the repeated image can
|
// Tighten the clip rect because decomposing the repeated image can
|
||||||
// produce primitives that are partially covering the original image
|
// produce primitives that are partially covering the original image
|
||||||
// rect and we want to clip these extra parts out.
|
// rect and we want to clip these extra parts out.
|
||||||
let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap();
|
let tight_clip_rect = metadata
|
||||||
|
.combined_local_clip_rect
|
||||||
|
.intersection(&metadata.local_rect).unwrap();
|
||||||
|
|
||||||
let visible_rect = compute_conservative_visible_rect(
|
let visible_rect = compute_conservative_visible_rect(
|
||||||
prim_run_context,
|
prim_run_context,
|
||||||
|
@ -2669,16 +2803,19 @@ fn decompose_repeated_primitive(
|
||||||
&mut |origin, _| {
|
&mut |origin, _| {
|
||||||
|
|
||||||
let mut handle = GpuCacheHandle::new();
|
let mut handle = GpuCacheHandle::new();
|
||||||
|
let rect = LayoutRect {
|
||||||
|
origin: *origin,
|
||||||
|
size: *stretch_size,
|
||||||
|
};
|
||||||
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
|
if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
|
||||||
let rect = LayoutRect {
|
callback(&rect, request);
|
||||||
origin: *origin,
|
|
||||||
size: *stretch_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
callback(&rect, &tight_clip_rect, request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visible_tiles.push(VisibleGradientTile { handle });
|
visible_tiles.push(VisibleGradientTile {
|
||||||
|
local_rect: rect,
|
||||||
|
local_clip_rect: tight_clip_rect,
|
||||||
|
handle
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2725,31 +2862,6 @@ fn edge_flags_for_tile_spacing(tile_spacing: &LayoutSize) -> EdgeAaSegmentMask {
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
//Test for one clip region contains another
|
|
||||||
trait InsideTest<T> {
|
|
||||||
fn might_contain(&self, clip: &T) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InsideTest<ComplexClipRegion> for ComplexClipRegion {
|
|
||||||
// Returns true if clip is inside self, can return false negative
|
|
||||||
fn might_contain(&self, clip: &ComplexClipRegion) -> bool {
|
|
||||||
let delta_left = clip.rect.origin.x - self.rect.origin.x;
|
|
||||||
let delta_top = clip.rect.origin.y - self.rect.origin.y;
|
|
||||||
let delta_right = self.rect.max_x() - clip.rect.max_x();
|
|
||||||
let delta_bottom = self.rect.max_y() - clip.rect.max_y();
|
|
||||||
|
|
||||||
delta_left >= 0f32 && delta_top >= 0f32 && delta_right >= 0f32 && delta_bottom >= 0f32 &&
|
|
||||||
clip.radii.top_left.width >= self.radii.top_left.width - delta_left &&
|
|
||||||
clip.radii.top_left.height >= self.radii.top_left.height - delta_top &&
|
|
||||||
clip.radii.top_right.width >= self.radii.top_right.width - delta_right &&
|
|
||||||
clip.radii.top_right.height >= self.radii.top_right.height - delta_top &&
|
|
||||||
clip.radii.bottom_left.width >= self.radii.bottom_left.width - delta_left &&
|
|
||||||
clip.radii.bottom_left.height >= self.radii.bottom_left.height - delta_bottom &&
|
|
||||||
clip.radii.bottom_right.width >= self.radii.bottom_right.width - delta_right &&
|
|
||||||
clip.radii.bottom_right.height >= self.radii.bottom_right.height - delta_bottom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn convert_clip_chain_to_clip_vector(
|
fn convert_clip_chain_to_clip_vector(
|
||||||
clip_chain_nodes: ClipChainNodeRef,
|
clip_chain_nodes: ClipChainNodeRef,
|
||||||
extra_clip: ClipChainNodeRef,
|
extra_clip: ClipChainNodeRef,
|
||||||
|
|
|
@ -1063,6 +1063,7 @@ impl RenderBackend {
|
||||||
|
|
||||||
debug_assert!(op.render || !op.composite);
|
debug_assert!(op.render || !op.composite);
|
||||||
|
|
||||||
|
let mut render_time = None;
|
||||||
if op.render && doc.has_pixels() {
|
if op.render && doc.has_pixels() {
|
||||||
profile_scope!("generate frame");
|
profile_scope!("generate frame");
|
||||||
|
|
||||||
|
@ -1071,6 +1072,7 @@ impl RenderBackend {
|
||||||
// borrow ck hack for profile_counters
|
// borrow ck hack for profile_counters
|
||||||
let (pending_update, rendered_document) = {
|
let (pending_update, rendered_document) = {
|
||||||
let _timer = profile_counters.total_time.timer();
|
let _timer = profile_counters.total_time.timer();
|
||||||
|
let render_start_time = precise_time_ns();
|
||||||
|
|
||||||
let rendered_document = doc.render(
|
let rendered_document = doc.render(
|
||||||
&mut self.resource_cache,
|
&mut self.resource_cache,
|
||||||
|
@ -1085,6 +1087,8 @@ impl RenderBackend {
|
||||||
let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
|
let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
|
||||||
self.result_tx.send(msg).unwrap();
|
self.result_tx.send(msg).unwrap();
|
||||||
|
|
||||||
|
render_time = Some(precise_time_ns() - render_start_time);
|
||||||
|
|
||||||
let pending_update = self.resource_cache.pending_updates();
|
let pending_update = self.resource_cache.pending_updates();
|
||||||
(pending_update, rendered_document)
|
(pending_update, rendered_document)
|
||||||
};
|
};
|
||||||
|
@ -1111,7 +1115,7 @@ impl RenderBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
if transaction_msg.generate_frame {
|
if transaction_msg.generate_frame {
|
||||||
self.notifier.new_frame_ready(document_id, op.scroll, op.composite);
|
self.notifier.new_frame_ready(document_id, op.scroll, op.composite, render_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1410,7 +1414,7 @@ impl RenderBackend {
|
||||||
self.result_tx.send(msg_publish).unwrap();
|
self.result_tx.send(msg_publish).unwrap();
|
||||||
profile_counters.reset();
|
profile_counters.reset();
|
||||||
|
|
||||||
self.notifier.new_frame_ready(id, false, true);
|
self.notifier.new_frame_ready(id, false, true, None);
|
||||||
self.documents.insert(id, doc);
|
self.documents.insert(id, doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use device::{FileWatcherHandler, ShaderError, TextureFilter,
|
||||||
VertexUsageHint, VAO, VBO, CustomVAO};
|
VertexUsageHint, VAO, VBO, CustomVAO};
|
||||||
use device::{ProgramCache, ReadPixelsFormat};
|
use device::{ProgramCache, ReadPixelsFormat};
|
||||||
use euclid::{rect, Transform3D};
|
use euclid::{rect, Transform3D};
|
||||||
use frame_builder::FrameBuilderConfig;
|
use frame_builder::{ChasePrimitive, FrameBuilderConfig};
|
||||||
use gleam::gl;
|
use gleam::gl;
|
||||||
use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
|
use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
|
||||||
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
||||||
|
@ -270,14 +270,15 @@ pub(crate) enum TextureSampler {
|
||||||
CacheA8,
|
CacheA8,
|
||||||
CacheRGBA8,
|
CacheRGBA8,
|
||||||
ResourceCache,
|
ResourceCache,
|
||||||
ClipScrollNodes,
|
TransformPalette,
|
||||||
RenderTasks,
|
RenderTasks,
|
||||||
Dither,
|
Dither,
|
||||||
// A special sampler that is bound to the A8 output of
|
// A special sampler that is bound to the A8 output of
|
||||||
// the *first* pass. Items rendered in this target are
|
// the *first* pass. Items rendered in this target are
|
||||||
// available as inputs to tasks in any subsequent pass.
|
// available as inputs to tasks in any subsequent pass.
|
||||||
SharedCacheA8,
|
SharedCacheA8,
|
||||||
LocalClipRects
|
PrimitiveHeadersF,
|
||||||
|
PrimitiveHeadersI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureSampler {
|
impl TextureSampler {
|
||||||
|
@ -302,11 +303,12 @@ impl Into<TextureSlot> for TextureSampler {
|
||||||
TextureSampler::CacheA8 => TextureSlot(3),
|
TextureSampler::CacheA8 => TextureSlot(3),
|
||||||
TextureSampler::CacheRGBA8 => TextureSlot(4),
|
TextureSampler::CacheRGBA8 => TextureSlot(4),
|
||||||
TextureSampler::ResourceCache => TextureSlot(5),
|
TextureSampler::ResourceCache => TextureSlot(5),
|
||||||
TextureSampler::ClipScrollNodes => TextureSlot(6),
|
TextureSampler::TransformPalette => TextureSlot(6),
|
||||||
TextureSampler::RenderTasks => TextureSlot(7),
|
TextureSampler::RenderTasks => TextureSlot(7),
|
||||||
TextureSampler::Dither => TextureSlot(8),
|
TextureSampler::Dither => TextureSlot(8),
|
||||||
TextureSampler::SharedCacheA8 => TextureSlot(9),
|
TextureSampler::SharedCacheA8 => TextureSlot(9),
|
||||||
TextureSampler::LocalClipRects => TextureSlot(10),
|
TextureSampler::PrimitiveHeadersF => TextureSlot(10),
|
||||||
|
TextureSampler::PrimitiveHeadersI => TextureSlot(11),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,12 +332,7 @@ pub(crate) mod desc {
|
||||||
],
|
],
|
||||||
instance_attributes: &[
|
instance_attributes: &[
|
||||||
VertexAttribute {
|
VertexAttribute {
|
||||||
name: "aData0",
|
name: "aData",
|
||||||
count: 4,
|
|
||||||
kind: VertexAttributeKind::I32,
|
|
||||||
},
|
|
||||||
VertexAttribute {
|
|
||||||
name: "aData1",
|
|
||||||
count: 4,
|
count: 4,
|
||||||
kind: VertexAttributeKind::I32,
|
kind: VertexAttributeKind::I32,
|
||||||
},
|
},
|
||||||
|
@ -1215,8 +1212,14 @@ struct VertexDataTexture {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VertexDataTexture {
|
impl VertexDataTexture {
|
||||||
fn new(device: &mut Device) -> VertexDataTexture {
|
fn new(
|
||||||
let texture = device.create_texture(TextureTarget::Default, ImageFormat::RGBAF32);
|
device: &mut Device,
|
||||||
|
format: ImageFormat,
|
||||||
|
) -> VertexDataTexture {
|
||||||
|
let texture = device.create_texture(
|
||||||
|
TextureTarget::Default,
|
||||||
|
format,
|
||||||
|
);
|
||||||
let pbo = device.create_pbo();
|
let pbo = device.create_pbo();
|
||||||
|
|
||||||
VertexDataTexture { texture, pbo }
|
VertexDataTexture { texture, pbo }
|
||||||
|
@ -1369,8 +1372,9 @@ pub struct Renderer {
|
||||||
pub gpu_profile: GpuProfiler<GpuProfileTag>,
|
pub gpu_profile: GpuProfiler<GpuProfileTag>,
|
||||||
vaos: RendererVAOs,
|
vaos: RendererVAOs,
|
||||||
|
|
||||||
node_data_texture: VertexDataTexture,
|
prim_header_f_texture: VertexDataTexture,
|
||||||
local_clip_rects_texture: VertexDataTexture,
|
prim_header_i_texture: VertexDataTexture,
|
||||||
|
transforms_texture: VertexDataTexture,
|
||||||
render_task_texture: VertexDataTexture,
|
render_task_texture: VertexDataTexture,
|
||||||
gpu_cache_texture: CacheTexture,
|
gpu_cache_texture: CacheTexture,
|
||||||
|
|
||||||
|
@ -1629,9 +1633,10 @@ impl Renderer {
|
||||||
|
|
||||||
let texture_resolver = SourceTextureResolver::new(&mut device);
|
let texture_resolver = SourceTextureResolver::new(&mut device);
|
||||||
|
|
||||||
let node_data_texture = VertexDataTexture::new(&mut device);
|
let prim_header_f_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
|
||||||
let local_clip_rects_texture = VertexDataTexture::new(&mut device);
|
let prim_header_i_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAI32);
|
||||||
let render_task_texture = VertexDataTexture::new(&mut device);
|
let transforms_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
|
||||||
|
let render_task_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
|
||||||
|
|
||||||
let gpu_cache_texture = CacheTexture::new(
|
let gpu_cache_texture = CacheTexture::new(
|
||||||
&mut device,
|
&mut device,
|
||||||
|
@ -1653,6 +1658,7 @@ impl Renderer {
|
||||||
default_font_render_mode,
|
default_font_render_mode,
|
||||||
dual_source_blending_is_enabled: true,
|
dual_source_blending_is_enabled: true,
|
||||||
dual_source_blending_is_supported: ext_dual_source_blending,
|
dual_source_blending_is_supported: ext_dual_source_blending,
|
||||||
|
chase_primitive: options.chase_primitive,
|
||||||
};
|
};
|
||||||
|
|
||||||
let device_pixel_ratio = options.device_pixel_ratio;
|
let device_pixel_ratio = options.device_pixel_ratio;
|
||||||
|
@ -1784,8 +1790,9 @@ impl Renderer {
|
||||||
dash_and_dot_vao,
|
dash_and_dot_vao,
|
||||||
border_vao,
|
border_vao,
|
||||||
},
|
},
|
||||||
node_data_texture,
|
transforms_texture,
|
||||||
local_clip_rects_texture,
|
prim_header_i_texture,
|
||||||
|
prim_header_f_texture,
|
||||||
render_task_texture,
|
render_task_texture,
|
||||||
pipeline_info: PipelineInfo::default(),
|
pipeline_info: PipelineInfo::default(),
|
||||||
dither_matrix_texture,
|
dither_matrix_texture,
|
||||||
|
@ -3533,16 +3540,31 @@ impl Renderer {
|
||||||
let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
|
let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
|
||||||
self.device.set_device_pixel_ratio(frame.device_pixel_ratio);
|
self.device.set_device_pixel_ratio(frame.device_pixel_ratio);
|
||||||
|
|
||||||
self.node_data_texture.update(&mut self.device, &mut frame.node_data);
|
self.prim_header_f_texture.update(
|
||||||
self.device.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture);
|
|
||||||
|
|
||||||
self.local_clip_rects_texture.update(
|
|
||||||
&mut self.device,
|
&mut self.device,
|
||||||
&mut frame.clip_chain_local_clip_rects
|
&mut frame.prim_headers.headers_float,
|
||||||
);
|
);
|
||||||
self.device.bind_texture(
|
self.device.bind_texture(
|
||||||
TextureSampler::LocalClipRects,
|
TextureSampler::PrimitiveHeadersF,
|
||||||
&self.local_clip_rects_texture.texture
|
&self.prim_header_f_texture.texture,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.prim_header_i_texture.update(
|
||||||
|
&mut self.device,
|
||||||
|
&mut frame.prim_headers.headers_int,
|
||||||
|
);
|
||||||
|
self.device.bind_texture(
|
||||||
|
TextureSampler::PrimitiveHeadersI,
|
||||||
|
&self.prim_header_i_texture.texture,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.transforms_texture.update(
|
||||||
|
&mut self.device,
|
||||||
|
&mut frame.transform_palette,
|
||||||
|
);
|
||||||
|
self.device.bind_texture(
|
||||||
|
TextureSampler::TransformPalette,
|
||||||
|
&self.transforms_texture.texture,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.render_task_texture
|
self.render_task_texture
|
||||||
|
@ -3929,8 +3951,9 @@ impl Renderer {
|
||||||
if let Some(dither_matrix_texture) = self.dither_matrix_texture {
|
if let Some(dither_matrix_texture) = self.dither_matrix_texture {
|
||||||
self.device.delete_texture(dither_matrix_texture);
|
self.device.delete_texture(dither_matrix_texture);
|
||||||
}
|
}
|
||||||
self.node_data_texture.deinit(&mut self.device);
|
self.transforms_texture.deinit(&mut self.device);
|
||||||
self.local_clip_rects_texture.deinit(&mut self.device);
|
self.prim_header_f_texture.deinit(&mut self.device);
|
||||||
|
self.prim_header_i_texture.deinit(&mut self.device);
|
||||||
self.render_task_texture.deinit(&mut self.device);
|
self.render_task_texture.deinit(&mut self.device);
|
||||||
self.device.delete_pbo(self.texture_cache_upload_pbo);
|
self.device.delete_pbo(self.texture_cache_upload_pbo);
|
||||||
self.texture_resolver.deinit(&mut self.device);
|
self.texture_resolver.deinit(&mut self.device);
|
||||||
|
@ -4017,11 +4040,11 @@ pub trait SceneBuilderHooks {
|
||||||
/// and before it processes anything.
|
/// and before it processes anything.
|
||||||
fn register(&self);
|
fn register(&self);
|
||||||
/// This is called before each scene swap occurs.
|
/// This is called before each scene swap occurs.
|
||||||
fn pre_scene_swap(&self);
|
fn pre_scene_swap(&self, scenebuild_time: u64);
|
||||||
/// This is called after each scene swap occurs. The PipelineInfo contains
|
/// This is called after each scene swap occurs. The PipelineInfo contains
|
||||||
/// the updated epochs and pipelines removed in the new scene compared to
|
/// the updated epochs and pipelines removed in the new scene compared to
|
||||||
/// the old scene.
|
/// the old scene.
|
||||||
fn post_scene_swap(&self, info: PipelineInfo);
|
fn post_scene_swap(&self, info: PipelineInfo, sceneswap_time: u64);
|
||||||
/// This is called after a resource update operation on the scene builder
|
/// This is called after a resource update operation on the scene builder
|
||||||
/// thread, in the case where resource updates were applied without a scene
|
/// thread, in the case where resource updates were applied without a scene
|
||||||
/// build.
|
/// build.
|
||||||
|
@ -4078,6 +4101,7 @@ pub struct RendererOptions {
|
||||||
pub disable_dual_source_blending: bool,
|
pub disable_dual_source_blending: bool,
|
||||||
pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>,
|
pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>,
|
||||||
pub sampler: Option<Box<AsyncPropertySampler + Send>>,
|
pub sampler: Option<Box<AsyncPropertySampler + Send>>,
|
||||||
|
pub chase_primitive: ChasePrimitive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RendererOptions {
|
impl Default for RendererOptions {
|
||||||
|
@ -4111,6 +4135,7 @@ impl Default for RendererOptions {
|
||||||
disable_dual_source_blending: false,
|
disable_dual_source_blending: false,
|
||||||
scene_builder_hooks: None,
|
scene_builder_hooks: None,
|
||||||
sampler: None,
|
sampler: None,
|
||||||
|
chase_primitive: ChasePrimitive::Nothing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,13 +641,20 @@ impl ResourceCache {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !self.pending_image_requests.insert(request) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are tiling, then we need to confirm the dirty rect intersects
|
||||||
|
// the tile before leaving the request in the pending queue.
|
||||||
|
//
|
||||||
// We can start a worker thread rasterizing right now, if:
|
// We can start a worker thread rasterizing right now, if:
|
||||||
// - The image is a blob.
|
// - The image is a blob.
|
||||||
// - The blob hasn't already been requested this frame.
|
// - The blob hasn't already been requested this frame.
|
||||||
if self.pending_image_requests.insert(request) && template.data.is_blob() {
|
if template.data.is_blob() || dirty_rect.is_some() {
|
||||||
let (offset, size) = match template.tiling {
|
let (offset, size) = match request.tile {
|
||||||
Some(tile_size) => {
|
Some(tile_offset) => {
|
||||||
let tile_offset = request.tile.unwrap();
|
let tile_size = template.tiling.unwrap();
|
||||||
let actual_size = compute_tile_size(
|
let actual_size = compute_tile_size(
|
||||||
&template.descriptor,
|
&template.descriptor,
|
||||||
tile_size,
|
tile_size,
|
||||||
|
@ -671,17 +678,19 @@ impl ResourceCache {
|
||||||
None => (DevicePoint::zero(), template.descriptor.size),
|
None => (DevicePoint::zero(), template.descriptor.size),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref mut renderer) = self.blob_image_renderer {
|
if template.data.is_blob() {
|
||||||
renderer.request(
|
if let Some(ref mut renderer) = self.blob_image_renderer {
|
||||||
&self.resources,
|
renderer.request(
|
||||||
request.into(),
|
&self.resources,
|
||||||
&BlobImageDescriptor {
|
request.into(),
|
||||||
size,
|
&BlobImageDescriptor {
|
||||||
offset,
|
size,
|
||||||
format: template.descriptor.format,
|
offset,
|
||||||
},
|
format: template.descriptor.format,
|
||||||
dirty_rect,
|
},
|
||||||
);
|
dirty_rect,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -923,6 +932,8 @@ impl ResourceCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
|
fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
|
||||||
|
let mut keys_to_clear_dirty_rect = FastHashSet::default();
|
||||||
|
|
||||||
for request in self.pending_image_requests.drain() {
|
for request in self.pending_image_requests.drain() {
|
||||||
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
|
let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
|
||||||
debug_assert!(image_template.data.uses_texture_cache());
|
debug_assert!(image_template.data.uses_texture_cache());
|
||||||
|
@ -963,23 +974,24 @@ impl ResourceCache {
|
||||||
|
|
||||||
let entry = self.cached_images.get_mut(&request).as_mut().unwrap();
|
let entry = self.cached_images.get_mut(&request).as_mut().unwrap();
|
||||||
let mut descriptor = image_template.descriptor.clone();
|
let mut descriptor = image_template.descriptor.clone();
|
||||||
//TODO: erasing the dirty rectangle here is incorrect for tiled images,
|
let local_dirty_rect;
|
||||||
// since other tile requests may follow that depend on it
|
|
||||||
let mut local_dirty_rect = image_template.dirty_rect.take();
|
|
||||||
|
|
||||||
if let Some(tile) = request.tile {
|
if let Some(tile) = request.tile {
|
||||||
let tile_size = image_template.tiling.unwrap();
|
let tile_size = image_template.tiling.unwrap();
|
||||||
let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
|
let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
|
||||||
|
|
||||||
if let Some(ref mut rect) = local_dirty_rect {
|
local_dirty_rect = if let Some(ref rect) = image_template.dirty_rect {
|
||||||
match intersect_for_tile(*rect, clipped_tile_size, tile_size, tile) {
|
keys_to_clear_dirty_rect.insert(request.key.clone());
|
||||||
Some(intersection) => *rect = intersection,
|
|
||||||
None => {
|
// We should either have a dirty rect, or we are re-uploading where the dirty
|
||||||
// if re-uploaded, the dirty rect is ignored anyway
|
// rect is ignored anyway.
|
||||||
debug_assert!(self.texture_cache.needs_upload(&entry.texture_cache_handle))
|
let intersection = intersect_for_tile(*rect, clipped_tile_size, tile_size, tile);
|
||||||
}
|
debug_assert!(intersection.is_some() ||
|
||||||
}
|
self.texture_cache.needs_upload(&entry.texture_cache_handle));
|
||||||
}
|
intersection
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// The tiled image could be stored on the CPU as one large image or be
|
// The tiled image could be stored on the CPU as one large image or be
|
||||||
// already broken up into tiles. This affects the way we compute the stride
|
// already broken up into tiles. This affects the way we compute the stride
|
||||||
|
@ -995,6 +1007,8 @@ impl ResourceCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor.size = clipped_tile_size;
|
descriptor.size = clipped_tile_size;
|
||||||
|
} else {
|
||||||
|
local_dirty_rect = image_template.dirty_rect.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = match request.rendering {
|
let filter = match request.rendering {
|
||||||
|
@ -1036,6 +1050,11 @@ impl ResourceCache {
|
||||||
UvRectKind::Rect,
|
UvRectKind::Rect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key in keys_to_clear_dirty_rect.drain() {
|
||||||
|
let image_template = self.resources.image_templates.get_mut(key).unwrap();
|
||||||
|
image_template.dirty_rect.take();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_frame(&mut self) {
|
pub fn end_frame(&mut self) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ use render_backend::DocumentView;
|
||||||
use renderer::{PipelineInfo, SceneBuilderHooks};
|
use renderer::{PipelineInfo, SceneBuilderHooks};
|
||||||
use scene::Scene;
|
use scene::Scene;
|
||||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
use time::precise_time_ns;
|
||||||
|
|
||||||
// Message from render backend to scene builder.
|
// Message from render backend to scene builder.
|
||||||
pub enum SceneBuilderRequest {
|
pub enum SceneBuilderRequest {
|
||||||
|
@ -137,6 +138,7 @@ impl SceneBuilder {
|
||||||
frame_ops,
|
frame_ops,
|
||||||
render,
|
render,
|
||||||
} => {
|
} => {
|
||||||
|
let scenebuild_start_time = precise_time_ns();
|
||||||
let built_scene = scene.map(|request|{
|
let built_scene = scene.map(|request|{
|
||||||
build_scene(&self.config, request)
|
build_scene(&self.config, request)
|
||||||
});
|
});
|
||||||
|
@ -156,13 +158,15 @@ impl SceneBuilder {
|
||||||
};
|
};
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
hooks.pre_scene_swap();
|
let scenebuild_time = precise_time_ns() - scenebuild_start_time;
|
||||||
|
hooks.pre_scene_swap(scenebuild_time);
|
||||||
|
|
||||||
(Some(info), Some(tx), Some(rx))
|
(Some(info), Some(tx), Some(rx))
|
||||||
}
|
}
|
||||||
_ => (None, None, None),
|
_ => (None, None, None),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let sceneswap_start_time = precise_time_ns();
|
||||||
let has_resources_updates = !resource_updates.is_empty();
|
let has_resources_updates = !resource_updates.is_empty();
|
||||||
self.tx.send(SceneBuilderResult::Transaction {
|
self.tx.send(SceneBuilderResult::Transaction {
|
||||||
document_id,
|
document_id,
|
||||||
|
@ -178,7 +182,8 @@ impl SceneBuilder {
|
||||||
if let Some(pipeline_info) = pipeline_info {
|
if let Some(pipeline_info) = pipeline_info {
|
||||||
// Block until the swap is done, then invoke the hook.
|
// Block until the swap is done, then invoke the hook.
|
||||||
let swap_result = result_rx.unwrap().recv();
|
let swap_result = result_rx.unwrap().recv();
|
||||||
self.hooks.as_ref().unwrap().post_scene_swap(pipeline_info);
|
let sceneswap_time = precise_time_ns() - sceneswap_start_time;
|
||||||
|
self.hooks.as_ref().unwrap().post_scene_swap(pipeline_info, sceneswap_time);
|
||||||
// Once the hook is done, allow the RB thread to resume
|
// Once the hook is done, allow the RB thread to resume
|
||||||
match swap_result {
|
match swap_result {
|
||||||
Ok(SceneSwapResult::Complete(resume_tx)) => {
|
Ok(SceneSwapResult::Complete(resume_tx)) => {
|
||||||
|
|
|
@ -351,11 +351,12 @@ fn create_prim_shader(
|
||||||
("sDither", TextureSampler::Dither),
|
("sDither", TextureSampler::Dither),
|
||||||
("sCacheA8", TextureSampler::CacheA8),
|
("sCacheA8", TextureSampler::CacheA8),
|
||||||
("sCacheRGBA8", TextureSampler::CacheRGBA8),
|
("sCacheRGBA8", TextureSampler::CacheRGBA8),
|
||||||
("sClipScrollNodes", TextureSampler::ClipScrollNodes),
|
("sTransformPalette", TextureSampler::TransformPalette),
|
||||||
("sRenderTasks", TextureSampler::RenderTasks),
|
("sRenderTasks", TextureSampler::RenderTasks),
|
||||||
("sResourceCache", TextureSampler::ResourceCache),
|
("sResourceCache", TextureSampler::ResourceCache),
|
||||||
("sSharedCacheA8", TextureSampler::SharedCacheA8),
|
("sSharedCacheA8", TextureSampler::SharedCacheA8),
|
||||||
("sLocalClipRects", TextureSampler::LocalClipRects),
|
("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
|
||||||
|
("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -379,11 +380,12 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result<Program
|
||||||
program,
|
program,
|
||||||
&[
|
&[
|
||||||
("sColor0", TextureSampler::Color0),
|
("sColor0", TextureSampler::Color0),
|
||||||
("sClipScrollNodes", TextureSampler::ClipScrollNodes),
|
("sTransformPalette", TextureSampler::TransformPalette),
|
||||||
("sRenderTasks", TextureSampler::RenderTasks),
|
("sRenderTasks", TextureSampler::RenderTasks),
|
||||||
("sResourceCache", TextureSampler::ResourceCache),
|
("sResourceCache", TextureSampler::ResourceCache),
|
||||||
("sSharedCacheA8", TextureSampler::SharedCacheA8),
|
("sSharedCacheA8", TextureSampler::SharedCacheA8),
|
||||||
("sLocalClipRects", TextureSampler::LocalClipRects),
|
("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
|
||||||
|
("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -501,6 +501,7 @@ impl TextureCache {
|
||||||
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
|
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
|
||||||
(ImageFormat::RGBAF32, _) |
|
(ImageFormat::RGBAF32, _) |
|
||||||
(ImageFormat::RG8, _) |
|
(ImageFormat::RG8, _) |
|
||||||
|
(ImageFormat::RGBAI32, _) |
|
||||||
(ImageFormat::R8, TextureFilter::Nearest) |
|
(ImageFormat::R8, TextureFilter::Nearest) |
|
||||||
(ImageFormat::R8, TextureFilter::Trilinear) |
|
(ImageFormat::R8, TextureFilter::Trilinear) |
|
||||||
(ImageFormat::BGRA8, TextureFilter::Trilinear) => unreachable!(),
|
(ImageFormat::BGRA8, TextureFilter::Trilinear) => unreachable!(),
|
||||||
|
@ -725,6 +726,7 @@ impl TextureCache {
|
||||||
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
|
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
|
||||||
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
|
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
|
||||||
(ImageFormat::RGBAF32, _) |
|
(ImageFormat::RGBAF32, _) |
|
||||||
|
(ImageFormat::RGBAI32, _) |
|
||||||
(ImageFormat::R8, TextureFilter::Nearest) |
|
(ImageFormat::R8, TextureFilter::Nearest) |
|
||||||
(ImageFormat::R8, TextureFilter::Trilinear) |
|
(ImageFormat::R8, TextureFilter::Trilinear) |
|
||||||
(ImageFormat::BGRA8, TextureFilter::Trilinear) |
|
(ImageFormat::BGRA8, TextureFilter::Trilinear) |
|
||||||
|
|
|
@ -12,8 +12,7 @@ use device::{FrameId, Texture};
|
||||||
#[cfg(feature = "pathfinder")]
|
#[cfg(feature = "pathfinder")]
|
||||||
use euclid::{TypedPoint2D, TypedVector2D};
|
use euclid::{TypedPoint2D, TypedVector2D};
|
||||||
use gpu_cache::{GpuCache};
|
use gpu_cache::{GpuCache};
|
||||||
use gpu_types::{BorderInstance, BlurDirection, BlurInstance};
|
use gpu_types::{BorderInstance, BlurDirection, BlurInstance, PrimitiveHeaders, TransformData, TransformPalette};
|
||||||
use gpu_types::{ClipScrollNodeData, ZBufferIdGenerator};
|
|
||||||
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
||||||
#[cfg(feature = "pathfinder")]
|
#[cfg(feature = "pathfinder")]
|
||||||
use pathfinder_partitioner::mesh::Mesh;
|
use pathfinder_partitioner::mesh::Mesh;
|
||||||
|
@ -48,7 +47,7 @@ pub struct RenderTargetContext<'a, 'rc> {
|
||||||
pub resource_cache: &'rc mut ResourceCache,
|
pub resource_cache: &'rc mut ResourceCache,
|
||||||
pub clip_scroll_tree: &'a ClipScrollTree,
|
pub clip_scroll_tree: &'a ClipScrollTree,
|
||||||
pub use_dual_source_blending: bool,
|
pub use_dual_source_blending: bool,
|
||||||
pub node_data: &'a [ClipScrollNodeData],
|
pub transforms: &'a TransformPalette,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||||
|
@ -103,6 +102,7 @@ pub trait RenderTarget {
|
||||||
_gpu_cache: &mut GpuCache,
|
_gpu_cache: &mut GpuCache,
|
||||||
_render_tasks: &mut RenderTaskTree,
|
_render_tasks: &mut RenderTaskTree,
|
||||||
_deferred_resolves: &mut Vec<DeferredResolve>,
|
_deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
|
_prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
// TODO(gw): It's a bit odd that we need the deferred resolves and mutable
|
// TODO(gw): It's a bit odd that we need the deferred resolves and mutable
|
||||||
|
@ -166,12 +166,19 @@ impl<T: RenderTarget> RenderTargetList<T> {
|
||||||
render_tasks: &mut RenderTaskTree,
|
render_tasks: &mut RenderTaskTree,
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
saved_index: Option<SavedTargetIndex>,
|
saved_index: Option<SavedTargetIndex>,
|
||||||
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
debug_assert_eq!(None, self.saved_index);
|
debug_assert_eq!(None, self.saved_index);
|
||||||
self.saved_index = saved_index;
|
self.saved_index = saved_index;
|
||||||
|
|
||||||
for target in &mut self.targets {
|
for target in &mut self.targets {
|
||||||
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
|
target.build(
|
||||||
|
ctx,
|
||||||
|
gpu_cache,
|
||||||
|
render_tasks,
|
||||||
|
deferred_resolves,
|
||||||
|
prim_headers,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +340,9 @@ impl RenderTarget for ColorRenderTarget {
|
||||||
gpu_cache: &mut GpuCache,
|
gpu_cache: &mut GpuCache,
|
||||||
render_tasks: &mut RenderTaskTree,
|
render_tasks: &mut RenderTaskTree,
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
let mut merged_batches = AlphaBatchContainer::new(None);
|
let mut merged_batches = AlphaBatchContainer::new(None);
|
||||||
let mut z_generator = ZBufferIdGenerator::new();
|
|
||||||
|
|
||||||
for task_id in &self.alpha_tasks {
|
for task_id in &self.alpha_tasks {
|
||||||
let task = &render_tasks[*task_id];
|
let task = &render_tasks[*task_id];
|
||||||
|
@ -358,7 +365,7 @@ impl RenderTarget for ColorRenderTarget {
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
render_tasks,
|
render_tasks,
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
&mut z_generator,
|
prim_headers,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(batch_container) = batch_builder.build(&mut merged_batches) {
|
if let Some(batch_container) = batch_builder.build(&mut merged_batches) {
|
||||||
|
@ -594,6 +601,7 @@ impl RenderTarget for AlphaRenderTarget {
|
||||||
ctx.resource_cache,
|
ctx.resource_cache,
|
||||||
gpu_cache,
|
gpu_cache,
|
||||||
clip_store,
|
clip_store,
|
||||||
|
ctx.transforms,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
RenderTaskKind::ClipRegion(ref task) => {
|
RenderTaskKind::ClipRegion(ref task) => {
|
||||||
|
@ -795,6 +803,7 @@ impl RenderPass {
|
||||||
render_tasks: &mut RenderTaskTree,
|
render_tasks: &mut RenderTaskTree,
|
||||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||||
clip_store: &ClipStore,
|
clip_store: &ClipStore,
|
||||||
|
prim_headers: &mut PrimitiveHeaders,
|
||||||
) {
|
) {
|
||||||
profile_scope!("RenderPass::build");
|
profile_scope!("RenderPass::build");
|
||||||
|
|
||||||
|
@ -811,7 +820,13 @@ impl RenderPass {
|
||||||
deferred_resolves,
|
deferred_resolves,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
target.build(ctx, gpu_cache, render_tasks, deferred_resolves);
|
target.build(
|
||||||
|
ctx,
|
||||||
|
gpu_cache,
|
||||||
|
render_tasks,
|
||||||
|
deferred_resolves,
|
||||||
|
prim_headers,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
|
RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
|
||||||
let is_shared_alpha = self.tasks.iter().any(|&task_id| {
|
let is_shared_alpha = self.tasks.iter().any(|&task_id| {
|
||||||
|
@ -911,8 +926,22 @@ impl RenderPass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
color.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_color);
|
color.build(
|
||||||
alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_alpha);
|
ctx,
|
||||||
|
gpu_cache,
|
||||||
|
render_tasks,
|
||||||
|
deferred_resolves,
|
||||||
|
saved_color,
|
||||||
|
prim_headers,
|
||||||
|
);
|
||||||
|
alpha.build(
|
||||||
|
ctx,
|
||||||
|
gpu_cache,
|
||||||
|
render_tasks,
|
||||||
|
deferred_resolves,
|
||||||
|
saved_alpha,
|
||||||
|
prim_headers,
|
||||||
|
);
|
||||||
alpha.is_shared = is_shared_alpha;
|
alpha.is_shared = is_shared_alpha;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -956,9 +985,9 @@ pub struct Frame {
|
||||||
#[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
|
#[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
|
||||||
pub profile_counters: FrameProfileCounters,
|
pub profile_counters: FrameProfileCounters,
|
||||||
|
|
||||||
pub node_data: Vec<ClipScrollNodeData>,
|
pub transform_palette: Vec<TransformData>,
|
||||||
pub clip_chain_local_clip_rects: Vec<LayoutRect>,
|
|
||||||
pub render_tasks: RenderTaskTree,
|
pub render_tasks: RenderTaskTree,
|
||||||
|
pub prim_headers: PrimitiveHeaders,
|
||||||
|
|
||||||
/// The GPU cache frame that the contents of Self depend on
|
/// The GPU cache frame that the contents of Self depend on
|
||||||
pub gpu_cache_frame_id: FrameId,
|
pub gpu_cache_frame_id: FrameId,
|
||||||
|
|
|
@ -1103,7 +1103,7 @@ pub struct DynamicProperties {
|
||||||
pub trait RenderNotifier: Send {
|
pub trait RenderNotifier: Send {
|
||||||
fn clone(&self) -> Box<RenderNotifier>;
|
fn clone(&self) -> Box<RenderNotifier>;
|
||||||
fn wake_up(&self);
|
fn wake_up(&self);
|
||||||
fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool);
|
fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>);
|
||||||
fn external_event(&self, _evt: ExternalEvent) {
|
fn external_event(&self, _evt: ExternalEvent) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ pub struct ColorU {
|
||||||
|
|
||||||
impl ColorU {
|
impl ColorU {
|
||||||
/// Constructs a new additive `ColorU` from its components.
|
/// Constructs a new additive `ColorU` from its components.
|
||||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> ColorU {
|
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||||
ColorU { r, g, b, a }
|
ColorU { r, g, b, a }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,22 +273,10 @@ pub enum RepeatMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct GradientBorder {
|
|
||||||
pub gradient: Gradient,
|
|
||||||
pub outset: SideOffsets2D<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
|
||||||
pub struct RadialGradientBorder {
|
|
||||||
pub gradient: RadialGradient,
|
|
||||||
pub outset: SideOffsets2D<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
|
||||||
/// TODO(mrobinson): Currently only images are supported, but we will
|
|
||||||
/// eventually add support for Gradient and RadialGradient.
|
|
||||||
pub enum NinePatchBorderSource {
|
pub enum NinePatchBorderSource {
|
||||||
Image(ImageKey),
|
Image(ImageKey),
|
||||||
|
Gradient(Gradient),
|
||||||
|
RadialGradient(RadialGradient),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
@ -333,8 +321,6 @@ pub struct NinePatchBorder {
|
||||||
pub enum BorderDetails {
|
pub enum BorderDetails {
|
||||||
Normal(NormalBorder),
|
Normal(NormalBorder),
|
||||||
NinePatch(NinePatchBorder),
|
NinePatch(NinePatchBorder),
|
||||||
Gradient(GradientBorder),
|
|
||||||
RadialGradient(RadialGradientBorder),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
|
|
|
@ -27,8 +27,8 @@ use {StickyFrameDisplayItem, StickyOffsetBounds, TextDisplayItem, TransformStyle
|
||||||
use {YuvData, YuvImageDisplayItem};
|
use {YuvData, YuvImageDisplayItem};
|
||||||
|
|
||||||
// We don't want to push a long text-run. If a text-run is too long, split it into several parts.
|
// We don't want to push a long text-run. If a text-run is too long, split it into several parts.
|
||||||
// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_PRIM_HEADER - VECS_PER_TEXT_RUN) * 2
|
// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2
|
||||||
pub const MAX_TEXT_RUN_LENGTH: usize = 2038;
|
pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
|
||||||
|
|
||||||
// We start at 2, because the root reference is always 0 and the root scroll node is always 1.
|
// We start at 2, because the root reference is always 0 and the root scroll node is always 1.
|
||||||
const FIRST_CLIP_ID: usize = 2;
|
const FIRST_CLIP_ID: usize = 2;
|
||||||
|
|
|
@ -59,6 +59,7 @@ pub enum ImageFormat {
|
||||||
BGRA8 = 3,
|
BGRA8 = 3,
|
||||||
RGBAF32 = 4,
|
RGBAF32 = 4,
|
||||||
RG8 = 5,
|
RG8 = 5,
|
||||||
|
RGBAI32 = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImageFormat {
|
impl ImageFormat {
|
||||||
|
@ -68,6 +69,7 @@ impl ImageFormat {
|
||||||
ImageFormat::BGRA8 => 4,
|
ImageFormat::BGRA8 => 4,
|
||||||
ImageFormat::RGBAF32 => 16,
|
ImageFormat::RGBAF32 => 16,
|
||||||
ImageFormat::RG8 => 2,
|
ImageFormat::RG8 => 2,
|
||||||
|
ImageFormat::RGBAI32 => 16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
cf98ad4d63729c678a7575eb9bce36794da5e270
|
cdfaaeb5f74e416f39af1081c9a676c752d23896
|
||||||
|
|
|
@ -93,6 +93,7 @@ enum class ImageFormat : uint32_t {
|
||||||
BGRA8 = 3,
|
BGRA8 = 3,
|
||||||
RGBAF32 = 4,
|
RGBAF32 = 4,
|
||||||
RG8 = 5,
|
RG8 = 5,
|
||||||
|
RGBAI32 = 6,
|
||||||
|
|
||||||
Sentinel /* this must be last for serialization purposes. */
|
Sentinel /* this must be last for serialization purposes. */
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ euclid = "0.17"
|
||||||
gleam = "0.5"
|
gleam = "0.5"
|
||||||
glutin = "0.15"
|
glutin = "0.15"
|
||||||
app_units = "0.6"
|
app_units = "0.6"
|
||||||
image = "0.18"
|
image = "0.19"
|
||||||
clap = { version = "2", features = ["yaml"] }
|
clap = { version = "2", features = ["yaml"] }
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
|
@ -67,6 +67,10 @@ args:
|
||||||
- no_batch:
|
- no_batch:
|
||||||
long: no-batch
|
long: no-batch
|
||||||
help: Disable batching of instanced draw calls
|
help: Disable batching of instanced draw calls
|
||||||
|
- chase:
|
||||||
|
long: chase
|
||||||
|
help: Chase a particular primitive matching the local rect
|
||||||
|
takes_value: true
|
||||||
|
|
||||||
subcommands:
|
subcommands:
|
||||||
- png:
|
- png:
|
||||||
|
|
|
@ -257,7 +257,7 @@ fn make_window(
|
||||||
})
|
})
|
||||||
.with_vsync(vsync);
|
.with_vsync(vsync);
|
||||||
let window_builder = winit::WindowBuilder::new()
|
let window_builder = winit::WindowBuilder::new()
|
||||||
.with_title("WRech")
|
.with_title("WRench")
|
||||||
.with_multitouch()
|
.with_multitouch()
|
||||||
.with_dimensions(size.width, size.height);
|
.with_dimensions(size.width, size.height);
|
||||||
|
|
||||||
|
@ -351,7 +351,11 @@ impl RenderNotifier for Notifier {
|
||||||
self.tx.send(NotifierEvent::ShutDown).unwrap();
|
self.tx.send(NotifierEvent::ShutDown).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) {
|
fn new_frame_ready(&self,
|
||||||
|
_: DocumentId,
|
||||||
|
_scrolled: bool,
|
||||||
|
composite_needed: bool,
|
||||||
|
_render_time: Option<u64>) {
|
||||||
if composite_needed {
|
if composite_needed {
|
||||||
self.wake_up();
|
self.wake_up();
|
||||||
}
|
}
|
||||||
|
@ -424,6 +428,20 @@ fn main() {
|
||||||
})
|
})
|
||||||
.unwrap_or(DeviceUintSize::new(1920, 1080));
|
.unwrap_or(DeviceUintSize::new(1920, 1080));
|
||||||
let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap());
|
let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap());
|
||||||
|
let chase_primitive = match args.value_of("chase") {
|
||||||
|
Some(s) => {
|
||||||
|
let mut items = s
|
||||||
|
.split(',')
|
||||||
|
.map(|s| s.parse::<f32>().unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let rect = LayoutRect::new(
|
||||||
|
LayoutPoint::new(items[0], items[1]),
|
||||||
|
LayoutSize::new(items[2], items[3]),
|
||||||
|
);
|
||||||
|
webrender::ChasePrimitive::LocalRect(rect)
|
||||||
|
},
|
||||||
|
None => webrender::ChasePrimitive::Nothing,
|
||||||
|
};
|
||||||
|
|
||||||
let mut events_loop = if args.is_present("headless") {
|
let mut events_loop = if args.is_present("headless") {
|
||||||
None
|
None
|
||||||
|
@ -462,6 +480,7 @@ fn main() {
|
||||||
args.is_present("precache"),
|
args.is_present("precache"),
|
||||||
args.is_present("slow_subpixel"),
|
args.is_present("slow_subpixel"),
|
||||||
zoom_factor.unwrap_or(1.0),
|
zoom_factor.unwrap_or(1.0),
|
||||||
|
chase_primitive,
|
||||||
notifier,
|
notifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -634,17 +653,30 @@ fn render<'a>(
|
||||||
let path = PathBuf::from("../captures/wrench");
|
let path = PathBuf::from("../captures/wrench");
|
||||||
wrench.api.save_capture(path, CaptureBits::all());
|
wrench.api.save_capture(path, CaptureBits::all());
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Up => {
|
VirtualKeyCode::Up | VirtualKeyCode::Down => {
|
||||||
|
let mut txn = Transaction::new();
|
||||||
|
|
||||||
|
let offset = match vk {
|
||||||
|
winit::VirtualKeyCode::Up => LayoutVector2D::new(0.0, 10.0),
|
||||||
|
winit::VirtualKeyCode::Down => LayoutVector2D::new(0.0, -10.0),
|
||||||
|
_ => unreachable!("Should not see non directional keys here.")
|
||||||
|
};
|
||||||
|
|
||||||
|
txn.scroll(ScrollLocation::Delta(offset), cursor_position);
|
||||||
|
txn.generate_frame();
|
||||||
|
wrench.api.send_transaction(wrench.document_id, txn);
|
||||||
|
|
||||||
|
do_frame = true;
|
||||||
|
}
|
||||||
|
VirtualKeyCode::Add => {
|
||||||
let current_zoom = wrench.get_page_zoom();
|
let current_zoom = wrench.get_page_zoom();
|
||||||
let new_zoom_factor = ZoomFactor::new(current_zoom.get() + 0.1);
|
let new_zoom_factor = ZoomFactor::new(current_zoom.get() + 0.1);
|
||||||
|
|
||||||
wrench.set_page_zoom(new_zoom_factor);
|
wrench.set_page_zoom(new_zoom_factor);
|
||||||
do_frame = true;
|
do_frame = true;
|
||||||
}
|
}
|
||||||
VirtualKeyCode::Down => {
|
VirtualKeyCode::Subtract => {
|
||||||
let current_zoom = wrench.get_page_zoom();
|
let current_zoom = wrench.get_page_zoom();
|
||||||
let new_zoom_factor = ZoomFactor::new((current_zoom.get() - 0.1).max(0.1));
|
let new_zoom_factor = ZoomFactor::new((current_zoom.get() - 0.1).max(0.1));
|
||||||
|
|
||||||
wrench.set_page_zoom(new_zoom_factor);
|
wrench.set_page_zoom(new_zoom_factor);
|
||||||
do_frame = true;
|
do_frame = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,10 @@ impl RenderNotifier for Notifier {
|
||||||
self.update(false);
|
self.update(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_frame_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) {
|
fn new_frame_ready(&self, _: DocumentId,
|
||||||
|
scrolled: bool,
|
||||||
|
_composite_needed: bool,
|
||||||
|
_render_time: Option<u64>) {
|
||||||
self.update(!scrolled);
|
self.update(!scrolled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +183,7 @@ impl Wrench {
|
||||||
precache_shaders: bool,
|
precache_shaders: bool,
|
||||||
disable_dual_source_blending: bool,
|
disable_dual_source_blending: bool,
|
||||||
zoom_factor: f32,
|
zoom_factor: f32,
|
||||||
|
chase_primitive: webrender::ChasePrimitive,
|
||||||
notifier: Option<Box<RenderNotifier>>,
|
notifier: Option<Box<RenderNotifier>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
println!("Shader override path: {:?}", shader_override_path);
|
println!("Shader override path: {:?}", shader_override_path);
|
||||||
|
@ -212,6 +216,7 @@ impl Wrench {
|
||||||
precache_shaders,
|
precache_shaders,
|
||||||
blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))),
|
blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))),
|
||||||
disable_dual_source_blending,
|
disable_dual_source_blending,
|
||||||
|
chase_primitive,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,8 @@ fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool {
|
||||||
}
|
}
|
||||||
ImageFormat::RG8 => true,
|
ImageFormat::RG8 => true,
|
||||||
ImageFormat::R8 => false,
|
ImageFormat::R8 => false,
|
||||||
ImageFormat::RGBAF32 => unreachable!(),
|
ImageFormat::RGBAF32 |
|
||||||
|
ImageFormat::RGBAI32 => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -880,26 +881,28 @@ impl YamlFrameReader {
|
||||||
radius,
|
radius,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
"image" => {
|
"image" | "gradient" | "radial-gradient" => {
|
||||||
let file = rsrc_path(&item["image-source"], &self.aux_dir);
|
|
||||||
let (image_key, _) = self
|
|
||||||
.add_or_get_image(&file, None, wrench);
|
|
||||||
let image_width = item["image-width"]
|
let image_width = item["image-width"]
|
||||||
.as_i64()
|
.as_i64()
|
||||||
.expect("border must have image-width");
|
.unwrap_or(info.rect.size.width as i64);
|
||||||
let image_height = item["image-height"]
|
let image_height = item["image-height"]
|
||||||
.as_i64()
|
.as_i64()
|
||||||
.expect("border must have image-height");
|
.unwrap_or(info.rect.size.height as i64);
|
||||||
let fill = item["fill"].as_bool().unwrap_or(false);
|
let fill = item["fill"].as_bool().unwrap_or(false);
|
||||||
let slice = item["slice"].as_vec_u32().expect("border must have slice");
|
|
||||||
let slice = broadcast(&slice, 4);
|
let slice = item["slice"].as_vec_u32();
|
||||||
|
let slice = match slice {
|
||||||
|
Some(slice) => broadcast(&slice, 4),
|
||||||
|
None => vec![widths.top as u32, widths.left as u32, widths.bottom as u32, widths.right as u32],
|
||||||
|
};
|
||||||
|
|
||||||
let outset = item["outset"]
|
let outset = item["outset"]
|
||||||
.as_vec_f32()
|
.as_vec_f32()
|
||||||
.expect("border must have outset");
|
.expect("border must have outset");
|
||||||
let outset = broadcast(&outset, 4);
|
let outset = broadcast(&outset, 4);
|
||||||
let repeat_horizontal = match item["repeat-horizontal"]
|
let repeat_horizontal = match item["repeat-horizontal"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.expect("border must have repeat-horizontal")
|
.unwrap_or("stretch")
|
||||||
{
|
{
|
||||||
"stretch" => RepeatMode::Stretch,
|
"stretch" => RepeatMode::Stretch,
|
||||||
"repeat" => RepeatMode::Repeat,
|
"repeat" => RepeatMode::Repeat,
|
||||||
|
@ -909,7 +912,7 @@ impl YamlFrameReader {
|
||||||
};
|
};
|
||||||
let repeat_vertical = match item["repeat-vertical"]
|
let repeat_vertical = match item["repeat-vertical"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.expect("border must have repeat-vertical")
|
.unwrap_or("stretch")
|
||||||
{
|
{
|
||||||
"stretch" => RepeatMode::Stretch,
|
"stretch" => RepeatMode::Stretch,
|
||||||
"repeat" => RepeatMode::Repeat,
|
"repeat" => RepeatMode::Repeat,
|
||||||
|
@ -917,8 +920,27 @@ impl YamlFrameReader {
|
||||||
"space" => RepeatMode::Space,
|
"space" => RepeatMode::Space,
|
||||||
s => panic!("Unknown box border image repeat mode {}", s),
|
s => panic!("Unknown box border image repeat mode {}", s),
|
||||||
};
|
};
|
||||||
|
let source = match border_type {
|
||||||
|
"image" => {
|
||||||
|
let file = rsrc_path(&item["image-source"], &self.aux_dir);
|
||||||
|
let (image_key, _) = self
|
||||||
|
.add_or_get_image(&file, None, wrench);
|
||||||
|
NinePatchBorderSource::Image(image_key)
|
||||||
|
}
|
||||||
|
"gradient" => {
|
||||||
|
let gradient = self.to_gradient(dl, item);
|
||||||
|
NinePatchBorderSource::Gradient(gradient)
|
||||||
|
}
|
||||||
|
"radial-gradient" => {
|
||||||
|
let gradient = self.to_radial_gradient(dl, item);
|
||||||
|
NinePatchBorderSource::RadialGradient(gradient)
|
||||||
|
|
||||||
|
}
|
||||||
|
_ => unreachable!("Unexpected border type"),
|
||||||
|
};
|
||||||
|
|
||||||
Some(BorderDetails::NinePatch(NinePatchBorder {
|
Some(BorderDetails::NinePatch(NinePatchBorder {
|
||||||
source: NinePatchBorderSource::Image(image_key),
|
source,
|
||||||
width: image_width as u32,
|
width: image_width as u32,
|
||||||
height: image_height as u32,
|
height: image_height as u32,
|
||||||
slice: SideOffsets2D::new(slice[0], slice[1], slice[2], slice[3]),
|
slice: SideOffsets2D::new(slice[0], slice[1], slice[2], slice[3]),
|
||||||
|
@ -928,28 +950,6 @@ impl YamlFrameReader {
|
||||||
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
|
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
"gradient" => {
|
|
||||||
let gradient = self.to_gradient(dl, item);
|
|
||||||
let outset = item["outset"]
|
|
||||||
.as_vec_f32()
|
|
||||||
.expect("borders must have outset");
|
|
||||||
let outset = broadcast(&outset, 4);
|
|
||||||
Some(BorderDetails::Gradient(GradientBorder {
|
|
||||||
gradient,
|
|
||||||
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
"radial-gradient" => {
|
|
||||||
let gradient = self.to_radial_gradient(dl, item);
|
|
||||||
let outset = item["outset"]
|
|
||||||
.as_vec_f32()
|
|
||||||
.expect("borders must have outset");
|
|
||||||
let outset = broadcast(&outset, 4);
|
|
||||||
Some(BorderDetails::RadialGradient(RadialGradientBorder {
|
|
||||||
gradient,
|
|
||||||
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unable to parse border {:?}", item);
|
println!("Unable to parse border {:?}", item);
|
||||||
None
|
None
|
||||||
|
@ -1391,7 +1391,7 @@ impl YamlFrameReader {
|
||||||
clip_rect,
|
clip_rect,
|
||||||
complex_clips,
|
complex_clips,
|
||||||
image_mask,
|
image_mask,
|
||||||
ScrollSensitivity::Script,
|
ScrollSensitivity::ScriptAndInputEvents,
|
||||||
);
|
);
|
||||||
if let Some(numeric_id) = numeric_id {
|
if let Some(numeric_id) = numeric_id {
|
||||||
self.add_clip_id_mapping(numeric_id, real_id);
|
self.add_clip_id_mapping(numeric_id, real_id);
|
||||||
|
|
|
@ -885,14 +885,35 @@ impl YamlFrameWriter {
|
||||||
details.outset.left,
|
details.outset.left,
|
||||||
];
|
];
|
||||||
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
||||||
str_node(&mut v, "border-type", "image");
|
|
||||||
|
|
||||||
match details.source {
|
match details.source {
|
||||||
NinePatchBorderSource::Image(image_key) => {
|
NinePatchBorderSource::Image(image_key) => {
|
||||||
|
str_node(&mut v, "border-type", "image");
|
||||||
if let Some(path) = self.path_for_image(image_key) {
|
if let Some(path) = self.path_for_image(image_key) {
|
||||||
path_node(&mut v, "image", &path);
|
path_node(&mut v, "image", &path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NinePatchBorderSource::Gradient(gradient) => {
|
||||||
|
str_node(&mut v, "gradient", "image");
|
||||||
|
point_node(&mut v, "start", &gradient.start_point);
|
||||||
|
point_node(&mut v, "end", &gradient.end_point);
|
||||||
|
let mut stops = vec![];
|
||||||
|
for stop in display_list.get(base.gradient_stops()) {
|
||||||
|
stops.push(Yaml::Real(stop.offset.to_string()));
|
||||||
|
stops.push(Yaml::String(color_to_string(stop.color)));
|
||||||
|
}
|
||||||
|
yaml_node(&mut v, "stops", Yaml::Array(stops));
|
||||||
|
bool_node(&mut v, "repeat", gradient.extend_mode == ExtendMode::Repeat);
|
||||||
|
}
|
||||||
|
NinePatchBorderSource::RadialGradient(gradient) => {
|
||||||
|
str_node(&mut v, "border-type", "radial-gradient");
|
||||||
|
radial_gradient_to_yaml(
|
||||||
|
&mut v,
|
||||||
|
&gradient,
|
||||||
|
base.gradient_stops(),
|
||||||
|
display_list
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32_node(&mut v, "image-width", details.width);
|
u32_node(&mut v, "image-width", details.width);
|
||||||
|
@ -924,59 +945,6 @@ impl YamlFrameWriter {
|
||||||
RepeatMode::Space => str_node(&mut v, "repeat-vertical", "space"),
|
RepeatMode::Space => str_node(&mut v, "repeat-vertical", "space"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
BorderDetails::Gradient(ref details) => {
|
|
||||||
let widths: Vec<f32> = vec![
|
|
||||||
item.widths.top,
|
|
||||||
item.widths.right,
|
|
||||||
item.widths.bottom,
|
|
||||||
item.widths.left,
|
|
||||||
];
|
|
||||||
let outset: Vec<f32> = vec![
|
|
||||||
details.outset.top,
|
|
||||||
details.outset.right,
|
|
||||||
details.outset.bottom,
|
|
||||||
details.outset.left,
|
|
||||||
];
|
|
||||||
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
|
||||||
str_node(&mut v, "border-type", "gradient");
|
|
||||||
point_node(&mut v, "start", &details.gradient.start_point);
|
|
||||||
point_node(&mut v, "end", &details.gradient.end_point);
|
|
||||||
let mut stops = vec![];
|
|
||||||
for stop in display_list.get(base.gradient_stops()) {
|
|
||||||
stops.push(Yaml::Real(stop.offset.to_string()));
|
|
||||||
stops.push(Yaml::String(color_to_string(stop.color)));
|
|
||||||
}
|
|
||||||
yaml_node(&mut v, "stops", Yaml::Array(stops));
|
|
||||||
bool_node(
|
|
||||||
&mut v,
|
|
||||||
"repeat",
|
|
||||||
details.gradient.extend_mode == ExtendMode::Repeat,
|
|
||||||
);
|
|
||||||
yaml_node(&mut v, "outset", f32_vec_yaml(&outset, true));
|
|
||||||
}
|
|
||||||
BorderDetails::RadialGradient(ref details) => {
|
|
||||||
let widths: Vec<f32> = vec![
|
|
||||||
item.widths.top,
|
|
||||||
item.widths.right,
|
|
||||||
item.widths.bottom,
|
|
||||||
item.widths.left,
|
|
||||||
];
|
|
||||||
let outset: Vec<f32> = vec![
|
|
||||||
details.outset.top,
|
|
||||||
details.outset.right,
|
|
||||||
details.outset.bottom,
|
|
||||||
details.outset.left,
|
|
||||||
];
|
|
||||||
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
|
|
||||||
str_node(&mut v, "border-type", "radial-gradient");
|
|
||||||
yaml_node(&mut v, "outset", f32_vec_yaml(&outset, true));
|
|
||||||
radial_gradient_to_yaml(
|
|
||||||
&mut v,
|
|
||||||
&details.gradient,
|
|
||||||
base.gradient_stops(),
|
|
||||||
display_list
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BoxShadow(item) => {
|
BoxShadow(item) => {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче