Bug 1465058 - Update webrender to commit 8e697f8cb1f1aab2e5f6b9b903eb7191340b10c5. r=Gankro

MozReview-Commit-ID: BakJj8upl1A

--HG--
extra : rebase_source : 977723b4c807e1ac4887c957ff72a2628b2367c1
This commit is contained in:
Kartikaya Gupta 2018-06-04 10:53:49 -04:00
Родитель 4dae1c8fc0
Коммит 0ffc26692e
33 изменённых файлов: 835 добавлений и 495 удалений

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

@ -35,9 +35,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -47,13 +47,20 @@ impl Example for App {
FilterOp::Opacity(PropertyBinding::Binding(self.opacity_key, self.opacity), self.opacity),
];
let info = LayoutPrimitiveInfo::new(bounds);
let reference_frame_id = builder.push_reference_frame(
&info,
Some(PropertyBinding::Binding(self.property_key, LayoutTransform::identity())),
None,
);
builder.push_clip_id(reference_frame_id);
let info = LayoutPrimitiveInfo::new(bounds);
builder.push_stacking_context(
&info,
None,
Some(PropertyBinding::Binding(self.property_key, LayoutTransform::identity())),
TransformStyle::Flat,
None,
MixBlendMode::Normal,
filters,
GlyphRasterSpace::Screen,
@ -73,6 +80,9 @@ impl Example for App {
builder.pop_clip_id();
builder.pop_stacking_context();
builder.pop_clip_id();
builder.pop_reference_frame();
}
fn on_event(&mut self, win_event: winit::WindowEvent, api: &RenderApi, document_id: DocumentId) -> bool {

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

@ -193,9 +193,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -251,9 +251,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
api::TransformStyle::Flat,
None,
api::MixBlendMode::Normal,
Vec::new(),
api::GlyphRasterSpace::Screen,

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

@ -69,7 +69,7 @@ impl App {
let document_id = api.add_document(size, layer);
let mut txn = Transaction::new();
txn.set_window_parameters(framebuffer_size, bounds, 1.0);
txn.set_window_parameters(framebuffer_size, bounds, device_pixel_ratio);
txn.set_root_pipeline(pipeline_id);
api.send_transaction(document_id, txn);
@ -114,9 +114,7 @@ impl Example for App {
builder.push_stacking_context(
&LayoutPrimitiveInfo::new(doc.content_rect),
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -102,9 +102,7 @@ impl App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,
@ -148,9 +146,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -40,9 +40,7 @@ impl Example for App {
sub_builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,
@ -62,13 +60,20 @@ impl Example for App {
);
api.send_transaction(document_id, txn);
let info = LayoutPrimitiveInfo::new(sub_bounds);
let reference_frame_id = builder.push_reference_frame(
&info,
Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
None,
);
builder.push_clip_id(reference_frame_id);
// And this is for the root pipeline
builder.push_stacking_context(
&info,
None,
Some(PropertyBinding::Binding(PropertyBindingKey::new(42), LayoutTransform::identity())),
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,
@ -77,6 +82,9 @@ impl Example for App {
builder.push_rect(&info, ColorF::new(1.0, 0.0, 0.0, 1.0));
builder.push_iframe(&info, sub_pipeline_id, false);
builder.pop_stacking_context();
builder.pop_clip_id();
builder.pop_reference_frame();
}
}

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

@ -42,9 +42,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -180,9 +180,7 @@ impl Window {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -35,9 +35,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,
@ -50,9 +48,7 @@ impl Example for App {
builder.push_stacking_context(
&LayoutPrimitiveInfo::new((10, 10).by(0, 0)),
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -94,9 +94,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -89,9 +89,7 @@ impl Example for App {
builder.push_stacking_context(
&info,
None,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new(),
GlyphRasterSpace::Screen,

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

@ -98,13 +98,3 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
}
#endif //WR_VERTEX_SHADER
#ifdef WR_FRAGMENT_SHADER
//Note: identical to prim_shared
float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}
#endif //WR_FRAGMENT_SHADER

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

@ -2,20 +2,58 @@
* 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/. */
#include shared,prim_shared,ellipse,shared_border
#include shared,ellipse
flat varying vec4 vColor0;
flat varying vec4 vColor1;
// For edges, the colors are the same. For corners, these
// are the colors of each edge making up the corner.
flat varying vec4 vColor0[2];
flat varying vec4 vColor1[2];
// A point + tangent defining the line where the edge
// transition occurs. Used for corners only.
flat varying vec4 vColorLine;
flat varying int vFeatures;
flat varying vec2 vClipCenter;
flat varying vec4 vClipRadii;
flat varying vec2 vClipSign;
// x = segment, y = styles, z = edge axes
flat varying ivec3 vConfig;
// xy = Local space position of the clip center.
// zw = Scale the rect origin by this to get the outer
// corner from the segment rectangle.
flat varying vec4 vClipCenter_Sign;
// An outer and inner elliptical radii for border
// corner clipping.
flat varying vec4 vClipRadii;
// Reference point for determine edge clip lines.
flat varying vec4 vEdgeReference;
// Stores widths/2 and widths/3 to save doing this in FS.
flat varying vec4 vPartialWidths;
// Local space position
varying vec2 vPos;
#define CLIP_RADII 1
#define MIX_COLOR 2
#define SEGMENT_TOP_LEFT 0
#define SEGMENT_TOP_RIGHT 1
#define SEGMENT_BOTTOM_RIGHT 2
#define SEGMENT_BOTTOM_LEFT 3
#define SEGMENT_LEFT 4
#define SEGMENT_TOP 5
#define SEGMENT_RIGHT 6
#define SEGMENT_BOTTOM 7
// Border styles as defined in webrender_api/types.rs
#define BORDER_STYLE_NONE 0
#define BORDER_STYLE_SOLID 1
#define BORDER_STYLE_DOUBLE 2
#define BORDER_STYLE_DOTTED 3
#define BORDER_STYLE_DASHED 4
#define BORDER_STYLE_HIDDEN 5
#define BORDER_STYLE_GROOVE 6
#define BORDER_STYLE_RIDGE 7
#define BORDER_STYLE_INSET 8
#define BORDER_STYLE_OUTSET 9
#ifdef WR_VERTEX_SHADER
@ -27,15 +65,6 @@ in int aFlags;
in vec2 aWidths;
in vec2 aRadii;
#define SEGMENT_TOP_LEFT 0
#define SEGMENT_TOP_RIGHT 1
#define SEGMENT_BOTTOM_RIGHT 2
#define SEGMENT_BOTTOM_LEFT 3
#define SEGMENT_LEFT 4
#define SEGMENT_TOP 5
#define SEGMENT_RIGHT 6
#define SEGMENT_BOTTOM 7
vec2 get_outer_corner_scale(int segment) {
vec2 p;
@ -61,67 +90,252 @@ vec2 get_outer_corner_scale(int segment) {
return p;
}
void main(void) {
vec2 pos = aRect.xy + aRect.zw * aPosition.xy;
vec4 mod_color(vec4 color, float f) {
return vec4(clamp(color.rgb * f, vec3(0.0), vec3(color.a)), color.a);
}
int segment = aFlags & 0xff;
int style = (aFlags >> 8) & 0xff;
vec4[2] get_colors_for_side(vec4 color, int style) {
vec4 result[2];
const vec2 f = vec2(1.3, 0.7);
vec2 outer_scale = get_outer_corner_scale(segment);
vec2 outer = aRect.xy + outer_scale * aRect.zw;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
vColor0 = aColor0;
vColor1 = aColor1;
vPos = pos;
vFeatures = 0;
vClipSign = clip_sign;
vClipCenter = outer + clip_sign * aRadii;
vClipRadii = vec4(aRadii, aRadii - aWidths);
vColorLine = vec4(0.0);
switch (segment) {
case SEGMENT_TOP_LEFT:
case SEGMENT_TOP_RIGHT:
case SEGMENT_BOTTOM_RIGHT:
case SEGMENT_BOTTOM_LEFT:
vFeatures |= (CLIP_RADII | MIX_COLOR);
vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
switch (style) {
case BORDER_STYLE_GROOVE:
result[0] = mod_color(color, f.x);
result[1] = mod_color(color, f.y);
break;
case BORDER_STYLE_RIDGE:
result[0] = mod_color(color, f.y);
result[1] = mod_color(color, f.x);
break;
default:
result[0] = color;
result[1] = color;
break;
}
gl_Position = uTransform * vec4(aTaskOrigin + pos, 0.0, 1.0);
return result;
}
void main(void) {
int segment = aFlags & 0xff;
int style0 = (aFlags >> 8) & 0xff;
int style1 = (aFlags >> 16) & 0xff;
vec2 outer_scale = get_outer_corner_scale(segment);
vec2 outer = outer_scale * aRect.zw;
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
// Set some flags used by the FS to determine the
// orientation of the two edges in this corner.
ivec2 edge_axis;
// Derive the positions for the edge clips, which must be handled
// differently between corners and edges.
vec2 edge_reference;
switch (segment) {
case SEGMENT_TOP_LEFT:
edge_axis = ivec2(0, 1);
edge_reference = outer;
break;
case SEGMENT_TOP_RIGHT:
edge_axis = ivec2(1, 0);
edge_reference = vec2(outer.x - aWidths.x, outer.y);
break;
case SEGMENT_BOTTOM_RIGHT:
edge_axis = ivec2(0, 1);
edge_reference = outer - aWidths;
break;
case SEGMENT_BOTTOM_LEFT:
edge_axis = ivec2(1, 0);
edge_reference = vec2(outer.x, outer.y - aWidths.y);
break;
case SEGMENT_TOP:
case SEGMENT_BOTTOM:
edge_axis = ivec2(1, 1);
edge_reference = vec2(0.0);
break;
case SEGMENT_LEFT:
case SEGMENT_RIGHT:
default:
edge_axis = ivec2(0, 0);
edge_reference = vec2(0.0);
break;
}
vConfig = ivec3(
segment,
style0 | (style1 << 16),
edge_axis.x | (edge_axis.y << 16)
);
vPartialWidths = vec4(aWidths / 3.0, aWidths / 2.0);
vPos = aRect.zw * aPosition.xy;
vColor0 = get_colors_for_side(aColor0, style0);
vColor1 = get_colors_for_side(aColor1, style1);
vClipCenter_Sign = vec4(outer + clip_sign * aRadii, clip_sign);
vClipRadii = vec4(aRadii, max(aRadii - aWidths, 0.0));
vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
vEdgeReference = vec4(edge_reference, edge_reference + aWidths);
gl_Position = uTransform * vec4(aTaskOrigin + aRect.xy + vPos, 0.0, 1.0);
}
#endif
#ifdef WR_FRAGMENT_SHADER
vec4 evaluate_color_for_style_in_corner(
vec2 clip_relative_pos,
int style,
vec4 color[2],
vec4 clip_radii,
float mix_factor,
int segment,
float aa_range
) {
switch (style) {
case BORDER_STYLE_DOUBLE: {
// Get the distances from 0.33 of the radii, and
// also 0.67 of the radii. Use these to form a
// SDF subtraction which will clip out the inside
// third of the rounded edge.
float d_radii_a = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.xy,
aa_range
);
float d_radii_b = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - 2.0 * vPartialWidths.xy,
aa_range
);
float d = min(-d_radii_a, d_radii_b);
float alpha = distance_aa(aa_range, d);
return alpha * color[0];
}
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE: {
float d = distance_to_ellipse(
clip_relative_pos,
clip_radii.xy - vPartialWidths.zw,
aa_range
);
float alpha = distance_aa(aa_range, d);
float swizzled_factor;
switch (segment) {
case SEGMENT_TOP_LEFT: swizzled_factor = 0.0; break;
case SEGMENT_TOP_RIGHT: swizzled_factor = mix_factor; break;
case SEGMENT_BOTTOM_RIGHT: swizzled_factor = 1.0; break;
case SEGMENT_BOTTOM_LEFT: swizzled_factor = 1.0 - mix_factor; break;
default: swizzled_factor = 0.0; break;
};
vec4 c0 = mix(color[1], color[0], swizzled_factor);
vec4 c1 = mix(color[0], color[1], swizzled_factor);
return mix(c0, c1, alpha);
}
default:
break;
}
return color[0];
}
vec4 evaluate_color_for_style_in_edge(
vec2 pos,
int style,
vec4 color[2],
float aa_range,
int edge_axis
) {
switch (style) {
case BORDER_STYLE_DOUBLE: {
float d0 = -1.0;
float d1 = -1.0;
if (vPartialWidths[edge_axis] > 1.0) {
vec2 ref = vec2(
vEdgeReference[edge_axis] + vPartialWidths[edge_axis],
vEdgeReference[edge_axis+2] - vPartialWidths[edge_axis]
);
d0 = pos[edge_axis] - ref.x;
d1 = ref.y - pos[edge_axis];
}
float d = min(d0, d1);
float alpha = distance_aa(aa_range, d);
return alpha * color[0];
}
case BORDER_STYLE_GROOVE:
case BORDER_STYLE_RIDGE: {
float ref = vEdgeReference[edge_axis] + vPartialWidths[edge_axis+2];
float d = pos[edge_axis] - ref;
float alpha = distance_aa(aa_range, d);
return mix(color[0], color[1], alpha);
}
default:
break;
}
return color[0];
}
void main(void) {
float aa_range = compute_aa_range(vPos);
float d = -1.0;
vec4 color0, color1;
int segment = vConfig.x;
ivec2 style = ivec2(vConfig.y & 0xffff, vConfig.y >> 16);
ivec2 edge_axis = ivec2(vConfig.z & 0xffff, vConfig.z >> 16);
// Apply color mix
float mix_factor = 0.0;
if ((vFeatures & MIX_COLOR) != 0) {
if (edge_axis.x != edge_axis.y) {
float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos);
mix_factor = distance_aa(aa_range, -d_line);
}
// Apply clip radii
if ((vFeatures & CLIP_RADII) != 0) {
vec2 p = vPos - vClipCenter;
if (vClipSign.x * p.x < 0.0 && vClipSign.y * p.y < 0.0) {
float d_radii_a = distance_to_ellipse(p, vClipRadii.xy, aa_range);
float d_radii_b = distance_to_ellipse(p, vClipRadii.zw, aa_range);
// Check if inside corner clip-region
vec2 clip_relative_pos = vPos - vClipCenter_Sign.xy;
bool in_clip_region = all(lessThan(vClipCenter_Sign.zw * clip_relative_pos, vec2(0.0)));
if (in_clip_region) {
float d_radii_a = distance_to_ellipse(clip_relative_pos, vClipRadii.xy, aa_range);
float d_radii_b = distance_to_ellipse(clip_relative_pos, vClipRadii.zw, aa_range);
float d_radii = max(d_radii_a, -d_radii_b);
d = max(d, d_radii);
}
color0 = evaluate_color_for_style_in_corner(
clip_relative_pos,
style.x,
vColor0,
vClipRadii,
mix_factor,
segment,
aa_range
);
color1 = evaluate_color_for_style_in_corner(
clip_relative_pos,
style.y,
vColor1,
vClipRadii,
mix_factor,
segment,
aa_range
);
} else {
color0 = evaluate_color_for_style_in_edge(
vPos,
style.x,
vColor0,
aa_range,
edge_axis.x
);
color1 = evaluate_color_for_style_in_edge(
vPos,
style.y,
vColor1,
aa_range,
edge_axis.y
);
}
float alpha = distance_aa(aa_range, d);
vec4 color = mix(vColor0, vColor1, mix_factor);
vec4 color = mix(color0, color1, mix_factor);
oFragColor = color * alpha;
}
#endif

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

@ -25,11 +25,6 @@ vec2 clamp_rect(vec2 pt, RectWithSize rect) {
return clamp(pt, rect.p0, rect.p0 + rect.size);
}
float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}
// TODO: convert back to RectWithEndPoint if driver issues are resolved, if ever.
flat varying vec4 vClipMaskUvBounds;
varying vec3 vClipMaskUv;

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

@ -56,6 +56,61 @@
#else
out vec4 oFragColor;
#endif
#define EPSILON 0.0001
float distance_to_line(vec2 p0, vec2 perp_dir, vec2 p) {
vec2 dir_to_p0 = p0 - p;
return dot(normalize(perp_dir), dir_to_p0);
}
/// Find the appropriate half range to apply the AA approximation over.
/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
float compute_aa_range(vec2 position) {
// The constant factor is chosen to compensate for the fact that length(fw) is equal
// to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
//
// This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
// the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
// such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
// curves properly connect with non-antialiased vertical or horizontal lines, among other things.
//
// Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
// indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
// a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
// aliased corner and a straight edge.
//
// We may want to adjust this constant in specific scenarios (for example keep the principled
// value for straight edges where we want pixel-perfect equivalence with non antialiased lines
// when axis aligned, while selecting a larger and smoother aa range on curves).
return 0.35355 * length(fwidth(position));
}
/// Return the blending coefficient for distance antialiasing.
///
/// 0.0 means inside the shape, 1.0 means outside.
///
/// This cubic polynomial approximates the area of a 1x1 pixel square under a
/// line, given the signed Euclidean distance from the center of the square to
/// that line. Calculating the *exact* area would require taking into account
/// not only this distance but also the angle of the line. However, in
/// practice, this complexity is not required, as the area is roughly the same
/// regardless of the angle.
///
/// The coefficients of this polynomial were determined through least-squares
/// regression and are accurate to within 2.16% of the total area of the pixel
/// square 95% of the time, with a maximum error of 3.53%.
///
/// See the comments in `compute_aa_range()` for more information on the
/// cutoff values of -0.5 and 0.5.
float distance_aa(float aa_range, float signed_distance) {
float dist = 0.5 * signed_distance / aa_range;
if (dist <= -0.5 + EPSILON)
return 1.0;
if (dist >= 0.5 - EPSILON)
return 0.0;
return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
}
#endif
//======================================================================================

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

@ -2,8 +2,6 @@
* 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
// Border styles as defined in webrender_api/types.rs
#define BORDER_STYLE_NONE 0
#define BORDER_STYLE_SOLID 1
@ -16,6 +14,8 @@
#define BORDER_STYLE_INSET 8
#define BORDER_STYLE_OUTSET 9
#ifdef WR_VERTEX_SHADER
struct Border {
vec4 style;
vec4 widths;

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

@ -2,8 +2,6 @@
* 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/. */
#define EPSILON 0.0001
flat varying vec4 vTransformBounds;
#ifdef WR_VERTEX_SHADER
@ -16,54 +14,6 @@ void init_transform_vs(vec4 local_bounds) {
#ifdef WR_FRAGMENT_SHADER
/// Find the appropriate half range to apply the AA approximation over.
/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
float compute_aa_range(vec2 position) {
// The constant factor is chosen to compensate for the fact that length(fw) is equal
// to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
//
// This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
// the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
// such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
// curves properly connect with non-antialiased vertical or horizontal lines, among other things.
//
// Lines over a half-pixel away from the pixel center *can* intersect with the pixel square;
// indeed, unless they are horizontal or vertical, they are guaranteed to. However, choosing
// a nonzero area for such pixels causes noticeable artifacts at the junction between an anti-
// aliased corner and a straight edge.
//
// We may want to adjust this constant in specific scenarios (for example keep the principled
// value for straight edges where we want pixel-perfect equivalence with non antialiased lines
// when axis aligned, while selecting a larger and smoother aa range on curves).
return 0.35355 * length(fwidth(position));
}
/// Return the blending coefficient for distance antialiasing.
///
/// 0.0 means inside the shape, 1.0 means outside.
///
/// This cubic polynomial approximates the area of a 1x1 pixel square under a
/// line, given the signed Euclidean distance from the center of the square to
/// that line. Calculating the *exact* area would require taking into account
/// not only this distance but also the angle of the line. However, in
/// practice, this complexity is not required, as the area is roughly the same
/// regardless of the angle.
///
/// The coefficients of this polynomial were determined through least-squares
/// regression and are accurate to within 2.16% of the total area of the pixel
/// square 95% of the time, with a maximum error of 3.53%.
///
/// See the comments in `compute_aa_range()` for more information on the
/// cutoff values of -0.5 and 0.5.
float distance_aa(float aa_range, float signed_distance) {
float dist = 0.5 * signed_distance / aa_range;
if (dist <= -0.5 + EPSILON)
return 1.0;
if (dist >= 0.5 - EPSILON)
return 0.0;
return 0.5 + dist * (0.8431027 * dist * dist - 1.14453603);
}
float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
vec2 d = max(p0 - pos, pos - p1);
return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));

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

@ -471,16 +471,16 @@ impl<'a> DisplayListFlattener<'a> {
BorderStyle::Solid |
BorderStyle::Hidden |
BorderStyle::None |
BorderStyle::Double |
BorderStyle::Inset |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Outset => {
true
}
BorderStyle::Double |
BorderStyle::Dotted |
BorderStyle::Dashed |
BorderStyle::Groove |
BorderStyle::Ridge => {
BorderStyle::Dashed => {
false
}
}
@ -1015,10 +1015,17 @@ impl DotInfo {
}
}
#[derive(Debug)]
pub struct BorderSegmentInfo {
task_rect: DeviceRect,
segment: BorderSegment,
radius: DeviceSize,
widths: DeviceSize,
}
#[derive(Debug)]
pub struct BorderRenderTaskInfo {
pub instances: Vec<BorderInstance>,
pub segments: Vec<BrushSegment>,
pub border_segments: Vec<BorderSegmentInfo>,
pub size: DeviceIntSize,
}
@ -1028,9 +1035,9 @@ impl BorderRenderTaskInfo {
border: &NormalBorder,
widths: &BorderWidths,
scale: LayoutToDeviceScale,
brush_segments: &mut Vec<BrushSegment>,
) -> Self {
let mut instances = Vec::new();
let mut segments = Vec::new();
let mut border_segments = Vec::new();
let dp_width_top = (widths.top * scale.0).ceil();
let dp_width_bottom = (widths.bottom * scale.0).ceil();
@ -1088,15 +1095,6 @@ impl BorderRenderTaskInfo {
dp_size_tl.height.max(dp_size_tr.height) + height_inner + dp_size_bl.height.max(dp_size_br.height),
);
// These modulate colors are not part of the specification. They
// are derived from the Gecko source code and experimentation, and
// used to modulate the colors in order to generate colors for
// the inset/outset and groove/ridge border styles.
let left_color = border.left.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
let top_color = border.top.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
let right_color = border.right.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
let bottom_color = border.bottom.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
add_edge_segment(
LayoutRect::from_floats(
rect.origin.x,
@ -1110,13 +1108,12 @@ impl BorderRenderTaskInfo {
dp_width_left,
size.height - dp_size_bl.height,
),
border.left.style,
left_color,
&border.left,
BorderSegment::Left,
EdgeAaSegmentMask::LEFT | EdgeAaSegmentMask::RIGHT,
&mut instances,
&mut border_segments,
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
&mut segments,
brush_segments,
);
add_edge_segment(
@ -1132,13 +1129,12 @@ impl BorderRenderTaskInfo {
size.width - dp_size_tr.width,
dp_width_top,
),
border.top.style,
top_color,
&border.top,
BorderSegment::Top,
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::BOTTOM,
&mut instances,
&mut border_segments,
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
&mut segments,
brush_segments,
);
add_edge_segment(
@ -1154,13 +1150,12 @@ impl BorderRenderTaskInfo {
size.width,
size.height - dp_size_br.height,
),
border.right.style,
right_color,
&border.right,
BorderSegment::Right,
EdgeAaSegmentMask::RIGHT | EdgeAaSegmentMask::LEFT,
&mut instances,
&mut border_segments,
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
&mut segments,
brush_segments,
);
add_edge_segment(
@ -1176,13 +1171,12 @@ impl BorderRenderTaskInfo {
size.width - dp_size_br.width,
size.height,
),
border.bottom.style,
bottom_color,
&border.bottom,
BorderSegment::Bottom,
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::TOP,
&mut instances,
&mut border_segments,
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
&mut segments,
brush_segments,
);
add_corner_segment(
@ -1198,16 +1192,14 @@ impl BorderRenderTaskInfo {
dp_size_tl.width,
dp_size_tl.height,
),
border.left.style,
left_color,
border.top.style,
top_color,
&border.left,
&border.top,
DeviceSize::new(dp_width_left, dp_width_top),
dp_corner_tl,
BorderSegment::TopLeft,
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::LEFT,
&mut instances,
&mut segments,
&mut border_segments,
brush_segments,
);
add_corner_segment(
@ -1223,16 +1215,14 @@ impl BorderRenderTaskInfo {
size.width,
dp_size_tr.height,
),
border.top.style,
top_color,
border.right.style,
right_color,
&border.top,
&border.right,
DeviceSize::new(dp_width_right, dp_width_top),
dp_corner_tr,
BorderSegment::TopRight,
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::RIGHT,
&mut instances,
&mut segments,
&mut border_segments,
brush_segments,
);
add_corner_segment(
@ -1248,16 +1238,14 @@ impl BorderRenderTaskInfo {
size.width,
size.height,
),
border.right.style,
right_color,
border.bottom.style,
bottom_color,
&border.right,
&border.bottom,
DeviceSize::new(dp_width_right, dp_width_bottom),
dp_corner_br,
BorderSegment::BottomRight,
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::RIGHT,
&mut instances,
&mut segments,
&mut border_segments,
brush_segments,
);
add_corner_segment(
@ -1273,24 +1261,82 @@ impl BorderRenderTaskInfo {
dp_size_bl.width,
size.height,
),
border.bottom.style,
bottom_color,
border.left.style,
left_color,
&border.bottom,
&border.left,
DeviceSize::new(dp_width_left, dp_width_bottom),
dp_corner_bl,
BorderSegment::BottomLeft,
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::LEFT,
&mut instances,
&mut segments,
&mut border_segments,
brush_segments,
);
BorderRenderTaskInfo {
segments,
instances,
border_segments,
size: size.to_i32(),
}
}
pub fn build_instances(
&self,
border: &NormalBorder,
) -> Vec<BorderInstance> {
let mut instances = Vec::new();
for info in &self.border_segments {
let (side0, side1, flip0, flip1) = match info.segment {
BorderSegment::Left => (&border.left, &border.left, false, false),
BorderSegment::Top => (&border.top, &border.top, false, false),
BorderSegment::Right => (&border.right, &border.right, true, true),
BorderSegment::Bottom => (&border.bottom, &border.bottom, true, true),
BorderSegment::TopLeft => (&border.left, &border.top, false, false),
BorderSegment::TopRight => (&border.top, &border.right, false, true),
BorderSegment::BottomRight => (&border.right, &border.bottom, true, true),
BorderSegment::BottomLeft => (&border.bottom, &border.left, true, false),
};
let style0 = if side0.style.is_hidden() {
side1.style
} else {
side0.style
};
let style1 = if side1.style.is_hidden() {
side0.style
} else {
side1.style
};
// These modulate colors are not part of the specification. They
// are derived from the Gecko source code and experimentation, and
// used to modulate the colors in order to generate colors for
// the inset/outset and groove/ridge border styles.
let color0 = if flip0 {
side0.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
} else {
side0.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
};
let color1 = if flip1 {
side1.border_color(2.0 / 3.0, 1.0, 0.7, 0.3)
} else {
side1.border_color(1.0, 2.0 / 3.0, 0.3, 0.7)
};
add_segment(
info.task_rect,
style0,
style1,
color0,
color1,
info.segment,
&mut instances,
info.widths,
info.radius,
);
}
instances
}
}
fn add_brush_segment(
@ -1347,23 +1393,16 @@ fn add_segment(
fn add_corner_segment(
image_rect: LayoutRect,
task_rect: DeviceRect,
mut style0: BorderStyle,
color0: ColorF,
mut style1: BorderStyle,
color1: ColorF,
side0: &BorderSide,
side1: &BorderSide,
widths: DeviceSize,
radius: DeviceSize,
segment: BorderSegment,
edge_flags: EdgeAaSegmentMask,
instances: &mut Vec<BorderInstance>,
border_segments: &mut Vec<BorderSegmentInfo>,
brush_segments: &mut Vec<BrushSegment>,
) {
// TODO(gw): This will need to be a bit more involved when
// we support other border types here. For example,
// groove / ridge borders will always need to
// use two instances.
if color0.a <= 0.0 && color1.a <= 0.0 {
if side0.color.a <= 0.0 && side1.color.a <= 0.0 {
return;
}
@ -1371,31 +1410,16 @@ fn add_corner_segment(
return;
}
let style0_hidden = style0 == BorderStyle::Hidden || style0 == BorderStyle::None;
let style1_hidden = style1 == BorderStyle::Hidden || style1 == BorderStyle::None;
if style0_hidden && style1_hidden {
if side0.style.is_hidden() && side1.style.is_hidden() {
return;
}
if style0_hidden {
style0 = style1;
}
if style1_hidden {
style1 = style0;
}
add_segment(
border_segments.push(BorderSegmentInfo {
task_rect,
style0,
style1,
color0,
color1,
segment,
instances,
widths,
radius,
);
widths,
});
add_brush_segment(
image_rect,
@ -1409,33 +1433,27 @@ fn add_corner_segment(
fn add_edge_segment(
image_rect: LayoutRect,
task_rect: DeviceRect,
style: BorderStyle,
color: ColorF,
side: &BorderSide,
segment: BorderSegment,
edge_flags: EdgeAaSegmentMask,
instances: &mut Vec<BorderInstance>,
border_segments: &mut Vec<BorderSegmentInfo>,
brush_flags: BrushFlags,
brush_segments: &mut Vec<BrushSegment>,
) {
if color.a <= 0.0 {
if side.color.a <= 0.0 {
return;
}
if style == BorderStyle::Hidden || style == BorderStyle::None {
if side.style.is_hidden() {
return;
}
add_segment(
border_segments.push(BorderSegmentInfo {
task_rect,
style,
style,
color,
color,
segment,
instances,
DeviceSize::zero(),
DeviceSize::zero(),
);
radius: DeviceSize::zero(),
widths: task_rect.size,
});
add_brush_segment(
image_rect,

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

@ -8,10 +8,10 @@ use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, Devi
use api::{DevicePixelScale, DeviceUintRect, DisplayItemRef, Epoch, ExtendMode, ExternalScrollId};
use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, GradientStop};
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint};
use api::{LayoutPrimitiveInfo, LayoutRect, LayoutVector2D, LayoutSize, LayoutTransform};
use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
use api::{LineOrientation, LineStyle, LocalClip, NinePatchBorderSource, PipelineId};
use api::{PropertyBinding, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity, Shadow};
use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{TransformStyle, YuvColorSpace, YuvData};
use app_units::Au;
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
@ -157,10 +157,6 @@ pub struct DisplayListFlattener<'a> {
/// output textures.
output_pipelines: &'a FastHashSet<PipelineId>,
/// A list of replacements to make in order to properly handle fixed position
/// content as well as stacking contexts that create reference frames.
replacements: Vec<(ClipId, ClipId)>,
/// The data structure that converting between ClipId and the various index
/// types that the ClipScrollTree uses.
id_to_index_mapper: ClipIdToIndexMapper,
@ -225,7 +221,6 @@ impl<'a> DisplayListFlattener<'a> {
font_instances,
config: *frame_builder_config,
pipeline_epochs: Vec::new(),
replacements: Vec::new(),
output_pipelines,
id_to_index_mapper: ClipIdToIndexMapper::default(),
hit_testing_runs: recycle_vec(old_builder.hit_testing_runs),
@ -263,17 +258,6 @@ impl<'a> DisplayListFlattener<'a> {
)
}
/// Since WebRender still handles fixed position and reference frame content internally
/// we need to apply this table of id replacements only to the id that affects the
/// position of a node. We can eventually remove this when clients start handling
/// reference frames themselves. This method applies these replacements.
fn apply_scroll_frame_id_replacement(&self, index: ClipId) -> ClipId {
match self.replacements.last() {
Some(&(to_replace, replacement)) if to_replace == index => replacement,
_ => index,
}
}
fn get_complex_clips(
&self,
pipeline_id: PipelineId,
@ -282,14 +266,7 @@ impl<'a> DisplayListFlattener<'a> {
if complex_clips.is_empty() {
return vec![];
}
self.scene
.pipelines
.get(&pipeline_id)
.expect("No display list?")
.display_list
.get(complex_clips)
.collect()
self.scene.get_display_list_for_pipeline(pipeline_id).get(complex_clips).collect()
}
fn get_clip_chain_items(
@ -300,14 +277,7 @@ impl<'a> DisplayListFlattener<'a> {
if items.is_empty() {
return vec![];
}
self.scene
.pipelines
.get(&pipeline_id)
.expect("No display list?")
.display_list
.get(items)
.collect()
self.scene.get_display_list_for_pipeline(pipeline_id).get(items).collect()
}
fn flatten_root(&mut self, pipeline: &'a ScenePipeline, frame_size: &LayoutSize) {
@ -379,6 +349,10 @@ impl<'a> DisplayListFlattener<'a> {
None => break,
};
if SpecificDisplayItem::PopReferenceFrame == *item.item() {
return;
}
if SpecificDisplayItem::PopStackingContext == *item.item() {
return;
}
@ -462,15 +436,37 @@ impl<'a> DisplayListFlattener<'a> {
);
}
fn flatten_reference_frame(
&mut self,
traversal: &mut BuiltDisplayListIter<'a>,
pipeline_id: PipelineId,
item: &DisplayItemRef,
reference_frame: &ReferenceFrame,
scroll_node_id: ClipId,
reference_frame_relative_offset: LayoutVector2D,
) {
self.push_reference_frame(
reference_frame.id,
Some(scroll_node_id),
pipeline_id,
reference_frame.transform,
reference_frame.perspective,
reference_frame_relative_offset + item.rect().origin.to_vector(),
);
self.flatten_items(traversal, pipeline_id, LayoutVector2D::zero());
self.pop_reference_frame();
}
fn flatten_stacking_context(
&mut self,
traversal: &mut BuiltDisplayListIter<'a>,
pipeline_id: PipelineId,
item: &DisplayItemRef,
stacking_context: &StackingContext,
unreplaced_scroll_id: ClipId,
scroll_node_id: ClipId,
mut reference_frame_relative_offset: LayoutVector2D,
reference_frame_relative_offset: LayoutVector2D,
is_backface_visible: bool,
) {
// Avoid doing unnecessary work for empty stacking contexts.
@ -481,52 +477,20 @@ impl<'a> DisplayListFlattener<'a> {
let composition_operations = {
// TODO(optimization?): self.traversal.display_list()
let display_list = &self
.scene
.pipelines
.get(&pipeline_id)
.expect("No display list?!")
.display_list;
let display_list = self.scene.get_display_list_for_pipeline(pipeline_id);
CompositeOps::new(
stacking_context.filter_ops_for_compositing(display_list, item.filters()),
stacking_context.mix_blend_mode_for_compositing(),
)
};
let bounds = item.rect();
reference_frame_relative_offset += bounds.origin.to_vector();
// If we have a transformation or a perspective, we should have been assigned a new
// reference frame id. This means this stacking context establishes a new reference frame.
// Descendant fixed position content will be positioned relative to us.
if let Some(reference_frame_id) = stacking_context.reference_frame_id {
debug_assert!(
stacking_context.transform.is_some() ||
stacking_context.perspective.is_some()
);
self.push_reference_frame(
reference_frame_id,
Some(scroll_node_id),
pipeline_id,
stacking_context.transform,
stacking_context.perspective,
reference_frame_relative_offset,
);
self.replacements.push((unreplaced_scroll_id, reference_frame_id));
reference_frame_relative_offset = LayoutVector2D::zero();
}
// We apply the replacements one more time in case we need to set it to a replacement
// that we just pushed above.
let final_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id);
self.push_stacking_context(
pipeline_id,
composition_operations,
stacking_context.transform_style,
is_backface_visible,
false,
final_scroll_node,
scroll_node_id,
stacking_context.clip_node_id,
stacking_context.glyph_raster_space,
);
@ -534,14 +498,9 @@ impl<'a> DisplayListFlattener<'a> {
self.flatten_items(
traversal,
pipeline_id,
reference_frame_relative_offset,
reference_frame_relative_offset + item.rect().origin.to_vector(),
);
if stacking_context.reference_frame_id.is_some() {
self.replacements.pop();
self.pop_reference_frame();
}
self.pop_stacking_context();
}
@ -608,10 +567,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id: PipelineId,
reference_frame_relative_offset: LayoutVector2D,
) -> Option<BuiltDisplayListIter<'a>> {
let mut clip_and_scroll_ids = item.clip_and_scroll();
let unreplaced_scroll_id = clip_and_scroll_ids.scroll_node_id;
clip_and_scroll_ids.scroll_node_id =
self.apply_scroll_frame_id_replacement(clip_and_scroll_ids.scroll_node_id);
let clip_and_scroll_ids = item.clip_and_scroll();
let clip_and_scroll = self.id_to_index_mapper.map_clip_and_scroll(&clip_and_scroll_ids);
let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset);
@ -733,13 +689,25 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
&item,
&info.stacking_context,
unreplaced_scroll_id,
clip_and_scroll_ids.scroll_node_id,
reference_frame_relative_offset,
prim_info.is_backface_visible,
);
return Some(subtraversal);
}
SpecificDisplayItem::PushReferenceFrame(ref info) => {
let mut subtraversal = item.sub_iter();
self.flatten_reference_frame(
&mut subtraversal,
pipeline_id,
&item,
&info.reference_frame,
clip_and_scroll_ids.scroll_node_id,
reference_frame_relative_offset,
);
return Some(subtraversal);
}
SpecificDisplayItem::Iframe(ref info) => {
self.flatten_iframe(
&item,
@ -792,7 +760,7 @@ impl<'a> DisplayListFlattener<'a> {
// Do nothing; these are dummy items for the display list parser
SpecificDisplayItem::SetGradientStops => {}
SpecificDisplayItem::PopStackingContext => {
SpecificDisplayItem::PopStackingContext | SpecificDisplayItem::PopReferenceFrame => {
unreachable!("Should have returned in parent method.")
}
SpecificDisplayItem::PushShadow(shadow) => {

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

@ -81,7 +81,6 @@ unsafe impl Send for ThreadSafePathfinderFontContext {}
unsafe impl Sync for ThreadSafePathfinderFontContext { }
impl GlyphRasterizer {
pub(in super) fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) {
let font_contexts = Arc::clone(&self.font_contexts);
debug!("add_font_to_pathfinder({:?})", font_key);
@ -180,9 +179,7 @@ impl GlyphRasterizer {
Entry::Vacant(_) => {}
}
let cached_glyph_info = match cached_glyph_info {
Some(cached_glyph_info) => cached_glyph_info,
None => {
if cached_glyph_info.is_none() {
let mut pathfinder_font_context = self.font_contexts.lock_pathfinder_context();
let pathfinder_font_instance = pathfinder_font_renderer::FontInstance {
@ -196,39 +193,40 @@ impl GlyphRasterizer {
let pathfinder_glyph_key =
pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
pathfinder_subpixel_offset);
let glyph_dimensions =
match pathfinder_font_context.glyph_dimensions(&pathfinder_font_instance,
if let Ok(glyph_dimensions) =
pathfinder_font_context.glyph_dimensions(&pathfinder_font_instance,
&pathfinder_glyph_key,
false) {
Ok(glyph_dimensions) => glyph_dimensions,
Err(_) => continue,
};
let cached_glyph_info = CachedGlyphInfo {
render_task_cache_key: RenderTaskCacheKey {
let render_task_cache_key = RenderTaskCacheKey {
size: TypedSize2D::from_untyped(&glyph_dimensions.size.to_i32()),
kind: RenderTaskCacheKeyKind::Glyph(self.next_gpu_glyph_cache_key),
},
};
cached_glyph_info = Some(CachedGlyphInfo {
render_task_cache_key,
format: font.get_glyph_format(),
origin: DeviceIntPoint::new(glyph_dimensions.origin.x as i32,
-glyph_dimensions.origin.y as i32),
};
});
self.next_gpu_glyph_cache_key.0 += 1;
cached_glyph_info
}
};
}
let handle =
let handle = match cached_glyph_info {
Some(glyph_info) => {
match self.request_glyph_from_pathfinder_if_necessary(glyph_key,
&font,
cached_glyph_info.clone(),
glyph_info.clone(),
texture_cache,
gpu_cache,
render_task_cache,
render_task_tree,
render_passes) {
Ok(_) => GlyphCacheEntry::Cached(cached_glyph_info),
Ok(_) => GlyphCacheEntry::Cached(glyph_info),
Err(_) => GlyphCacheEntry::Blank,
}
}
None => GlyphCacheEntry::Blank,
};
glyph_key_cache.insert(glyph_key.clone(), handle);

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

@ -1469,6 +1469,7 @@ impl PrimitiveStore {
let scale = world_scale * frame_context.device_pixel_scale;
let scale_au = Au::from_f32_px(scale.0);
let needs_update = scale_au != cache_key.scale;
let mut new_segments = Vec::new();
if needs_update {
cache_key.scale = scale_au;
@ -1478,6 +1479,7 @@ impl PrimitiveStore {
border,
widths,
scale,
&mut new_segments,
));
}
@ -1495,7 +1497,7 @@ impl PrimitiveStore {
|render_tasks| {
let task = RenderTask::new_border(
task_info.size,
task_info.instances.clone(),
task_info.build_instances(border),
);
let task_id = render_tasks.add(task);
@ -1508,7 +1510,7 @@ impl PrimitiveStore {
if needs_update {
brush.segment_desc = Some(BrushSegmentDescriptor {
segments: task_info.segments.clone(),
segments: new_segments,
clip_mask_kind: BrushClipMaskKind::Unknown,
});
}

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

@ -1190,26 +1190,28 @@ trait ToDebugString {
impl ToDebugString for SpecificDisplayItem {
fn debug_string(&self) -> String {
match *self {
SpecificDisplayItem::Image(..) => String::from("image"),
SpecificDisplayItem::YuvImage(..) => String::from("yuv_image"),
SpecificDisplayItem::Text(..) => String::from("text"),
SpecificDisplayItem::Rectangle(..) => String::from("rectangle"),
SpecificDisplayItem::ClearRectangle => String::from("clear_rectangle"),
SpecificDisplayItem::Line(..) => String::from("line"),
SpecificDisplayItem::Gradient(..) => String::from("gradient"),
SpecificDisplayItem::RadialGradient(..) => String::from("radial_gradient"),
SpecificDisplayItem::BoxShadow(..) => String::from("box_shadow"),
SpecificDisplayItem::Border(..) => String::from("border"),
SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
SpecificDisplayItem::Iframe(..) => String::from("iframe"),
SpecificDisplayItem::BoxShadow(..) => String::from("box_shadow"),
SpecificDisplayItem::ClearRectangle => String::from("clear_rectangle"),
SpecificDisplayItem::Clip(..) => String::from("clip"),
SpecificDisplayItem::ClipChain(..) => String::from("clip_chain"),
SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
SpecificDisplayItem::Gradient(..) => String::from("gradient"),
SpecificDisplayItem::Iframe(..) => String::from("iframe"),
SpecificDisplayItem::Image(..) => String::from("image"),
SpecificDisplayItem::Line(..) => String::from("line"),
SpecificDisplayItem::PopAllShadows => String::from("pop_all_shadows"),
SpecificDisplayItem::PopReferenceFrame => String::from("pop_reference_frame"),
SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
SpecificDisplayItem::PushReferenceFrame(..) => String::from("push_reference_frame"),
SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
SpecificDisplayItem::RadialGradient(..) => String::from("radial_gradient"),
SpecificDisplayItem::Rectangle(..) => String::from("rectangle"),
SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
SpecificDisplayItem::Text(..) => String::from("text"),
SpecificDisplayItem::YuvImage(..) => String::from("yuv_image"),
}
}
}

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

@ -701,7 +701,13 @@ impl RenderTask {
}
};
let (target_rect, target_index) = self.get_target_rect();
let (mut target_rect, target_index) = self.get_target_rect();
// The primitives inside a fixed-location render task
// are already placed to their corresponding positions,
// so the shader doesn't need to shift by the origin.
if let RenderTaskLocation::Fixed(_) = self.location {
target_rect.origin = DeviceIntPoint::origin();
};
RenderTaskData {
data: [

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

@ -2887,8 +2887,18 @@ impl Renderer {
for alpha_batch_container in &target.alpha_batch_containers {
if let Some(target_rect) = alpha_batch_container.target_rect {
// Note: `framebuffer_target_rect` needs a Y-flip before going to GL
let rect = if render_target.is_none() {
let mut rect = target_rect
.intersection(&framebuffer_target_rect.to_i32())
.unwrap_or(DeviceIntRect::zero());
rect.origin.y = target_size.height as i32 - rect.origin.y - rect.size.height;
rect
} else {
target_rect
};
self.device.enable_scissor();
self.device.set_scissor_rect(target_rect);
self.device.set_scissor_rect(rect);
}
// Draw opaque batches front-to-back for maximum
@ -2930,8 +2940,18 @@ impl Renderer {
for alpha_batch_container in &target.alpha_batch_containers {
if let Some(target_rect) = alpha_batch_container.target_rect {
// Note: `framebuffer_target_rect` needs a Y-flip before going to GL
let rect = if render_target.is_none() {
let mut rect = target_rect
.intersection(&framebuffer_target_rect.to_i32())
.unwrap_or(DeviceIntRect::zero());
rect.origin.y = target_size.height as i32 - rect.origin.y - rect.size.height;
rect
} else {
target_rect
};
self.device.enable_scissor();
self.device.set_scissor_rect(target_rect);
self.device.set_scissor_rect(rect);
}
for batch in &alpha_batch_container.alpha_batches {

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

@ -662,6 +662,7 @@ impl ResourceCache {
if let Some(dirty) = dirty_rect {
if intersect_for_tile(dirty, actual_size, tile_size, tile_offset).is_none() {
// don't bother requesting unchanged tiles
self.pending_image_requests.remove(&request);
return
}
}

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

@ -115,6 +115,13 @@ impl Scene {
self.root_pipeline_id = Some(pipeline_id);
}
pub fn get_display_list_for_pipeline(&self, pipeline_id: PipelineId) -> &BuiltDisplayList {
&self.pipelines
.get(&pipeline_id)
.expect("Expected to find display list for pipeline")
.display_list
}
pub fn set_display_list(
&mut self,
pipeline_id: PipelineId,

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

@ -109,6 +109,8 @@ pub enum SpecificDisplayItem {
Iframe(IframeDisplayItem),
PushStackingContext(PushStackingContextDisplayItem),
PopStackingContext,
PushReferenceFrame(PushReferenceFrameDisplayListItem),
PopReferenceFrame,
SetGradientStops,
PushShadow(Shadow),
PopAllShadows,
@ -138,6 +140,8 @@ pub enum CompletelySpecificDisplayItem {
Iframe(IframeDisplayItem),
PushStackingContext(PushStackingContextDisplayItem, Vec<FilterOp>),
PopStackingContext,
PushReferenceFrame(PushReferenceFrameDisplayListItem),
PopReferenceFrame,
SetGradientStops(Vec<GradientStop>),
PushShadow(Shadow),
PopAllShadows,
@ -386,6 +390,12 @@ pub enum BorderStyle {
Outset = 9,
}
impl BorderStyle {
pub fn is_hidden(&self) -> bool {
*self == BorderStyle::Hidden || *self == BorderStyle::None
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum BoxShadowClipMode {
@ -462,6 +472,18 @@ pub struct RadialGradientDisplayItem {
pub tile_spacing: LayoutSize,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct PushReferenceFrameDisplayListItem {
pub reference_frame: ReferenceFrame,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ReferenceFrame {
pub transform: Option<PropertyBinding<LayoutTransform>>,
pub perspective: Option<LayoutTransform>,
pub id: ClipId,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct PushStackingContextDisplayItem {
pub stacking_context: StackingContext,
@ -469,11 +491,8 @@ pub struct PushStackingContextDisplayItem {
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct StackingContext {
pub transform: Option<PropertyBinding<LayoutTransform>>,
pub transform_style: TransformStyle,
pub perspective: Option<LayoutTransform>,
pub mix_blend_mode: MixBlendMode,
pub reference_frame_id: Option<ClipId>,
pub clip_node_id: Option<ClipId>,
pub glyph_raster_space: GlyphRasterSpace,
} // IMPLICIT: filters: Vec<FilterOp>

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

@ -20,10 +20,11 @@ use {FontInstanceKey, GlyphInstance, GlyphOptions, GlyphRasterSpace, Gradient};
use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
use {ImageRendering, LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform};
use {LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
use {RectangleDisplayItem, ScrollFrameDisplayItem, ScrollSensitivity, Shadow, SpecificDisplayItem};
use {StackingContext, StickyFrameDisplayItem, StickyOffsetBounds, TextDisplayItem, TransformStyle};
use {YuvColorSpace, YuvData, YuvImageDisplayItem};
use {PropertyBinding, PushReferenceFrameDisplayListItem, PushStackingContextDisplayItem};
use {RadialGradient, RadialGradientDisplayItem, RectangleDisplayItem, ReferenceFrame};
use {ScrollFrameDisplayItem, ScrollSensitivity, Shadow, SpecificDisplayItem, StackingContext};
use {StickyFrameDisplayItem, StickyOffsetBounds, TextDisplayItem, TransformStyle, YuvColorSpace};
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.
// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_PRIM_HEADER - VECS_PER_TEXT_RUN) * 2
@ -481,6 +482,8 @@ impl Serialize for BuiltDisplayList {
item.iter.list.get(item.iter.cur_filters).collect()
),
SpecificDisplayItem::PopStackingContext => PopStackingContext,
SpecificDisplayItem::PushReferenceFrame(v) => PushReferenceFrame(v),
SpecificDisplayItem::PopReferenceFrame => PopReferenceFrame,
SpecificDisplayItem::SetGradientStops => SetGradientStops(
item.iter.list.get(item.iter.cur_stops).collect()
),
@ -555,13 +558,15 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
SpecificDisplayItem::Iframe(specific_item)
}
PushStackingContext(specific_item, filters) => {
if specific_item.stacking_context.reference_frame_id.is_some() {
total_clip_ids += 1;
}
DisplayListBuilder::push_iter_impl(&mut temp, filters);
SpecificDisplayItem::PushStackingContext(specific_item)
},
PopStackingContext => SpecificDisplayItem::PopStackingContext,
PushReferenceFrame(specific_item) => {
total_clip_ids += 1;
SpecificDisplayItem::PushReferenceFrame(specific_item)
}
PopReferenceFrame => SpecificDisplayItem::PopReferenceFrame,
SetGradientStops(stops) => {
DisplayListBuilder::push_iter_impl(&mut temp, stops);
SpecificDisplayItem::SetGradientStops
@ -1277,30 +1282,41 @@ impl DisplayListBuilder {
self.push_item(item, info);
}
pub fn push_reference_frame(
&mut self,
info: &LayoutPrimitiveInfo,
transform: Option<PropertyBinding<LayoutTransform>>,
perspective: Option<LayoutTransform>,
) -> ClipId {
let id = self.generate_clip_id();
let item = SpecificDisplayItem::PushReferenceFrame(PushReferenceFrameDisplayListItem {
reference_frame: ReferenceFrame {
transform,
perspective,
id,
},
});
self.push_item(item, info);
id
}
pub fn pop_reference_frame(&mut self) {
self.push_new_empty_item(SpecificDisplayItem::PopReferenceFrame);
}
pub fn push_stacking_context(
&mut self,
info: &LayoutPrimitiveInfo,
clip_node_id: Option<ClipId>,
transform: Option<PropertyBinding<LayoutTransform>>,
transform_style: TransformStyle,
perspective: Option<LayoutTransform>,
mix_blend_mode: MixBlendMode,
filters: Vec<FilterOp>,
glyph_raster_space: GlyphRasterSpace,
) -> Option<ClipId> {
let reference_frame_id = if transform.is_some() || perspective.is_some() {
Some(self.generate_clip_id())
} else {
None
};
) {
let item = SpecificDisplayItem::PushStackingContext(PushStackingContextDisplayItem {
stacking_context: StackingContext {
transform,
transform_style,
perspective,
mix_blend_mode,
reference_frame_id,
clip_node_id,
glyph_raster_space,
},
@ -1308,8 +1324,6 @@ impl DisplayListBuilder {
self.push_item(item, info);
self.push_iter(&filters);
reference_frame_id
}
pub fn pop_stacking_context(&mut self) {

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

@ -1 +1 @@
3829687ffbe8d55885d71a3d5e5e79216251548f
8e697f8cb1f1aab2e5f6b9b903eb7191340b10c5

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

@ -154,6 +154,13 @@ impl<'a> RawtestHarness<'a> {
Some(31),
);
let called = Arc::new(AtomicIsize::new(0));
let called_inner = Arc::clone(&called);
self.wrench.callbacks.lock().unwrap().request = Box::new(move |_| {
called_inner.fetch_add(1, Ordering::SeqCst);
});
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
let info = LayoutPrimitiveInfo::new(rect(0., -9600.0, 1510.000031, 111256.));
@ -178,13 +185,6 @@ impl<'a> RawtestHarness<'a> {
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
let called = Arc::new(AtomicIsize::new(0));
let called_inner = Arc::clone(&called);
self.wrench.callbacks.lock().unwrap().request = Box::new(move |_| {
called_inner.fetch_add(1, Ordering::SeqCst);
});
let pixels = self.render_and_get_pixels(window_rect);
// make sure we didn't request too many blobs
@ -225,6 +225,8 @@ impl<'a> RawtestHarness<'a> {
txn = Transaction::new();
txn.delete_image(blob_img);
self.wrench.api.update_resources(txn.resource_updates);
*self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
}
fn test_offscreen_blob(&mut self) {
@ -362,6 +364,13 @@ impl<'a> RawtestHarness<'a> {
);
}
let called = Arc::new(AtomicIsize::new(0));
let called_inner = Arc::clone(&called);
self.wrench.callbacks.lock().unwrap().request = Box::new(move |_| {
assert_eq!(0, called_inner.fetch_add(1, Ordering::SeqCst));
});
// draw the blob the first time
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0));
@ -379,16 +388,9 @@ impl<'a> RawtestHarness<'a> {
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
let called = Arc::new(AtomicIsize::new(0));
let called_inner = Arc::clone(&called);
self.wrench.callbacks.lock().unwrap().request = Box::new(move |_| {
called_inner.fetch_add(1, Ordering::SeqCst);
});
let pixels_first = self.render_and_get_pixels(window_rect);
assert!(called.load(Ordering::SeqCst) == 1);
assert_eq!(1, called.load(Ordering::SeqCst));
// draw the blob image a second time at a different location
@ -411,13 +413,16 @@ impl<'a> RawtestHarness<'a> {
let pixels_second = self.render_and_get_pixels(window_rect);
// make sure we only requested once
assert!(called.load(Ordering::SeqCst) == 1);
assert_eq!(1, called.load(Ordering::SeqCst));
// use png;
// png::save_flipped("out1.png", &pixels_first, window_rect.size);
// png::save_flipped("out2.png", &pixels_second, window_rect.size);
assert!(pixels_first != pixels_second);
// cleanup
*self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
}
fn test_blob_update_epoch_test(&mut self) {
@ -539,6 +544,9 @@ impl<'a> RawtestHarness<'a> {
assert_eq!(img1_requested.load(Ordering::SeqCst), 3);
// the second image should've been requested twice
assert_eq!(img2_requested.load(Ordering::SeqCst), 2);
// cleanup
*self.wrench.callbacks.lock().unwrap() = blob::BlobCallbacks::new();
}
fn test_blob_update_test(&mut self) {

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

@ -1254,6 +1254,26 @@ impl YamlFrameReader {
Some(self.to_complex_clip_region(complex_clip))
}
pub fn get_item_type_from_yaml(item: &Yaml) -> &str {
let shorthands = [
"rect",
"image",
"text",
"glyphs",
"box-shadow", // Note: box_shadow shorthand check has to come before border.
"border",
"gradient",
"radial-gradient",
];
for shorthand in shorthands.iter() {
if !item[*shorthand].is_badvalue() {
return shorthand;
}
}
item["type"].as_str().unwrap_or("unknown")
}
pub fn add_display_list_items_from_yaml(
&mut self,
dl: &mut DisplayListBuilder,
@ -1268,32 +1288,13 @@ impl YamlFrameReader {
LayoutSize::new(big_number, big_number));
for item in yaml.as_vec().unwrap() {
// an explicit type can be skipped with some shorthand
let item_type = if !item["rect"].is_badvalue() {
"rect"
} else if !item["image"].is_badvalue() {
"image"
} else if !item["text"].is_badvalue() {
"text"
} else if !item["glyphs"].is_badvalue() {
"glyphs"
} else if !item["box-shadow"].is_badvalue() {
// Note: box_shadow shorthand check has to come before border.
"box-shadow"
} else if !item["border"].is_badvalue() {
"border"
} else if !item["gradient"].is_badvalue() {
"gradient"
} else if !item["radial-gradient"].is_badvalue() {
"radial-gradient"
} else {
item["type"].as_str().unwrap_or("unknown")
};
let item_type = Self::get_item_type_from_yaml(item);
// We never skip stacking contexts because they are structural elements
// of the display list.
if item_type != "stacking-context" && self.include_only.contains(&item_type.to_owned())
{
// We never skip stacking contexts and reference frames because
// they are structural elements of the display list.
if item_type != "stacking-context" &&
item_type != "reference-frame" &&
self.include_only.contains(&item_type.to_owned()) {
continue;
}
@ -1343,6 +1344,7 @@ impl YamlFrameReader {
"stacking-context" => {
self.add_stacking_context_from_yaml(dl, wrench, item, false, &mut info)
}
"reference-frame" => self.handle_reference_frame(dl, wrench, item, &mut info),
"shadow" => self.handle_push_shadow(dl, item, &mut info),
"pop-all-shadows" => self.handle_pop_all_shadows(dl),
_ => println!("Skipping unknown item type: {:?}", item),
@ -1503,22 +1505,22 @@ impl YamlFrameReader {
.unwrap_or(wrench.window_size_f32())
}
pub fn add_stacking_context_from_yaml(
pub fn push_reference_frame(
&mut self,
dl: &mut DisplayListBuilder,
wrench: &mut Wrench,
yaml: &Yaml,
is_root: bool,
info: &mut LayoutPrimitiveInfo,
) {
) -> ClipId {
let default_bounds = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32());
let bounds = yaml["bounds"].as_rect().unwrap_or(default_bounds);
let default_transform_origin = LayoutPoint::new(
bounds.origin.x + bounds.size.width * 0.5,
bounds.origin.y + bounds.size.height * 0.5,
);
info.rect = bounds;
let transform_origin = yaml["transform-origin"]
.as_point()
.unwrap_or(default_transform_origin);
@ -1531,8 +1533,6 @@ impl YamlFrameReader {
.as_transform(&transform_origin)
.map(|transform| transform.into());
let clip_node_id = self.to_clip_id(&yaml["clip-node"], dl.pipeline_id);
let perspective = match yaml["perspective"].as_f32() {
Some(value) if value != 0.0 => {
Some(make_perspective(perspective_origin, value as f32))
@ -1541,6 +1541,58 @@ impl YamlFrameReader {
_ => yaml["perspective"].as_matrix4d(),
};
let reference_frame_id = dl.push_reference_frame(info, transform.into(), perspective);
let numeric_id = yaml["reference-frame-id"].as_i64();
if let Some(numeric_id) = numeric_id {
self.add_clip_id_mapping(numeric_id as u64, reference_frame_id);
}
reference_frame_id
}
pub fn handle_reference_frame(
&mut self,
dl: &mut DisplayListBuilder,
wrench: &mut Wrench,
yaml: &Yaml,
info: &mut LayoutPrimitiveInfo,
) {
let reference_frame_id = self.push_reference_frame(dl, wrench, yaml, info);
if !yaml["items"].is_badvalue() {
dl.push_clip_id(reference_frame_id);
self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]);
dl.pop_clip_id();
}
dl.pop_reference_frame();
}
pub fn add_stacking_context_from_yaml(
&mut self,
dl: &mut DisplayListBuilder,
wrench: &mut Wrench,
yaml: &Yaml,
is_root: bool,
info: &mut LayoutPrimitiveInfo,
) {
let default_bounds = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32());
let bounds = yaml["bounds"].as_rect().unwrap_or(default_bounds);
info.rect = bounds;
info.clip_rect = bounds;
let reference_frame_id = if !yaml["transform"].is_badvalue() ||
!yaml["perspective"].is_badvalue() {
let reference_frame_id = self.push_reference_frame(dl, wrench, yaml, info);
info.rect.origin = LayoutPoint::zero();
info.clip_rect.origin = LayoutPoint::zero();
Some(reference_frame_id)
} else {
None
};
let clip_node_id = self.to_clip_id(&yaml["clip-node"], dl.pipeline_id);
let transform_style = yaml["transform-style"]
.as_transform_style()
.unwrap_or(TransformStyle::Flat);
@ -1559,33 +1611,33 @@ impl YamlFrameReader {
}
let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]);
info.rect = bounds;
info.clip_rect = bounds;
let reference_frame_id = dl.push_stacking_context(
if let Some(reference_frame_id) = reference_frame_id {
dl.push_clip_id(reference_frame_id);
}
dl.push_stacking_context(
&info,
clip_node_id,
transform.into(),
transform_style,
perspective,
mix_blend_mode,
filters,
glyph_raster_space,
);
let numeric_id = yaml["reference-frame-id"].as_i64();
match (numeric_id, reference_frame_id) {
(Some(numeric_id), Some(reference_frame_id)) => {
self.add_clip_id_mapping(numeric_id as u64, reference_frame_id);
}
_ => {},
}
if !yaml["items"].is_badvalue() {
self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]);
}
dl.pop_stacking_context();
if reference_frame_id.is_some() {
dl.pop_clip_id();
}
if reference_frame_id.is_some() {
dl.pop_reference_frame();
}
}
}

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

@ -178,6 +178,25 @@ fn maybe_radius_yaml(radius: &BorderRadius) -> Option<Yaml> {
}
}
fn write_reference_frame(
parent: &mut Table,
reference_frame: &ReferenceFrame,
properties: &SceneProperties,
clip_id_mapper: &mut ClipIdMapper,
) {
matrix4d_node(
parent,
"transform",
&properties.resolve_layout_transform(&reference_frame.transform)
);
if let Some(perspective) = reference_frame.perspective {
matrix4d_node(parent, "perspective", &perspective);
}
usize_node(parent, "id", clip_id_mapper.add_id(reference_frame.id));
}
fn write_stacking_context(
parent: &mut Table,
sc: &StackingContext,
@ -185,8 +204,6 @@ fn write_stacking_context(
filter_iter: AuxIter<FilterOp>,
clip_id_mapper: &ClipIdMapper,
) {
matrix4d_node(parent, "transform", &properties.resolve_layout_transform(&sc.transform));
enum_node(parent, "transform-style", sc.transform_style);
let glyph_raster_space = match sc.glyph_raster_space {
@ -203,10 +220,6 @@ fn write_stacking_context(
yaml_node(parent, "clip-node", clip_id_mapper.map_id(&clip_node_id));
}
if let Some(perspective) = sc.perspective {
matrix4d_node(parent, "perspective", &perspective);
}
// mix_blend_mode
if sc.mix_blend_mode != MixBlendMode::Normal {
enum_node(parent, "mix-blend-mode", sc.mix_blend_mode)
@ -1031,6 +1044,19 @@ impl YamlFrameWriter {
self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper);
continue_traversal = Some(sub_iter);
}
PushReferenceFrame(item) => {
str_node(&mut v, "type", "reference-frame");
write_reference_frame(
&mut v,
&item.reference_frame,
&scene.properties,
clip_id_mapper
);
let mut sub_iter = base.sub_iter();
self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper);
continue_traversal = Some(sub_iter);
}
Clip(item) => {
str_node(&mut v, "type", "clip");
usize_node(&mut v, "id", clip_id_mapper.add_id(item.id));
@ -1121,6 +1147,7 @@ impl YamlFrameWriter {
}
PopStackingContext => return,
PopReferenceFrame => return,
SetGradientStops => panic!("dummy item yielded?"),
PushShadow(shadow) => {
str_node(&mut v, "type", "shadow");