--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "webrender"
-version = "0.31.0"
+version = "0.32.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"
build = "build.rs"
[features]
default = ["freetype-lib", "webgl"]
freetype-lib = ["freetype/servo-freetype-sys"]
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/doc/CLIPPING.md
@@ -0,0 +1,93 @@
+# Clipping in WebRender
+
+The WebRender display list allows defining clips in two different ways. The
+first is specified directly on each display item and cannot be reused between
+items. The second is specified using the `SpecificDisplayItem::Clip` display item
+and can be reused between items as well as used to define scrollable regions.
+
+## Clips
+
+Clips are defined using the ClipRegion in both cases.
+
+```rust
+pub struct ClipRegion {
+ pub main: LayoutRect,
+ pub complex: ItemRange,
+ pub image_mask: Option<ImageMask>,
+}
+```
+
+`main` defines a rectangular clip, while the other members make that rectangle
+smaller. `complex`, if it is not empty, defines the boundaries of a rounded
+rectangle. While `image_mask` defines the positioning, repetition, and data of
+a masking image.
+
+## Item Clips
+
+Item clips are simply a `ClipRegion` structure defined directly on the
+`DisplayItem`. The important thing to note about these clips is that all the
+coordinate in `ClipRegion` **are in the same coordinate space as the item
+itself**. This different than for clips defined by `SpecificDisplayItem::Clip`.
+
+## Clip Display Items
+
+Clip display items allow items to share clips in order to increase performance
+(shared clips are only rasterized once) and to allow for scrolling regions.
+Display items can be assigned a clip display item using the `clip_id`
+field. An item can be assigned any clip that is defined by its parent stacking
+context or any of the ancestors. The behavior of assigning an id outside of
+this hierarchy is undefined, because that situation does not occur in CSS
+
+The clip display item has a `ClipRegion` as well as several other fields:
+
+```rust
+pub struct ClipDisplayItem {
+ pub id: ClipId,
+ pub parent_id: ClipId,
+}
+```
+
+A `ClipDisplayItem` also gets a clip and bounds from the `BaseDisplayItem`. The
+clip is shared among all items that use this `ClipDisplayItem`. Critically,
+**coordinates in this ClipRegion are defined relative to the bounds of the
+ClipDisplayItem itself**. Additionally, WebRender only supports clip rectangles
+that start at the origin of the `BaseDisplayItem` bounds.
+
+The `BaseDisplayItem` bounds are known as the *content rectangle* of the clip. If
+the content rectangle is larger than *main* clipping rectangle, the clip will
+be a scrolling clip and participate in scrolling event capture and
+transformation.
+
+`ClipDisplayItems` are positioned, like all other items, relatively to their
+containing stacking context, yet they also live in a parallel tree defined by
+their `parent_id`. Child clips also include any clipping and scrolling that
+their ancestors do. In this way, a clip is positioned by a stacking context,
+but that position may be adjusted by any scroll offset of its parent clips.
+
+## Clip ids
+
+All clips defined by a `ClipDisplayItem` have an id. It is useful to associate
+an external id with WebRender id in order to allow for tracking and updating
+scroll positions using the WebRender API. In order to make this as cheap as
+possible and to avoid having to create a `HashMap` to map between the two types
+of ids, the WebRender API provides an optional id argument in
+`DisplayListBuilder::define_clip`. The only types of ids that are supported
+here are those created with `ClipId::new(...)`. If this argument is not
+provided `define_clip` will return a uniquely generated id. Thus, the following
+should always be true:
+
+```rust
+let id = ClipId::new(my_internal_id, pipeline_id);
+let generated_id = define_clip(content_rect, clip, id);
+assert!(id == generated_id);
+```
+
+## Pending changes
+1. Normalize the way that clipping coordinates are defined. Having them
+ specified in two different ways makes for a confusing API. This should be
+ fixed. ([github issue](https://github.com/servo/webrender/issues/1090))
+
+1. It should be possible to specify more than one predefined clip for an item.
+ This is necessary for items that live in a scrolling frame, but are also
+ clipped by a clip that lives outside that frame.
+ ([github issue](https://github.com/servo/webrender/issues/840))
--- a/gfx/webrender/res/clip_shared.glsl
+++ b/gfx/webrender/res/clip_shared.glsl
@@ -29,28 +29,31 @@ CacheClipInstance fetch_clip_item(int in
cci.render_task_index = aClipRenderTaskIndex;
cci.layer_index = aClipLayerIndex;
cci.data_index = aClipDataIndex;
cci.segment_index = aClipSegmentIndex;
return cci;
}
+struct ClipVertexInfo {
+ vec3 local_pos;
+ vec2 screen_pos;
+ RectWithSize clipped_local_rect;
+};
+
// The transformed vertex function that always covers the whole clip area,
// which is the intersection of all clip instances of a given primitive
-TransformVertexInfo write_clip_tile_vertex(vec4 local_clip_rect,
- Layer layer,
- ClipArea area,
- int segment_index) {
- vec2 lp0_base = local_clip_rect.xy;
- vec2 lp1_base = local_clip_rect.xy + local_clip_rect.zw;
+ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
+ Layer layer,
+ ClipArea area,
+ int segment_index) {
- vec2 lp0 = clamp_rect(lp0_base, layer.local_clip_rect);
- vec2 lp1 = clamp_rect(lp1_base, layer.local_clip_rect);
- vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
+ RectWithSize clipped_local_rect = intersect_rect(local_clip_rect,
+ layer.local_clip_rect);
vec2 outer_p0 = area.screen_origin_target_index.xy;
vec2 outer_p1 = outer_p0 + area.task_bounds.zw - area.task_bounds.xy;
vec2 inner_p0 = area.inner_rect.xy;
vec2 inner_p1 = area.inner_rect.zw;
vec2 p0, p1;
switch (segment_index) {
@@ -80,12 +83,12 @@ TransformVertexInfo write_clip_tile_vert
vec4 layer_pos = get_layer_pos(actual_pos / uDevicePixelRatio, layer);
// compute the point position in side the layer, in CSS space
vec2 vertex_pos = actual_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
gl_Position = uTransform * vec4(vertex_pos, 0.0, 1);
- return TransformVertexInfo(layer_pos.xyw, actual_pos, clipped_local_rect);
+ return ClipVertexInfo(layer_pos.xyw, actual_pos, clipped_local_rect);
}
#endif //WR_VERTEX_SHADER
--- a/gfx/webrender/res/cs_clip_image.glsl
+++ b/gfx/webrender/res/cs_clip_image.glsl
@@ -1,10 +1,10 @@
#line 1
/* 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/. */
varying vec3 vPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
flat varying vec4 vClipMaskUvRect;
flat varying vec4 vClipMaskUvInnerRect;
--- a/gfx/webrender/res/cs_clip_image.vs.glsl
+++ b/gfx/webrender/res/cs_clip_image.vs.glsl
@@ -1,42 +1,38 @@
#line 1
/* 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/. */
struct ImageMaskData {
- vec4 uv_rect;
- vec4 local_rect;
+ RectWithSize uv_rect;
+ RectWithSize local_rect;
};
ImageMaskData fetch_mask_data(int index) {
- ImageMaskData info;
-
- ivec2 uv = get_fetch_uv_2(index);
-
- info.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
- info.local_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
-
- return info;
+ vec4 data[2] = fetch_data_2(index);
+ return ImageMaskData(RectWithSize(data[0].xy, data[0].zw),
+ RectWithSize(data[1].xy, data[1].zw));
}
void main(void) {
CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
ClipArea area = fetch_clip_area(cci.render_task_index);
Layer layer = fetch_layer(cci.layer_index);
ImageMaskData mask = fetch_mask_data(cci.data_index);
- vec4 local_rect = mask.local_rect;
+ RectWithSize local_rect = mask.local_rect;
- TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
- layer,
- area,
- cci.segment_index);
+ ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
+ layer,
+ area,
+ cci.segment_index);
+
vLocalRect = vi.clipped_local_rect;
vPos = vi.local_pos;
- vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.xy) / local_rect.zw, 0.0);
+ vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.p0) / local_rect.size, 0.0);
vec2 texture_size = vec2(textureSize(sMask, 0));
- vClipMaskUvRect = mask.uv_rect / texture_size.xyxy;
+ vClipMaskUvRect = vec4(mask.uv_rect.p0, mask.uv_rect.size) / texture_size.xyxy;
// applying a half-texel offset to the UV boundaries to prevent linear samples from the outside
- vec4 inner_rect = vec4(mask.uv_rect.xy, mask.uv_rect.xy + mask.uv_rect.zw);
+ vec4 inner_rect = vec4(mask.uv_rect.p0, mask.uv_rect.p0 + mask.uv_rect.size);
vClipMaskUvInnerRect = (inner_rect + vec4(0.5, 0.5, -0.5, -0.5)) / texture_size.xyxy;
}
--- a/gfx/webrender/res/cs_clip_rectangle.glsl
+++ b/gfx/webrender/res/cs_clip_rectangle.glsl
@@ -1,11 +1,11 @@
#line 1
/* 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/. */
varying vec3 vPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
flat varying vec4 vClipRect;
flat varying vec4 vClipRadius;
flat varying float vClipMode;
--- a/gfx/webrender/res/cs_clip_rectangle.vs.glsl
+++ b/gfx/webrender/res/cs_clip_rectangle.vs.glsl
@@ -1,43 +1,31 @@
#line 1
/* 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/. */
struct ClipRect {
- vec4 rect;
+ RectWithSize rect;
vec4 mode;
};
ClipRect fetch_clip_rect(int index) {
- ClipRect rect;
-
- ivec2 uv = get_fetch_uv_2(index);
-
- rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
- rect.mode = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
-
- return rect;
+ vec4 data[2] = fetch_data_2(index);
+ return ClipRect(RectWithSize(data[0].xy, data[0].zw), data[1]);
}
struct ClipCorner {
- vec4 rect;
+ RectWithSize rect;
vec4 outer_inner_radius;
};
ClipCorner fetch_clip_corner(int index) {
- ClipCorner corner;
-
- ivec2 uv = get_fetch_uv_2(index);
-
- corner.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
- corner.outer_inner_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
-
- return corner;
+ vec4 data[2] = fetch_data_2(index);
+ return ClipCorner(RectWithSize(data[0].xy, data[0].zw), data[1]);
}
struct ClipData {
ClipRect rect;
ClipCorner top_left;
ClipCorner top_right;
ClipCorner bottom_left;
ClipCorner bottom_right;
@@ -55,24 +43,24 @@ ClipData fetch_clip(int index) {
return clip;
}
void main(void) {
CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
ClipArea area = fetch_clip_area(cci.render_task_index);
Layer layer = fetch_layer(cci.layer_index);
ClipData clip = fetch_clip(cci.data_index);
- vec4 local_rect = clip.rect.rect;
+ RectWithSize local_rect = clip.rect.rect;
- TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
- layer,
- area,
- cci.segment_index);
+ ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
+ layer,
+ area,
+ cci.segment_index);
vLocalRect = vi.clipped_local_rect;
vPos = vi.local_pos;
vClipMode = clip.rect.mode.x;
- vClipRect = vec4(local_rect.xy, local_rect.xy + local_rect.zw);
+ vClipRect = vec4(local_rect.p0, local_rect.p0 + local_rect.size);
vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
clip.top_right.outer_inner_radius.x,
clip.bottom_right.outer_inner_radius.x,
clip.bottom_left.outer_inner_radius.x);
}
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -31,67 +31,16 @@
#define UV_PIXEL uint(1)
#define EXTEND_MODE_CLAMP 0
#define EXTEND_MODE_REPEAT 1
uniform sampler2DArray sCacheA8;
uniform sampler2DArray sCacheRGBA8;
-flat varying vec4 vClipMaskUvBounds;
-varying vec3 vClipMaskUv;
-
-#ifdef WR_VERTEX_SHADER
-
-#define VECS_PER_LAYER 13
-#define VECS_PER_RENDER_TASK 3
-#define VECS_PER_PRIM_GEOM 2
-
-uniform sampler2D sLayers;
-uniform sampler2D sRenderTasks;
-uniform sampler2D sPrimGeometry;
-
-uniform sampler2D sData16;
-uniform sampler2D sData32;
-uniform sampler2D sData64;
-uniform sampler2D sData128;
-uniform sampler2D sResourceRects;
-
-// Instanced attributes
-in int aGlobalPrimId;
-in int aPrimitiveAddress;
-in int aTaskIndex;
-in int aClipTaskIndex;
-in int aLayerIndex;
-in int aElementIndex;
-in ivec2 aUserData;
-in int aZIndex;
-
-// get_fetch_uv is a macro to work around a macOS Intel driver parsing bug.
-// TODO: convert back to a function once the driver issues are resolved, if ever.
-// https://github.com/servo/webrender/pull/623
-// https://github.com/servo/servo/issues/13953
-#define get_fetch_uv(i, vpi) ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
-
-ivec2 get_fetch_uv_1(int index) {
- return get_fetch_uv(index, 1);
-}
-
-ivec2 get_fetch_uv_2(int index) {
- return get_fetch_uv(index, 2);
-}
-
-ivec2 get_fetch_uv_4(int index) {
- return get_fetch_uv(index, 4);
-}
-
-ivec2 get_fetch_uv_8(int index) {
- return get_fetch_uv(index, 8);
-}
-
struct RectWithSize {
vec2 p0;
vec2 size;
};
struct RectWithEndpoint {
vec2 p0;
vec2 p1;
@@ -125,16 +74,100 @@ vec2 clamp_rect(vec2 point, RectWithEndp
vec4 clamp_rect(vec4 points, RectWithSize rect) {
return clamp(points, rect.p0.xyxy, rect.p0.xyxy + rect.size.xyxy);
}
vec4 clamp_rect(vec4 points, RectWithEndpoint rect) {
return clamp(points, rect.p0.xyxy, rect.p1.xyxy);
}
+RectWithSize intersect_rect(RectWithSize a, RectWithSize b) {
+ vec4 p = clamp_rect(vec4(a.p0, a.p0 + a.size), b);
+ return RectWithSize(p.xy, max(vec2(0.0), p.zw - p.xy));
+}
+
+RectWithEndpoint intersect_rect(RectWithEndpoint a, RectWithEndpoint b) {
+ vec4 p = clamp_rect(vec4(a.p0, a.p1), b);
+ return RectWithEndpoint(p.xy, max(p.xy, p.zw));
+}
+
+
+flat varying RectWithEndpoint vClipMaskUvBounds;
+varying vec3 vClipMaskUv;
+
+#ifdef WR_VERTEX_SHADER
+
+#define VECS_PER_LAYER 13
+#define VECS_PER_RENDER_TASK 3
+#define VECS_PER_PRIM_GEOM 2
+
+uniform sampler2D sLayers;
+uniform sampler2D sRenderTasks;
+uniform sampler2D sPrimGeometry;
+
+uniform sampler2D sData16;
+uniform sampler2D sData32;
+uniform sampler2D sData64;
+uniform sampler2D sData128;
+uniform sampler2D sResourceRects;
+
+// Instanced attributes
+in int aGlobalPrimId;
+in int aPrimitiveAddress;
+in int aTaskIndex;
+in int aClipTaskIndex;
+in int aLayerIndex;
+in int aElementIndex;
+in ivec2 aUserData;
+in int aZIndex;
+
+// get_fetch_uv is a macro to work around a macOS Intel driver parsing bug.
+// TODO: convert back to a function once the driver issues are resolved, if ever.
+// https://github.com/servo/webrender/pull/623
+// https://github.com/servo/servo/issues/13953
+#define get_fetch_uv(i, vpi) ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
+
+vec4 fetch_data_1(int index) {
+ ivec2 uv = get_fetch_uv(index, 1);
+ return texelFetch(sData16, uv, 0);
+}
+
+vec4[2] fetch_data_2(int index) {
+ ivec2 uv = get_fetch_uv(index, 2);
+ return vec4[2](
+ texelFetchOffset(sData32, uv, 0, ivec2(0, 0)),
+ texelFetchOffset(sData32, uv, 0, ivec2(1, 0))
+ );
+}
+
+vec4[4] fetch_data_4(int index) {
+ ivec2 uv = get_fetch_uv(index, 4);
+ return vec4[4](
+ texelFetchOffset(sData64, uv, 0, ivec2(0, 0)),
+ texelFetchOffset(sData64, uv, 0, ivec2(1, 0)),
+ texelFetchOffset(sData64, uv, 0, ivec2(2, 0)),
+ texelFetchOffset(sData64, uv, 0, ivec2(3, 0))
+ );
+}
+
+vec4[8] fetch_data_8(int index) {
+ ivec2 uv = get_fetch_uv(index, 8);
+ return vec4[8](
+ texelFetchOffset(sData128, uv, 0, ivec2(0, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(1, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(2, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(3, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(4, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(5, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(6, 0)),
+ texelFetchOffset(sData128, uv, 0, ivec2(7, 0))
+ );
+}
+
+
struct Layer {
mat4 transform;
mat4 inv_transform;
RectWithSize local_clip_rect;
vec4 screen_vertices[4];
};
Layer fetch_layer(int index) {
@@ -231,81 +264,110 @@ ClipArea fetch_clip_area(int index) {
struct Gradient {
vec4 start_end_point;
vec4 tile_size_repeat;
vec4 extend_mode;
};
Gradient fetch_gradient(int index) {
- Gradient gradient;
-
- ivec2 uv = get_fetch_uv_4(index);
-
- gradient.start_end_point = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
- gradient.tile_size_repeat = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
- gradient.extend_mode = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
-
- return gradient;
+ vec4 data[4] = fetch_data_4(index);
+ return Gradient(data[0], data[1], data[2]);
}
struct GradientStop {
vec4 color;
vec4 offset;
};
GradientStop fetch_gradient_stop(int index) {
- GradientStop stop;
-
- ivec2 uv = get_fetch_uv_2(index);
-
- stop.color = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
- stop.offset = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
-
- return stop;
+ vec4 data[2] = fetch_data_2(index);
+ return GradientStop(data[0], data[1]);
}
struct RadialGradient {
vec4 start_end_center;
vec4 start_end_radius_ratio_xy_extend_mode;
vec4 tile_size_repeat;
};
RadialGradient fetch_radial_gradient(int index) {
- RadialGradient gradient;
+ vec4 data[4] = fetch_data_4(index);
+ return RadialGradient(data[0], data[1], data[2]);
+}
+
+struct Border {
+ vec4 style;
+ vec4 widths;
+ vec4 colors[4];
+ vec4 radii[2];
+};
- ivec2 uv = get_fetch_uv_4(index);
+Border fetch_border(int index) {
+ vec4 data[8] = fetch_data_8(index);
+ return Border(data[0], data[1],
+ vec4[4](data[2], data[3], data[4], data[5]),
+ vec4[2](data[6], data[7]));
+}
+
+struct BorderCorners {
+ vec2 tl_outer;
+ vec2 tl_inner;
+ vec2 tr_outer;
+ vec2 tr_inner;
+ vec2 br_outer;
+ vec2 br_inner;
+ vec2 bl_outer;
+ vec2 bl_inner;
+};
- gradient.start_end_center = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
- gradient.start_end_radius_ratio_xy_extend_mode = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
- gradient.tile_size_repeat = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
+BorderCorners get_border_corners(Border border, RectWithSize local_rect) {
+ vec2 tl_outer = local_rect.p0;
+ vec2 tl_inner = tl_outer + vec2(max(border.radii[0].x, border.widths.x),
+ max(border.radii[0].y, border.widths.y));
+
+ vec2 tr_outer = vec2(local_rect.p0.x + local_rect.size.x,
+ local_rect.p0.y);
+ vec2 tr_inner = tr_outer + vec2(-max(border.radii[0].z, border.widths.z),
+ max(border.radii[0].w, border.widths.y));
+
+ vec2 br_outer = vec2(local_rect.p0.x + local_rect.size.x,
+ local_rect.p0.y + local_rect.size.y);
+ vec2 br_inner = br_outer - vec2(max(border.radii[1].x, border.widths.z),
+ max(border.radii[1].y, border.widths.w));
- return gradient;
+ vec2 bl_outer = vec2(local_rect.p0.x,
+ local_rect.p0.y + local_rect.size.y);
+ vec2 bl_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x),
+ -max(border.radii[1].w, border.widths.w));
+
+ return BorderCorners(
+ tl_outer,
+ tl_inner,
+ tr_outer,
+ tr_inner,
+ br_outer,
+ br_inner,
+ bl_outer,
+ bl_inner
+ );
}
struct Glyph {
vec4 offset;
};
Glyph fetch_glyph(int index) {
- Glyph glyph;
-
- ivec2 uv = get_fetch_uv_1(index);
-
- glyph.offset = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
-
- return glyph;
+ vec4 data = fetch_data_1(index);
+ return Glyph(data);
}
RectWithSize fetch_instance_geometry(int index) {
- ivec2 uv = get_fetch_uv_1(index);
-
- vec4 rect = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
-
- return RectWithSize(rect.xy, rect.zw);
+ vec4 data = fetch_data_1(index);
+ return RectWithSize(data.xy, data.zw);
}
struct PrimitiveGeometry {
RectWithSize local_rect;
RectWithSize local_clip_rect;
};
PrimitiveGeometry fetch_prim_geometry(int index) {
@@ -449,33 +511,31 @@ vec4 get_layer_pos(vec2 pos, Layer layer
vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w;
vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w;
// get the normal to the layer plane
vec3 n = normalize(cross(b-a, c-a));
return untransform(pos, n, a, layer.inv_transform);
}
struct VertexInfo {
- RectWithEndpoint local_rect;
vec2 local_pos;
vec2 screen_pos;
};
VertexInfo write_vertex(RectWithSize instance_rect,
RectWithSize local_clip_rect,
float z,
Layer layer,
- AlphaBatchTask task) {
- RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
-
+ AlphaBatchTask task,
+ vec2 snap_ref) {
// Select the corner of the local rect that we are processing.
- vec2 local_pos = mix(local_rect.p0, local_rect.p1, aPosition.xy);
+ vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
// xy = top left corner of the local rect, zw = position of current vertex.
- vec4 local_p0_pos = vec4(local_rect.p0, local_pos);
+ vec4 local_p0_pos = vec4(snap_ref, local_pos);
// Clamp to the two local clip rects.
local_p0_pos = clamp_rect(local_p0_pos, local_clip_rect);
local_p0_pos = clamp_rect(local_p0_pos, layer.local_clip_rect);
// Transform the top corner and current vertex to world space.
vec4 world_p0 = layer.transform * vec4(local_p0_pos.xy, 0.0, 1.0);
world_p0.xyz /= world_p0.w;
@@ -491,26 +551,25 @@ VertexInfo write_vertex(RectWithSize ins
// Apply offsets for the render task to get correct screen location.
vec2 final_pos = device_p0_pos.zw -
snap_delta -
task.screen_space_origin +
task.render_target_origin;
gl_Position = uTransform * vec4(final_pos, z, 1.0);
- VertexInfo vi = VertexInfo(local_rect, local_p0_pos.zw, device_p0_pos.zw);
+ VertexInfo vi = VertexInfo(local_p0_pos.zw, device_p0_pos.zw);
return vi;
}
#ifdef WR_FEATURE_TRANSFORM
struct TransformVertexInfo {
vec3 local_pos;
vec2 screen_pos;
- vec4 clipped_local_rect;
};
float cross2(vec2 v0, vec2 v1) {
return v0.x * v1.y - v0.y * v1.x;
}
// Return intersection of line (p0,p1) and line (p2,p3)
vec2 intersect_lines(vec2 p0, vec2 p1, vec2 p2, vec2 p3) {
@@ -526,17 +585,18 @@ vec2 intersect_lines(vec2 p0, vec2 p1, v
return vec2(nx / d, ny / d);
}
TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
RectWithSize local_clip_rect,
float z,
Layer layer,
- AlphaBatchTask task) {
+ AlphaBatchTask task,
+ vec2 snap_ref) {
RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
vec2 current_local_pos, prev_local_pos, next_local_pos;
// Select the current vertex and the previous/next vertices,
// based on the vertex ID that is known based on the instance rect.
switch (gl_VertexID) {
case 0:
@@ -586,185 +646,156 @@ TransformVertexInfo write_transform_vert
// Intersect those adjusted lines to find the actual vertex position.
vec2 device_pos = intersect_lines(adjusted_prev_p0,
adjusted_prev_p1,
adjusted_next_p0,
adjusted_next_p1);
// Calculate the snap amount based on the first vertex as a reference point.
- vec4 world_p0 = layer.transform * vec4(local_rect.p0, 0.0, 1.0);
+ vec4 world_p0 = layer.transform * vec4(snap_ref, 0.0, 1.0);
vec2 device_p0 = uDevicePixelRatio * world_p0.xy / world_p0.w;
vec2 snap_delta = device_p0 - floor(device_p0 + 0.5);
// Apply offsets for the render task to get correct screen location.
vec2 final_pos = device_pos -
snap_delta -
task.screen_space_origin +
task.render_target_origin;
gl_Position = uTransform * vec4(final_pos, z, 1.0);
vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer);
- return TransformVertexInfo(layer_pos.xyw, device_pos, vec4(instance_rect.p0, instance_rect.size));
+ return TransformVertexInfo(layer_pos.xyw, device_pos);
}
#endif //WR_FEATURE_TRANSFORM
struct ResourceRect {
vec4 uv_rect;
};
ResourceRect fetch_resource_rect(int index) {
ResourceRect rect;
- ivec2 uv = get_fetch_uv_1(index);
+ ivec2 uv = get_fetch_uv(index, 1);
rect.uv_rect = texelFetchOffset(sResourceRects, uv, 0, ivec2(0, 0));
return rect;
}
struct Rectangle {
vec4 color;
};
Rectangle fetch_rectangle(int index) {
- Rectangle rect;
-
- ivec2 uv = get_fetch_uv_1(index);
-
- rect.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
-
- return rect;
+ vec4 data = fetch_data_1(index);
+ return Rectangle(data);
}
struct TextRun {
vec4 color;
};
TextRun fetch_text_run(int index) {
- TextRun text;
-
- ivec2 uv = get_fetch_uv_1(index);
-
- text.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
-
- return text;
+ vec4 data = fetch_data_1(index);
+ return TextRun(data);
}
struct Image {
vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between
// tiled instances of this image.
};
Image fetch_image(int index) {
- Image image;
-
- ivec2 uv = get_fetch_uv_1(index);
-
- image.stretch_size_and_tile_spacing = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
-
- return image;
+ vec4 data = fetch_data_1(index);
+ return Image(data);
}
// YUV color spaces
#define YUV_REC601 1
#define YUV_REC709 2
struct YuvImage {
vec4 y_st_rect;
vec4 u_st_rect;
vec4 v_st_rect;
vec2 size;
int color_space;
};
YuvImage fetch_yuv_image(int index) {
- YuvImage image;
-
- ivec2 uv = get_fetch_uv_1(index);
-
- vec4 size_color_space = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
- image.size = size_color_space.xy;
- image.color_space = int(size_color_space.z);
-
- return image;
+ vec4 data = fetch_data_1(index);
+ return YuvImage(vec4(0.0), vec4(0.0), vec4(0.0), data.xy, int(data.z));
}
struct BoxShadow {
vec4 src_rect;
vec4 bs_rect;
vec4 color;
vec4 border_radius_edge_size_blur_radius_inverted;
};
BoxShadow fetch_boxshadow(int index) {
- BoxShadow bs;
-
- ivec2 uv = get_fetch_uv_4(index);
-
- bs.src_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
- bs.bs_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
- bs.color = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
- bs.border_radius_edge_size_blur_radius_inverted = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
-
- return bs;
+ vec4 data[4] = fetch_data_4(index);
+ return BoxShadow(data[0], data[1], data[2], data[3]);
}
void write_clip(vec2 global_pos, ClipArea area) {
vec2 texture_size = vec2(textureSize(sCacheA8, 0).xy);
vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
- vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
+ vClipMaskUvBounds = RectWithEndpoint(area.task_bounds.xy / texture_size,
+ area.task_bounds.zw / texture_size);
vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
}
#endif //WR_VERTEX_SHADER
#ifdef WR_FRAGMENT_SHADER
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));
}
-vec2 init_transform_fs(vec3 local_pos, vec4 local_rect, out float fragment_alpha) {
+vec2 init_transform_fs(vec3 local_pos, RectWithSize local_rect, out float fragment_alpha) {
fragment_alpha = 1.0;
vec2 pos = local_pos.xy / local_pos.z;
// Because the local rect is placed on whole coordinates, but the interpolation
// occurs at pixel centers, we need to offset the signed distance by that amount.
// In the simple case of no zoom, and no transform, this is 0.5. However, we
// need to scale this by the amount that the local rect is changing by per
// fragment, based on the current zoom and transform.
vec2 fw = fwidth(pos.xy);
vec2 dxdy = 0.5 * fw;
// Now get the actual signed distance. Inset the local rect by the offset amount
// above to get correct distance values. This ensures that we only apply
// anti-aliasing when the fragment has partial coverage.
float d = signed_distance_rect(pos,
- local_rect.xy + dxdy,
- local_rect.xy + local_rect.zw - dxdy);
+ local_rect.p0 + dxdy,
+ local_rect.p0 + local_rect.size - dxdy);
// Find the appropriate distance to apply the AA smoothstep over.
float afwidth = 0.5 / length(fw);
// Only apply AA to fragments outside the signed distance field.
fragment_alpha = 1.0 - smoothstep(0.0, afwidth, d);
return pos;
}
float do_clip() {
// anything outside of the mask is considered transparent
bvec4 inside = lessThanEqual(
- vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
- vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
+ vec4(vClipMaskUvBounds.p0, vClipMaskUv.xy),
+ vec4(vClipMaskUv.xy, vClipMaskUvBounds.p1));
// check for the dummy bounds, which are given to the opaque objects
- return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
+ return vClipMaskUvBounds.p0 == vClipMaskUvBounds.p1 ? 1.0:
all(inside) ? textureLod(sCacheA8, vClipMaskUv, 0.0).r : 0.0;
}
vec4 dither(vec4 color) {
const int matrix_mask = 7;
ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask);
float noise_normalized = (texelFetch(sDither, pos, 0).r * 255.0 + 0.5) / 64.0;
--- a/gfx/webrender/res/ps_angle_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_angle_gradient.vs.glsl
@@ -6,17 +6,18 @@
void main(void) {
Primitive prim = load_primitive();
Gradient gradient = fetch_gradient(prim.prim_index);
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
vPos = vi.local_pos - prim.local_rect.p0;
vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw;
vec2 dir = end_point - start_point;
vStartPoint = start_point;
--- a/gfx/webrender/res/ps_border.fs.glsl
+++ b/gfx/webrender/res/ps_border.fs.glsl
@@ -170,61 +170,52 @@ vec4 draw_dashed_edge(float position, fl
if (mod(segment + 2.0, 2.0) == 0.0) {
return vHorizontalColor * vec4(1.0, 1.0, 1.0, 1.0 - alpha);
} else {
return vHorizontalColor * vec4(1.0, 1.0, 1.0, alpha);
}
}
-void draw_dashed_or_dotted_border(vec2 local_pos, float distance_from_mix_line) {
+vec4 draw_dashed_or_dotted_border(vec2 local_pos, float distance_from_mix_line) {
// This is the conversion factor for transformations and device pixel scaling.
float pixels_per_fragment = length(fwidth(local_pos.xy));
switch (vBorderPart) {
// These are the layer tile part PrimitivePart as uploaded by the tiling.rs
case PST_TOP_LEFT:
case PST_TOP_RIGHT:
case PST_BOTTOM_LEFT:
case PST_BOTTOM_RIGHT:
{
- oFragColor = get_fragment_color(distance_from_mix_line, pixels_per_fragment);
+ vec4 color = get_fragment_color(distance_from_mix_line, pixels_per_fragment);
if (vRadii.x > 0.0) {
- oFragColor *= vec4(1.0, 1.0, 1.0, alpha_for_solid_border_corner(local_pos,
- vRadii.zw,
- vRadii.xy,
- pixels_per_fragment));
+ color.a *= alpha_for_solid_border_corner(local_pos,
+ vRadii.zw,
+ vRadii.xy,
+ pixels_per_fragment);
}
-
- break;
+ return color;
}
case PST_BOTTOM:
case PST_TOP: {
- if (vBorderStyle == BORDER_STYLE_DASHED) {
- oFragColor = draw_dashed_edge(vLocalPos.x - vPieceRect.x,
- vPieceRect.w,
- pixels_per_fragment);
- } else {
- oFragColor = draw_dotted_edge(local_pos.yx, vPieceRect.yxwz, pixels_per_fragment);
- }
- break;
+ return vBorderStyle == BORDER_STYLE_DASHED ?
+ draw_dashed_edge(vLocalPos.x - vPieceRect.x, vPieceRect.w, pixels_per_fragment) :
+ draw_dotted_edge(local_pos.yx, vPieceRect.yxwz, pixels_per_fragment);
}
case PST_LEFT:
case PST_RIGHT:
{
- if (vBorderStyle == BORDER_STYLE_DASHED) {
- oFragColor = draw_dashed_edge(vLocalPos.y - vPieceRect.y,
- vPieceRect.z,
- pixels_per_fragment);
- } else {
- oFragColor = draw_dotted_edge(local_pos.xy, vPieceRect.xyzw, pixels_per_fragment);
- }
- break;
+ return vBorderStyle == BORDER_STYLE_DASHED ?
+ draw_dashed_edge(vLocalPos.y - vPieceRect.y, vPieceRect.z, pixels_per_fragment) :
+ draw_dotted_edge(local_pos.xy, vPieceRect.xyzw, pixels_per_fragment);
}
}
+
+ return vec4(0.0);
}
vec4 draw_double_edge(float pos,
float len,
float distance_from_mix_line,
float pixels_per_fragment) {
float total_border_width = len;
float one_third_width = total_border_width / 3.0;
@@ -292,187 +283,164 @@ vec4 draw_double_edge_corner(vec2 local_
distance_from_mix_line >= 0.0;
if (is_vertical) {
return draw_double_edge_vertical(local_pos, distance_from_mix_line, pixels_per_fragment);
} else {
return draw_double_edge_horizontal(local_pos, distance_from_mix_line, pixels_per_fragment);
}
}
-void draw_double_border(float distance_from_mix_line, vec2 local_pos) {
+vec4 draw_double_border(float distance_from_mix_line, vec2 local_pos) {
float pixels_per_fragment = length(fwidth(local_pos.xy));
switch (vBorderPart) {
// These are the layer tile part PrimitivePart as uploaded by the tiling.rs
case PST_TOP_LEFT:
case PST_TOP_RIGHT:
case PST_BOTTOM_LEFT:
case PST_BOTTOM_RIGHT:
- {
- oFragColor = draw_double_edge_corner(local_pos, distance_from_mix_line, pixels_per_fragment);
- break;
- }
+ return draw_double_edge_corner(local_pos, distance_from_mix_line, pixels_per_fragment);
case PST_BOTTOM:
case PST_TOP:
- {
- oFragColor = draw_double_edge_horizontal(local_pos,
- distance_from_mix_line,
- pixels_per_fragment);
- break;
- }
+ return draw_double_edge_horizontal(local_pos,
+ distance_from_mix_line,
+ pixels_per_fragment);
case PST_LEFT:
case PST_RIGHT:
- {
- oFragColor = draw_double_edge_vertical(local_pos,
- distance_from_mix_line,
- pixels_per_fragment);
- break;
- }
+ return draw_double_edge_vertical(local_pos,
+ distance_from_mix_line,
+ pixels_per_fragment);
}
+ return vec4(0.0);
}
-void draw_solid_border(float distanceFromMixLine, vec2 localPos) {
+vec4 draw_solid_border(float distanceFromMixLine, vec2 localPos) {
switch (vBorderPart) {
case PST_TOP_LEFT:
case PST_TOP_RIGHT:
case PST_BOTTOM_LEFT:
case PST_BOTTOM_RIGHT: {
// This is the conversion factor for transformations and device pixel scaling.
float pixelsPerFragment = length(fwidth(localPos.xy));
- oFragColor = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
+ vec4 color = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
if (vRadii.x > 0.0) {
- float alpha = alpha_for_solid_border_corner(localPos, vRadii.zw, vRadii.xy, pixelsPerFragment);
- oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
+ color.a *= alpha_for_solid_border_corner(localPos, vRadii.zw, vRadii.xy, pixelsPerFragment);
}
- break;
+ return color;
}
default:
- oFragColor = vHorizontalColor;
discard_pixels_in_rounded_borders(localPos);
- break;
+ return vHorizontalColor;
}
}
vec4 draw_mixed_edge(float distance, float border_len, vec4 color, vec2 brightness_mod) {
float modulator = distance / border_len > 0.5 ? brightness_mod.x : brightness_mod.y;
return vec4(color.xyz * modulator, color.a);
}
-void draw_mixed_border(float distanceFromMixLine, float distanceFromMiddle, vec2 localPos, vec2 brightness_mod) {
+vec4 draw_mixed_border(float distanceFromMixLine, float distanceFromMiddle, vec2 localPos, vec2 brightness_mod) {
switch (vBorderPart) {
case PST_TOP_LEFT:
case PST_TOP_RIGHT:
case PST_BOTTOM_LEFT:
case PST_BOTTOM_RIGHT: {
// This is the conversion factor for transformations and device pixel scaling.
float pixelsPerFragment = length(fwidth(localPos.xy));
vec4 color = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
if (vRadii.x > 0.0) {
float distance = distance(vRefPoint, localPos) - vRadii.z;
float length = vRadii.x - vRadii.z;
if (distanceFromMiddle < 0.0) {
distance = length - distance;
}
- oFragColor = 0.0 <= distance && distance <= length ?
- draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
- break;
+ return 0.0 <= distance && distance <= length ?
+ draw_mixed_edge(distance, length, color, brightness_mod) :
+ vec4(0.0, 0.0, 0.0, 0.0);
}
bool is_vertical = (vBorderPart == PST_TOP_LEFT) ? distanceFromMixLine < 0.0 :
distanceFromMixLine >= 0.0;
float distance = is_vertical ? abs(localPos.x - vRefPoint.x) : abs(localPos.y - vRefPoint.y);
float length = is_vertical ? abs(vPieceRect.z) : abs(vPieceRect.w);
if (distanceFromMiddle > 0.0) {
distance = length - distance;
}
- oFragColor = 0.0 <= distance && distance <= length ?
- draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
- break;
+ return 0.0 <= distance && distance <= length ?
+ draw_mixed_edge(distance, length, color, brightness_mod) :
+ vec4(0.0, 0.0, 0.0, 0.0);
}
case PST_BOTTOM:
- case PST_TOP: {
- oFragColor = draw_mixed_edge(localPos.y - vPieceRect.y, vPieceRect.w, vVerticalColor, brightness_mod);
- break;
- }
+ case PST_TOP:
+ return draw_mixed_edge(localPos.y - vPieceRect.y, vPieceRect.w, vVerticalColor, brightness_mod);
case PST_LEFT:
- case PST_RIGHT: {
- oFragColor = draw_mixed_edge(localPos.x - vPieceRect.x, vPieceRect.z, vHorizontalColor, brightness_mod);
+ case PST_RIGHT:
+ return draw_mixed_edge(localPos.x - vPieceRect.x, vPieceRect.z, vHorizontalColor, brightness_mod);
+ }
+ return vec4(0.0);
+}
+
+vec4 draw_complete_border(vec2 local_pos, float distance_from_mix_line, float distance_from_middle) {
+ vec2 brightness_mod = vec2(0.7, 1.3);
+
+ // Note: we can't pass-through in the following cases,
+ // because Angle doesn't support it and fails to compile the shaders.
+ switch (vBorderStyle) {
+ case BORDER_STYLE_DASHED:
+ return draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+ case BORDER_STYLE_DOTTED:
+ return draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+ case BORDER_STYLE_DOUBLE:
+ return draw_double_border(distance_from_mix_line, local_pos);
+ case BORDER_STYLE_OUTSET:
+ return draw_solid_border(distance_from_mix_line, local_pos);
+ case BORDER_STYLE_INSET:
+ return draw_solid_border(distance_from_mix_line, local_pos);
+ case BORDER_STYLE_SOLID:
+ return draw_solid_border(distance_from_mix_line, local_pos);
+ case BORDER_STYLE_NONE:
+ return draw_solid_border(distance_from_mix_line, local_pos);
+ case BORDER_STYLE_GROOVE:
+ return draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.yx);
+ case BORDER_STYLE_RIDGE:
+ return draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.xy);
+ case BORDER_STYLE_HIDDEN:
+ default:
break;
- }
}
+
+ // Note: Workaround for Angle on Windows,
+ // because non-empty case statements must have break or return.
+ discard;
+ return vec4(0.0);
}
// TODO: Investigate performance of this shader and see
// if it's worthwhile splitting it / removing branches etc.
void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = 0.0;
vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
#else
+ float alpha = 1.0;
vec2 local_pos = vLocalPos;
#endif
#ifdef WR_FEATURE_TRANSFORM
// TODO(gw): Support other border styles for transformed elements.
float distance_from_mix_line = (local_pos.x - vPieceRect.x) * vPieceRect.w -
(local_pos.y - vPieceRect.y) * vPieceRect.z;
distance_from_mix_line /= vPieceRectHypotenuseLength;
- float distance_from_middle = (local_pos.x - vLocalRect.x) +
- (local_pos.y - vLocalRect.y) -
- 0.5 * (vLocalRect.z + vLocalRect.w);
+ float distance_from_middle = (local_pos.x - vBorderRect.p0.x) +
+ (local_pos.y - vBorderRect.p0.y) -
+ 0.5 * (vBorderRect.size.x + vBorderRect.size.y);
#else
float distance_from_mix_line = vDistanceFromMixLine;
float distance_from_middle = vDistanceFromMiddle;
#endif
- vec2 brightness_mod = vec2(0.7, 1.3);
- bool needs_discard = false;
-
- // Note: we can't pass-through in the following cases,
- // because Angle doesn't support it and fails to compile the shaders.
- switch (vBorderStyle) {
- case BORDER_STYLE_DASHED:
- draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
- break;
- case BORDER_STYLE_DOTTED:
- draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
- break;
- case BORDER_STYLE_DOUBLE:
- draw_double_border(distance_from_mix_line, local_pos);
- break;
- case BORDER_STYLE_OUTSET:
- draw_solid_border(distance_from_mix_line, local_pos);
- break;
- case BORDER_STYLE_INSET:
- draw_solid_border(distance_from_mix_line, local_pos);
- break;
- case BORDER_STYLE_SOLID:
- draw_solid_border(distance_from_mix_line, local_pos);
- break;
- case BORDER_STYLE_NONE:
- draw_solid_border(distance_from_mix_line, local_pos);
- break;
- case BORDER_STYLE_GROOVE:
- draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.yx);
- break;
- case BORDER_STYLE_RIDGE:
- draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.xy);
- break;
- case BORDER_STYLE_HIDDEN:
- default:
- needs_discard = true;
- break;
- }
-
- // Note: Workaround for Angle on Windows,
- // because non-empty case statements must have break or return.
- if (needs_discard) {
- discard;
- }
-
-#ifdef WR_FEATURE_TRANSFORM
- oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
-#endif
+ oFragColor = draw_complete_border(local_pos, distance_from_mix_line, distance_from_middle);
+ oFragColor.a *= min(alpha, do_clip());
}
--- a/gfx/webrender/res/ps_border.glsl
+++ b/gfx/webrender/res/ps_border.glsl
@@ -1,31 +1,32 @@
#line 1
/* 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/. */
// These are not changing.
-flat varying vec4 vVerticalColor; // The vertical color, e.g. top/bottom
-flat varying vec4 vHorizontalColor; // The horizontal color e.g. left/right
-flat varying vec4 vRadii; // The border radius from CSS border-radius
-flat varying vec4 vLocalRect; // The rect of the border (x, y, w, h) in local space.
+flat varying vec4 vVerticalColor; // The vertical color, e.g. top/bottom
+flat varying vec4 vHorizontalColor; // The horizontal color e.g. left/right
+flat varying vec4 vRadii; // The border radius from CSS border-radius
+flat varying RectWithSize vBorderRect; // The rect of the border in local space.
// for corners, this is the beginning of the corner.
// For the lines, this is the top left of the line.
flat varying vec2 vRefPoint;
flat varying int vBorderStyle;
flat varying int vBorderPart; // Which part of the border we're drawing.
flat varying vec4 vPieceRect;
// These are in device space
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos; // The clamped position in local space.
+flat varying RectWithSize vLocalRect;
flat varying float vPieceRectHypotenuseLength;
#else
varying vec2 vLocalPos; // The clamped position in local space.
// These two are interpolated
varying float vDistanceFromMixLine; // This is the distance from the line where two colors
// meet in border corners.
varying float vDistanceFromMiddle; // This is the distance from the line between the top
--- a/gfx/webrender/res/ps_border.vs.glsl
+++ b/gfx/webrender/res/ps_border.vs.glsl
@@ -1,58 +1,35 @@
#line 1
/* 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/. */
-struct Border {
- vec4 style;
- vec4 widths;
- vec4 colors[4];
- vec4 radii[2];
-};
-
-Border fetch_border(int index) {
- Border border;
-
- ivec2 uv = get_fetch_uv_8(index);
-
- border.style = texelFetchOffset(sData128, uv, 0, ivec2(0, 0));
- border.widths = texelFetchOffset(sData128, uv, 0, ivec2(1, 0));
- border.colors[0] = texelFetchOffset(sData128, uv, 0, ivec2(2, 0));
- border.colors[1] = texelFetchOffset(sData128, uv, 0, ivec2(3, 0));
- border.colors[2] = texelFetchOffset(sData128, uv, 0, ivec2(4, 0));
- border.colors[3] = texelFetchOffset(sData128, uv, 0, ivec2(5, 0));
- border.radii[0] = texelFetchOffset(sData128, uv, 0, ivec2(6, 0));
- border.radii[1] = texelFetchOffset(sData128, uv, 0, ivec2(7, 0));
-
- return border;
-}
-
void main(void) {
Primitive prim = load_primitive();
Border border = fetch_border(prim.prim_index);
int sub_part = prim.sub_index;
+ vBorderRect = prim.local_rect;
- vec2 tl_outer = prim.local_rect.p0;
+ vec2 tl_outer = vBorderRect.p0;
vec2 tl_inner = tl_outer + vec2(max(border.radii[0].x, border.widths.x),
max(border.radii[0].y, border.widths.y));
- vec2 tr_outer = vec2(prim.local_rect.p0.x + prim.local_rect.size.x,
- prim.local_rect.p0.y);
+ vec2 tr_outer = vec2(vBorderRect.p0.x + vBorderRect.size.x,
+ vBorderRect.p0.y);
vec2 tr_inner = tr_outer + vec2(-max(border.radii[0].z, border.widths.z),
max(border.radii[0].w, border.widths.y));
- vec2 br_outer = vec2(prim.local_rect.p0.x + prim.local_rect.size.x,
- prim.local_rect.p0.y + prim.local_rect.size.y);
+ vec2 br_outer = vec2(vBorderRect.p0.x + vBorderRect.size.x,
+ vBorderRect.p0.y + vBorderRect.size.y);
vec2 br_inner = br_outer - vec2(max(border.radii[1].x, border.widths.z),
max(border.radii[1].y, border.widths.w));
- vec2 bl_outer = vec2(prim.local_rect.p0.x,
- prim.local_rect.p0.y + prim.local_rect.size.y);
+ vec2 bl_outer = vec2(vBorderRect.p0.x,
+ vBorderRect.p0.y + vBorderRect.size.y);
vec2 bl_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x),
-max(border.radii[1].w, border.widths.w));
RectWithSize segment_rect;
switch (sub_part) {
case PST_TOP_LEFT:
segment_rect.p0 = tl_outer;
segment_rect.size = tl_inner - tl_outer;
@@ -123,32 +100,31 @@ void main(void) {
break;
}
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
vLocalPos = vi.local_pos;
-
- // Local space
- vLocalRect = vi.clipped_local_rect;
+ vLocalRect = segment_rect;
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
vLocalPos = vi.local_pos.xy;
+#endif
- // Local space
- vLocalRect = vec4(prim.local_rect.p0, prim.local_rect.size);
-#endif
+ write_clip(vi.screen_pos, prim.clip_area);
float x0, y0, x1, y1;
switch (sub_part) {
// These are the layer tile part PrimitivePart as uploaded by the tiling.rs
case PST_TOP_LEFT:
x0 = segment_rect.p0.x;
y0 = segment_rect.p0.y;
// These are width / heights
@@ -204,13 +180,13 @@ void main(void) {
// to properly mix border colors. For transformed borders, we calculate this distance
// in the fragment shader itself. For non-transformed borders, we can use the
// interpolator.
#ifdef WR_FEATURE_TRANSFORM
vPieceRectHypotenuseLength = sqrt(pow(width, 2.0) + pow(height, 2.0));
#else
vDistanceFromMixLine = (vi.local_pos.x - x0) * height -
(vi.local_pos.y - y0) * width;
- vDistanceFromMiddle = (vi.local_pos.x - vLocalRect.x) +
- (vi.local_pos.y - vLocalRect.y) -
- 0.5 * (vLocalRect.z + vLocalRect.w);
+ vDistanceFromMiddle = (vi.local_pos.x - vBorderRect.p0.x) +
+ (vi.local_pos.y - vBorderRect.p0.y) -
+ 0.5 * (vBorderRect.size.x + vBorderRect.size.y);
#endif
}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_corner.fs.glsl
@@ -0,0 +1,122 @@
+#line 1
+/* 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/. */
+
+//
+// Signed distance to an ellipse.
+// Taken from http://www.iquilezles.org/www/articles/ellipsedist/ellipsedist.htm
+// Note that this fails for exact circles.
+//
+float sdEllipse( vec2 p, in vec2 ab ) {
+ p = abs( p ); if( p.x > p.y ){ p=p.yx; ab=ab.yx; }
+ float l = ab.y*ab.y - ab.x*ab.x;
+
+ float m = ab.x*p.x/l;
+ float n = ab.y*p.y/l;
+ float m2 = m*m;
+ float n2 = n*n;
+
+ float c = (m2 + n2 - 1.0)/3.0;
+ float c3 = c*c*c;
+
+ float q = c3 + m2*n2*2.0;
+ float d = c3 + m2*n2;
+ float g = m + m*n2;
+
+ float co;
+
+ if( d<0.0 )
+ {
+ float p = acos(q/c3)/3.0;
+ float s = cos(p);
+ float t = sin(p)*sqrt(3.0);
+ float rx = sqrt( -c*(s + t + 2.0) + m2 );
+ float ry = sqrt( -c*(s - t + 2.0) + m2 );
+ co = ( ry + sign(l)*rx + abs(g)/(rx*ry) - m)/2.0;
+ }
+ else
+ {
+ float h = 2.0*m*n*sqrt( d );
+ float s = sign(q+h)*pow( abs(q+h), 1.0/3.0 );
+ float u = sign(q-h)*pow( abs(q-h), 1.0/3.0 );
+ float rx = -s - u - c*4.0 + 2.0*m2;
+ float ry = (s - u)*sqrt(3.0);
+ float rm = sqrt( rx*rx + ry*ry );
+ float p = ry/sqrt(rm-rx);
+ co = (p + 2.0*g/rm - m)/2.0;
+ }
+
+ float si = sqrt( 1.0 - co*co );
+
+ vec2 r = vec2( ab.x*co, ab.y*si );
+
+ return length(r - p ) * sign(p.y-r.y);
+}
+
+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);
+}
+
+void main(void) {
+ float alpha = 1.0;
+#ifdef WR_FEATURE_TRANSFORM
+ alpha = 0.0;
+ vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+#else
+ vec2 local_pos = vLocalPos;
+#endif
+
+ alpha = min(alpha, do_clip());
+
+ // Find the appropriate distance to apply the AA smoothstep over.
+ vec2 fw = fwidth(local_pos);
+ float afwidth = length(fw);
+
+ // Only apply the clip AA if inside the clip region. This is
+ // necessary for correctness when the border width is greater
+ // than the border radius.
+ if (all(lessThan(local_pos * vClipSign, vClipCenter * vClipSign))) {
+ float d0, d1;
+
+ // sdEllipse fails on exact circles, so handle equal
+ // radii here. The branch coherency should make this
+ // a performance win for the circle case too.
+ if (vOuterRadii.x == vOuterRadii.y) {
+ // Get the distances to the inner and outer radii.
+ d0 = distance(vClipCenter, local_pos) - vOuterRadii.x;
+ } else {
+ // Get the distance to the outer ellipse.
+ vec2 p = local_pos - vClipCenter;
+ d0 = sdEllipse(p, vOuterRadii);
+ }
+
+ if (vInnerRadii.x == vInnerRadii.y) {
+ d1 = distance(vClipCenter, local_pos) - vInnerRadii.x;
+ } else {
+ // Get distance to inner ellipse. Skip if the inner
+ // radius is <= 0.0 to avoid FP errors.
+ if (vInnerRadii.x <= 0.0 || vInnerRadii.y <= 0.0) {
+ d1 = -d0;
+ } else {
+ vec2 p = local_pos - vClipCenter;
+ d1 = sdEllipse(p, vInnerRadii);
+ }
+ }
+
+ // Signed distance field subtract
+ float d = max(d0, 0.5 * afwidth - d1);
+
+ // Only apply AA to fragments outside the signed distance field.
+ alpha = min(alpha, 1.0 - smoothstep(0.0, afwidth, d));
+ }
+
+ // Select color based on side of line. Get distance from the
+ // reference line, and then apply AA along the edge.
+ float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
+ float m = smoothstep(-0.5 * afwidth, 0.5 * afwidth, ld);
+ vec4 color = mix(vColor0, vColor1, m);
+
+ oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_corner.glsl
@@ -0,0 +1,22 @@
+#line 1
+/* 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/. */
+
+// Edge color transition
+flat varying vec4 vColor0;
+flat varying vec4 vColor1;
+flat varying vec4 vColorEdgeLine;
+
+// Border radius
+flat varying vec2 vClipCenter;
+flat varying vec2 vOuterRadii;
+flat varying vec2 vInnerRadii;
+flat varying vec2 vClipSign;
+
+#ifdef WR_FEATURE_TRANSFORM
+flat varying RectWithSize vLocalRect;
+varying vec3 vLocalPos;
+#else
+varying vec2 vLocalPos;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_corner.vs.glsl
@@ -0,0 +1,112 @@
+#line 1
+/* 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/. */
+
+void set_radii(vec2 border_radius,
+ vec2 border_width,
+ vec2 outer_corner,
+ vec2 gradient_sign) {
+ if (border_radius.x > 0.0 && border_radius.y > 0.0) {
+ // Set inner/outer radius on valid border radius.
+ vOuterRadii = border_radius;
+ } else {
+ // No border radius - ensure clip has no effect.
+ vOuterRadii = vec2(2.0 * border_width);
+ }
+
+ if (border_radius.x > border_width.x && border_radius.y > border_width.y) {
+ vInnerRadii = max(vec2(0.0), border_radius - border_width);
+ } else {
+ vInnerRadii = vec2(0.0);
+ }
+
+ vec2 gradient = border_width * gradient_sign;
+ vColorEdgeLine = vec4(outer_corner, vec2(-gradient.y, gradient.x));
+}
+
+void main(void) {
+ Primitive prim = load_primitive();
+ Border border = fetch_border(prim.prim_index);
+ int sub_part = prim.sub_index;
+ BorderCorners corners = get_border_corners(border, prim.local_rect);
+
+ RectWithSize segment_rect;
+ switch (sub_part) {
+ case 0: {
+ segment_rect.p0 = corners.tl_outer;
+ segment_rect.size = corners.tl_inner - corners.tl_outer;
+ vColor0 = border.colors[0];
+ vColor1 = border.colors[1];
+ vClipCenter = corners.tl_outer + border.radii[0].xy;
+ vClipSign = vec2(1.0);
+ set_radii(border.radii[0].xy,
+ border.widths.xy,
+ corners.tl_outer,
+ vec2(1.0, 1.0));
+ break;
+ }
+ case 1: {
+ segment_rect.p0 = vec2(corners.tr_inner.x, corners.tr_outer.y);
+ segment_rect.size = vec2(corners.tr_outer.x - corners.tr_inner.x,
+ corners.tr_inner.y - corners.tr_outer.y);
+ vColor0 = border.colors[1];
+ vColor1 = border.colors[2];
+ vClipCenter = corners.tr_outer + vec2(-border.radii[0].z, border.radii[0].w);
+ vClipSign = vec2(-1.0, 1.0);
+ set_radii(border.radii[0].zw,
+ border.widths.zy,
+ corners.tr_outer,
+ vec2(-1.0, 1.0));
+ break;
+ }
+ case 2: {
+ segment_rect.p0 = corners.br_inner;
+ segment_rect.size = corners.br_outer - corners.br_inner;
+ vColor0 = border.colors[2];
+ vColor1 = border.colors[3];
+ vClipCenter = corners.br_outer - border.radii[1].xy;
+ vClipSign = vec2(-1.0, -1.0);
+ set_radii(border.radii[1].xy,
+ border.widths.zw,
+ corners.br_outer,
+ vec2(-1.0, -1.0));
+ break;
+ }
+ case 3: {
+ segment_rect.p0 = vec2(corners.bl_outer.x, corners.bl_inner.y);
+ segment_rect.size = vec2(corners.bl_inner.x - corners.bl_outer.x,
+ corners.bl_outer.y - corners.bl_inner.y);
+ vColor0 = border.colors[3];
+ vColor1 = border.colors[0];
+ vClipCenter = corners.bl_outer + vec2(border.radii[1].z, -border.radii[1].w);
+ vClipSign = vec2(1.0, -1.0);
+ set_radii(border.radii[1].zw,
+ border.widths.xw,
+ corners.bl_outer,
+ vec2(1.0, -1.0));
+ break;
+ }
+ }
+
+#ifdef WR_FEATURE_TRANSFORM
+ TransformVertexInfo vi = write_transform_vertex(segment_rect,
+ prim.local_clip_rect,
+ prim.z,
+ prim.layer,
+ prim.task,
+ prim.local_rect.p0);
+ vLocalPos = vi.local_pos;
+ vLocalRect = segment_rect;
+#else
+ VertexInfo vi = write_vertex(segment_rect,
+ prim.local_clip_rect,
+ prim.z,
+ prim.layer,
+ prim.task,
+ prim.local_rect.p0);
+ vLocalPos = vi.local_pos.xy;
+#endif
+
+ write_clip(vi.screen_pos, prim.clip_area);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_edge.fs.glsl
@@ -0,0 +1,15 @@
+/* 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/. */
+
+void main(void) {
+ float alpha = 1.0;
+#ifdef WR_FEATURE_TRANSFORM
+ alpha = 0.0;
+ init_transform_fs(vLocalPos, vLocalRect, alpha);
+#endif
+
+ alpha = min(alpha, do_clip());
+
+ oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_edge.glsl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+flat varying vec4 vColor;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying RectWithSize vLocalRect;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border_edge.vs.glsl
@@ -0,0 +1,53 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+ Primitive prim = load_primitive();
+ Border border = fetch_border(prim.prim_index);
+ int sub_part = prim.sub_index;
+ BorderCorners corners = get_border_corners(border, prim.local_rect);
+
+ vColor = border.colors[sub_part];
+
+ RectWithSize segment_rect;
+ switch (sub_part) {
+ case 0:
+ segment_rect.p0 = vec2(corners.tl_outer.x, corners.tl_inner.y);
+ segment_rect.size = vec2(border.widths.x, corners.bl_inner.y - corners.tl_inner.y);
+ break;
+ case 1:
+ segment_rect.p0 = vec2(corners.tl_inner.x, corners.tl_outer.y);
+ segment_rect.size = vec2(corners.tr_inner.x - corners.tl_inner.x, border.widths.y);
+ break;
+ case 2:
+ segment_rect.p0 = vec2(corners.tr_outer.x - border.widths.z, corners.tr_inner.y);
+ segment_rect.size = vec2(border.widths.z, corners.br_inner.y - corners.tr_inner.y);
+ break;
+ case 3:
+ segment_rect.p0 = vec2(corners.bl_inner.x, corners.bl_outer.y - border.widths.w);
+ segment_rect.size = vec2(corners.br_inner.x - corners.bl_inner.x, border.widths.w);
+ break;
+ }
+
+#ifdef WR_FEATURE_TRANSFORM
+ TransformVertexInfo vi = write_transform_vertex(segment_rect,
+ prim.local_clip_rect,
+ prim.z,
+ prim.layer,
+ prim.task,
+ prim.local_rect.p0);
+ vLocalPos = vi.local_pos;
+ vLocalRect = segment_rect;
+#else
+ VertexInfo vi = write_vertex(segment_rect,
+ prim.local_clip_rect,
+ prim.z,
+ prim.layer,
+ prim.task,
+ prim.local_rect.p0);
+#endif
+
+ write_clip(vi.screen_pos, prim.clip_area);
+}
--- a/gfx/webrender/res/ps_box_shadow.vs.glsl
+++ b/gfx/webrender/res/ps_box_shadow.vs.glsl
@@ -7,17 +7,18 @@ void main(void) {
Primitive prim = load_primitive();
BoxShadow bs = fetch_boxshadow(prim.prim_index);
RectWithSize segment_rect = fetch_instance_geometry(prim.sub_index);
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
RenderTaskData child_task = fetch_render_task(prim.user_data.x);
vUv.z = child_task.data1.x;
// Constant offsets to inset from bilinear filtering border.
vec2 patch_origin = child_task.data0.xy + vec2(1.0);
vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0);
vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio;
--- a/gfx/webrender/res/ps_cache_image.vs.glsl
+++ b/gfx/webrender/res/ps_cache_image.vs.glsl
@@ -8,17 +8,18 @@
void main(void) {
Primitive prim = load_primitive();
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
RenderTaskData child_task = fetch_render_task(prim.user_data.x);
vUv.z = child_task.data1.x;
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));
vec2 uv0 = child_task.data0.xy / texture_size;
vec2 uv1 = (child_task.data0.xy + child_task.data0.zw) / texture_size;
--- a/gfx/webrender/res/ps_gradient.glsl
+++ b/gfx/webrender/res/ps_gradient.glsl
@@ -1,12 +1,12 @@
/* 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/. */
varying vec4 vColor;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
#else
varying vec2 vPos;
#endif
--- a/gfx/webrender/res/ps_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_gradient.vs.glsl
@@ -56,26 +56,28 @@ void main(void) {
adjusted_color_g1 = mix(g0.color, g1.color, adjusted_offset.y);
}
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalRect = vi.clipped_local_rect;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalRect = segment_rect;
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
#else
VertexInfo vi = write_vertex(segment_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
vec2 f = (vi.local_pos - segment_rect.p0) / segment_rect.size;
vPos = vi.local_pos;
#endif
write_clip(vi.screen_pos, prim.clip_area);
vColor = mix(adjusted_color_g0, adjusted_color_g1, dot(f, axis));
--- a/gfx/webrender/res/ps_image.fs.glsl
+++ b/gfx/webrender/res/ps_image.fs.glsl
@@ -6,18 +6,17 @@
void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = 0.0;
vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
// We clamp the texture coordinate calculation here to the local rectangle boundaries,
// which makes the edge of the texture stretch instead of repeat.
- vec2 relative_pos_in_rect =
- clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+ vec2 relative_pos_in_rect = clamp_rect(pos, vLocalRect) - vLocalRect.p0;
#else
float alpha = 1.0;
vec2 relative_pos_in_rect = vLocalPos;
#endif
alpha = min(alpha, do_clip());
// We calculate the particular tile this fragment belongs to, taking into
--- a/gfx/webrender/res/ps_image.glsl
+++ b/gfx/webrender/res/ps_image.glsl
@@ -7,14 +7,14 @@
// check GL_TEXTURE_RECTANGLE.
flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas.
flat varying vec2 vTextureSize; // Size of the image in the texture atlas.
flat varying vec2 vTileSpacing; // Amount of space between tiled instances of this image.
flat varying vec4 vStRect; // Rectangle of valid texture rect.
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
flat varying vec2 vStretchSize;
#else
varying vec2 vLocalPos;
flat varying vec2 vStretchSize;
#endif
--- a/gfx/webrender/res/ps_image.vs.glsl
+++ b/gfx/webrender/res/ps_image.vs.glsl
@@ -8,26 +8,28 @@ void main(void) {
Image image = fetch_image(prim.prim_index);
ResourceRect res = fetch_resource_rect(prim.user_data.x);
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalRect = vi.clipped_local_rect;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalRect = prim.local_rect;
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalPos = vi.local_pos - vi.local_rect.p0;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalPos = vi.local_pos - prim.local_rect.p0;
#endif
write_clip(vi.screen_pos, prim.clip_area);
vTileSpacing = image.stretch_size_and_tile_spacing.zw;
vStretchSize = image.stretch_size_and_tile_spacing.xy;
// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use
--- a/gfx/webrender/res/ps_radial_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_radial_gradient.vs.glsl
@@ -6,17 +6,18 @@
void main(void) {
Primitive prim = load_primitive();
RadialGradient gradient = fetch_radial_gradient(prim.prim_index);
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
vPos = vi.local_pos - prim.local_rect.p0;
vStartCenter = gradient.start_end_center.xy;
vEndCenter = gradient.start_end_center.zw;
vStartRadius = gradient.start_end_radius_ratio_xy_extend_mode.x;
vEndRadius = gradient.start_end_radius_ratio_xy_extend_mode.y;
--- a/gfx/webrender/res/ps_rectangle.glsl
+++ b/gfx/webrender/res/ps_rectangle.glsl
@@ -1,10 +1,10 @@
/* 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/. */
varying vec4 vColor;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
#endif
--- a/gfx/webrender/res/ps_rectangle.vs.glsl
+++ b/gfx/webrender/res/ps_rectangle.vs.glsl
@@ -7,23 +7,25 @@ void main(void) {
Primitive prim = load_primitive();
Rectangle rect = fetch_rectangle(prim.prim_index);
vColor = rect.color;
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalRect = vi.clipped_local_rect;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalRect = prim.local_rect;
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
+ prim.task,
+ prim.local_rect.p0);
#endif
#ifdef WR_FEATURE_CLIP
write_clip(vi.screen_pos, prim.clip_area);
#endif
}
--- a/gfx/webrender/res/ps_text_run.glsl
+++ b/gfx/webrender/res/ps_text_run.glsl
@@ -3,10 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
flat varying vec4 vColor;
varying vec2 vUv;
flat varying vec4 vUvBorder;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
#endif
--- a/gfx/webrender/res/ps_text_run.vs.glsl
+++ b/gfx/webrender/res/ps_text_run.vs.glsl
@@ -12,27 +12,29 @@ void main(void) {
RectWithSize local_rect = RectWithSize(glyph.offset.xy,
(res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalRect = vi.clipped_local_rect;
+ prim.task,
+ local_rect.p0);
+ vLocalRect = local_rect;
vLocalPos = vi.local_pos;
vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.p0) / local_rect.size;
#else
VertexInfo vi = write_vertex(local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vec2 f = (vi.local_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0);
+ prim.task,
+ local_rect.p0);
+ vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size;
#endif
write_clip(vi.screen_pos, prim.clip_area);
vec2 texture_size = vec2(textureSize(sColor0, 0));
vec2 st0 = res.uv_rect.xy / texture_size;
vec2 st1 = res.uv_rect.zw / texture_size;
--- a/gfx/webrender/res/ps_yuv_image.fs.glsl
+++ b/gfx/webrender/res/ps_yuv_image.fs.glsl
@@ -5,18 +5,17 @@
void main(void) {
#ifdef WR_FEATURE_TRANSFORM
float alpha = 0.0;
vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
// We clamp the texture coordinate calculation here to the local rectangle boundaries,
// which makes the edge of the texture stretch instead of repeat.
- vec2 relative_pos_in_rect =
- clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+ vec2 relative_pos_in_rect = clamp_rect(pos, vLocalRect) - vLocalRect.p0;
#else
float alpha = 1.0;;
vec2 relative_pos_in_rect = vLocalPos;
#endif
alpha = min(alpha, do_clip());
// We clamp the texture coordinates to the half-pixel offset from the borders
--- a/gfx/webrender/res/ps_yuv_image.glsl
+++ b/gfx/webrender/res/ps_yuv_image.glsl
@@ -10,12 +10,12 @@ flat varying vec2 vTextureSizeUv; // Si
flat varying vec2 vStretchSize;
flat varying vec2 vHalfTexelY; // Normalized length of the half of a Y texel.
flat varying vec2 vHalfTexelUv; // Normalized length of the half of u and v texels.
flat varying mat3 vYuvColorMatrix;
#ifdef WR_FEATURE_TRANSFORM
varying vec3 vLocalPos;
-flat varying vec4 vLocalRect;
+flat varying RectWithSize vLocalRect;
#else
varying vec2 vLocalPos;
#endif
--- a/gfx/webrender/res/ps_yuv_image.vs.glsl
+++ b/gfx/webrender/res/ps_yuv_image.vs.glsl
@@ -5,26 +5,28 @@
void main(void) {
Primitive prim = load_primitive();
#ifdef WR_FEATURE_TRANSFORM
TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalRect = vi.clipped_local_rect;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalRect = prim.local_rect;
vLocalPos = vi.local_pos;
#else
VertexInfo vi = write_vertex(prim.local_rect,
prim.local_clip_rect,
prim.z,
prim.layer,
- prim.task);
- vLocalPos = vi.local_pos - vi.local_rect.p0;
+ prim.task,
+ prim.local_rect.p0);
+ vLocalPos = vi.local_pos - prim.local_rect.p0;
#endif
YuvImage image = fetch_yuv_image(prim.prim_index);
ResourceRect y_rect = fetch_resource_rect(prim.user_data.x);
ResourceRect u_rect = fetch_resource_rect(prim.user_data.x + 1);
ResourceRect v_rect = fetch_resource_rect(prim.user_data.x + 2);
vec2 y_texture_size = vec2(textureSize(sColor0, 0));
deleted file mode 100644
--- a/gfx/webrender/src/CLIPPING.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Clipping in WebRender
-
-The WebRender display list allows defining clips in two different ways. The
-first is specified directly on each display item and cannot be reused between
-items. The second is specified using the `SpecificDisplayItem::Clip` display item
-and can be reused between items as well as used to define scrollable regions.
-
-## Clips
-
-Clips are defined using the ClipRegion in both cases.
-
-```rust
-pub struct ClipRegion {
- pub main: LayoutRect,
- pub complex: ItemRange,
- pub image_mask: Option<ImageMask>,
-}
-```
-
-`main` defines a rectangular clip, while the other members make that rectangle
-smaller. `complex`, if it is not empty, defines the boundaries of a rounded
-rectangle. While `image_mask` defines the positioning, repetition, and data of
-a masking image.
-
-## Item Clips
-
-Item clips are simply a `ClipRegion` structure defined directly on the
-`DisplayItem`. The important thing to note about these clips is that all the
-coordinate in `ClipRegion` **are in the same coordinate space as the item
-itself**. This different than for clips defined by `SpecificDisplayItem::Clip`.
-
-## Clip Display Items
-
-Clip display items allow items to share clips in order to increase performance
-(shared clips are only rasterized once) and to allow for scrolling regions.
-Display items can be assigned a clip display item using the `scroll_layer_id`
-field. An item can be assigned any clip that is defined by its parent stacking
-context or any of the ancestors. The behavior of assigning an id outside of
-this hierarchy is undefined, because that situation does not occur in CSS
-
-The clip display item has a `ClipRegion` as well as several other fields:
-
-```rust
-pub struct ClipDisplayItem {
- pub id: ScrollLayerId,
- pub parent_id: ScrollLayerId,
-}
-```
-
-A `ClipDisplayItem` also gets a clip and bounds from the `BaseDisplayItem`. The
-clip is shared among all items that use this `ClipDisplayItem`. Critically,
-**coordinates in this ClipRegion are defined relative to the bounds of the
-ClipDisplayItem itself**. Additionally, WebRender only supports clip rectangles
-that start at the origin of the `BaseDisplayItem` bounds.
-
-The `BaseDisplayItem` bounds are known as the *content rectangle* of the clip. If
-the content rectangle is larger than *main* clipping rectangle, the clip will
-be a scrolling clip and participate in scrolling event capture and
-transformation.
-
-`ClipDisplayItems` are positioned, like all other items, relatively to their
-containing stacking context, yet they also live in a parallel tree defined by
-their `parent_id`. Child clips also include any clipping and scrolling that
-their ancestors do. In this way, a clip is positioned by a stacking context,
-but that position may be adjusted by any scroll offset of its parent clips.
-
-## Clip ids
-
-All clips defined by a `ClipDisplayItem` have an id. It is useful to associate
-an external id with WebRender id in order to allow for tracking and updating
-scroll positions using the WebRender API. In order to make this as cheap as
-possible and to avoid having to create a `HashMap` to map between the two types
-of ids, the WebRender API provides an optional id argument in
-`DisplayListBuilder::define_clip`. The only types of ids that are supported
-here are those created with `ScrollLayerId::new(...)`. If this argument is not
-provided `define_clip` will return a uniquely generated id. Thus, the following
-should always be true:
-
-```rust
-let id = ScrollLayerId::new(my_internal_id, pipeline_id);
-let generated_id = define_clip(content_rect, clip, id);
-assert!(id == generated_id);
-```
-
-## Pending changes
-
-1. Rename `ScrollLayerId` to `ClipId`. The current name is a holdover from the
- previous design. ([github issue](https://github.com/servo/webrender/issues/1089))
-
-2. Normalize the way that clipping coordinates are defined. Having them
- specified in two different ways makes for a confusing API. This should be
- fixed. ([github issue](https://github.com/servo/webrender/issues/1090))
-
-3. It should be possible to specify more than one predefined clip for an item.
- This is necessary for items that live in a scrolling frame, but are also
- clipped by a clip that lives outside that frame.
- ([github issue](https://github.com/servo/webrender/issues/840))
-
deleted file mode 100644
--- a/gfx/webrender/src/batch_builder.rs
+++ /dev/null
@@ -1,43 +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/. */
-
-use std::f32;
-use webrender_traits::{ColorF, BorderStyle};
-use webrender_traits::{BorderSide};
-
-//const BORDER_DASH_SIZE: f32 = 3.0;
-
-pub trait BorderSideHelpers {
- fn border_color(&self,
- scale_factor_0: f32,
- scale_factor_1: f32,
- black_color_0: f32,
- black_color_1: f32) -> ColorF;
-}
-
-impl BorderSideHelpers for BorderSide {
- fn border_color(&self,
- scale_factor_0: f32,
- scale_factor_1: f32,
- black_color_0: f32,
- black_color_1: f32) -> ColorF {
- match self.style {
- BorderStyle::Inset => {
- if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
- self.color.scale_rgb(scale_factor_1)
- } else {
- ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
- }
- }
- BorderStyle::Outset => {
- if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
- self.color.scale_rgb(scale_factor_0)
- } else {
- ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
- }
- }
- _ => self.color,
- }
- }
-}
--- a/gfx/webrender/src/border.rs
+++ b/gfx/webrender/src/border.rs
@@ -1,29 +1,32 @@
/* 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/. */
use frame_builder::FrameBuilder;
+use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, PrimitiveContainer};
use tiling::PrimitiveFlags;
-use webrender_traits::{BorderSide, BorderStyle, BorderWidths, NormalBorder};
-use webrender_traits::{ClipRegion, LayerPoint, LayerRect, LayerSize, ScrollLayerId};
+use util::pack_as_float;
+use webrender_traits::{BorderSide, BorderStyle, BorderWidths, ColorF, NormalBorder};
+use webrender_traits::{ClipId, ClipRegion, LayerPoint, LayerRect, LayerSize};
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderCornerKind {
None,
Solid,
- Complex,
+ Clip,
+ Unhandled,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BorderEdgeKind {
None,
Solid,
- Complex,
+ Unhandled,
}
pub trait NormalBorderHelpers {
fn get_corner(&self,
edge0: &BorderSide,
width0: f32,
edge1: &BorderSide,
width1: f32,
@@ -57,30 +60,35 @@ impl NormalBorderHelpers for NormalBorde
(BorderStyle::Hidden, _) | (_, BorderStyle::Hidden) => BorderCornerKind::None,
// If both borders are solid, we can draw them with a simple rectangle if
// both the colors match and there is no radius.
(BorderStyle::Solid, BorderStyle::Solid) => {
if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 {
BorderCornerKind::Solid
} else {
- BorderCornerKind::Complex
+ BorderCornerKind::Clip
}
}
+ // Inset / outset borders just modtify the color of edges, so can be
+ // drawn with the normal border corner shader.
+ (BorderStyle::Outset, BorderStyle::Outset) |
+ (BorderStyle::Inset, BorderStyle::Inset) => BorderCornerKind::Clip,
+
// Assume complex for these cases.
// TODO(gw): There are some cases in here that can be handled with a fast path.
// For example, with inset/outset borders, two of the four corners are solid.
- (BorderStyle::Dotted, _) | (_, BorderStyle::Dotted) => BorderCornerKind::Complex,
- (BorderStyle::Dashed, _) | (_, BorderStyle::Dashed) => BorderCornerKind::Complex,
- (BorderStyle::Double, _) | (_, BorderStyle::Double) => BorderCornerKind::Complex,
- (BorderStyle::Groove, _) | (_, BorderStyle::Groove) => BorderCornerKind::Complex,
- (BorderStyle::Ridge, _) | (_, BorderStyle::Ridge) => BorderCornerKind::Complex,
- (BorderStyle::Outset, _) | (_, BorderStyle::Outset) => BorderCornerKind::Complex,
- (BorderStyle::Inset, _) | (_, BorderStyle::Inset) => BorderCornerKind::Complex,
+ (BorderStyle::Dotted, _) | (_, BorderStyle::Dotted) => BorderCornerKind::Unhandled,
+ (BorderStyle::Dashed, _) | (_, BorderStyle::Dashed) => BorderCornerKind::Unhandled,
+ (BorderStyle::Double, _) | (_, BorderStyle::Double) => BorderCornerKind::Unhandled,
+ (BorderStyle::Groove, _) | (_, BorderStyle::Groove) => BorderCornerKind::Unhandled,
+ (BorderStyle::Ridge, _) | (_, BorderStyle::Ridge) => BorderCornerKind::Unhandled,
+ (BorderStyle::Outset, _) | (_, BorderStyle::Outset) => BorderCornerKind::Unhandled,
+ (BorderStyle::Inset, _) | (_, BorderStyle::Inset) => BorderCornerKind::Unhandled,
}
}
fn get_edge(&self,
edge: &BorderSide,
width: f32) -> (BorderEdgeKind, f32) {
if width == 0.0 {
return (BorderEdgeKind::None, 0.0);
@@ -93,110 +101,225 @@ impl NormalBorderHelpers for NormalBorde
BorderStyle::Solid |
BorderStyle::Inset |
BorderStyle::Outset => (BorderEdgeKind::Solid, width),
BorderStyle::Double |
BorderStyle::Dotted |
BorderStyle::Dashed |
BorderStyle::Groove |
- BorderStyle::Ridge => (BorderEdgeKind::Complex, width),
+ BorderStyle::Ridge => (BorderEdgeKind::Unhandled, width),
}
}
}
impl FrameBuilder {
+ fn add_normal_border_primitive(&mut self,
+ rect: &LayerRect,
+ border: &NormalBorder,
+ widths: &BorderWidths,
+ clip_id: ClipId,
+ clip_region: &ClipRegion,
+ use_new_border_path: bool) {
+ let radius = &border.radius;
+ let left = &border.left;
+ let right = &border.right;
+ let top = &border.top;
+ let bottom = &border.bottom;
+
+ // These colors are used during inset/outset scaling.
+ let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
+ let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
+ let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
+ let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);
+
+ let prim_cpu = BorderPrimitiveCpu {
+ use_new_border_path: use_new_border_path,
+ };
+
+ let prim_gpu = BorderPrimitiveGpu {
+ colors: [ left_color, top_color, right_color, bottom_color ],
+ widths: [ widths.left,
+ widths.top,
+ widths.right,
+ widths.bottom ],
+ style: [
+ pack_as_float(left.style as u32),
+ pack_as_float(top.style as u32),
+ pack_as_float(right.style as u32),
+ pack_as_float(bottom.style as u32),
+ ],
+ radii: [
+ radius.top_left,
+ radius.top_right,
+ radius.bottom_right,
+ radius.bottom_left,
+ ],
+ };
+
+ self.add_primitive(clip_id,
+ &rect,
+ clip_region,
+ &[],
+ PrimitiveContainer::Border(prim_cpu, prim_gpu));
+ }
+
// TODO(gw): This allows us to move border types over to the
// simplified shader model one at a time. Once all borders
// are converted, this can be removed, along with the complex
// border code path.
- pub fn add_simple_border(&mut self,
+ pub fn add_normal_border(&mut self,
rect: &LayerRect,
border: &NormalBorder,
widths: &BorderWidths,
- scroll_layer_id: ScrollLayerId,
- clip_region: &ClipRegion) -> bool {
+ clip_id: ClipId,
+ clip_region: &ClipRegion) {
// The border shader is quite expensive. For simple borders, we can just draw
// the border with a few rectangles. This generally gives better batching, and
// a GPU win in fragment shader time.
// More importantly, the software (OSMesa) implementation we run tests on is
// particularly slow at running our complex border shader, compared to the
// rectangle shader. This has the effect of making some of our tests time
// out more often on CI (the actual cause is simply too many Servo processes and
// threads being run on CI at once).
let radius = &border.radius;
let left = &border.left;
let right = &border.right;
let top = &border.top;
let bottom = &border.bottom;
- // If any of the corners are complex, fall back to slow path for now.
- let tl = border.get_corner(left, widths.left, top, widths.top, &radius.top_left);
- let tr = border.get_corner(top, widths.top, right, widths.right, &radius.top_right);
- let br = border.get_corner(right, widths.right, bottom, widths.bottom, &radius.bottom_right);
- let bl = border.get_corner(bottom, widths.bottom, left, widths.left, &radius.bottom_left);
+ let corners = [
+ border.get_corner(left, widths.left, top, widths.top, &radius.top_left),
+ border.get_corner(top, widths.top, right, widths.right, &radius.top_right),
+ border.get_corner(right, widths.right, bottom, widths.bottom, &radius.bottom_right),
+ border.get_corner(bottom, widths.bottom, left, widths.left, &radius.bottom_left),
+ ];
- if tl == BorderCornerKind::Complex ||
- tr == BorderCornerKind::Complex ||
- br == BorderCornerKind::Complex ||
- bl == BorderCornerKind::Complex {
- return false;
+ // If any of the corners are unhandled, fall back to slow path for now.
+ if corners.iter().any(|c| *c == BorderCornerKind::Unhandled) {
+ self.add_normal_border_primitive(rect,
+ border,
+ widths,
+ clip_id,
+ clip_region,
+ false);
+ return;
}
- // If any of the edges are complex, fall back to slow path for now.
let (left_edge, left_len) = border.get_edge(left, widths.left);
let (top_edge, top_len) = border.get_edge(top, widths.top);
let (right_edge, right_len) = border.get_edge(right, widths.right);
let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom);
- if left_edge == BorderEdgeKind::Complex ||
- top_edge == BorderEdgeKind::Complex ||
- right_edge == BorderEdgeKind::Complex ||
- bottom_edge == BorderEdgeKind::Complex {
- return false;
+ let edges = [
+ left_edge,
+ top_edge,
+ right_edge,
+ bottom_edge,
+ ];
+
+ // If any of the edges are unhandled, fall back to slow path for now.
+ if edges.iter().any(|e| *e == BorderEdgeKind::Unhandled) {
+ self.add_normal_border_primitive(rect,
+ border,
+ widths,
+ clip_id,
+ clip_region,
+ false);
+ return;
}
- let p0 = rect.origin;
- let p1 = rect.bottom_right();
- let rect_width = rect.size.width;
- let rect_height = rect.size.height;
+ // Use a simple rectangle case when all edges and corners are either
+ // solid or none.
+ let all_corners_simple = corners.iter().all(|c| {
+ *c == BorderCornerKind::Solid || *c == BorderCornerKind::None
+ });
+ let all_edges_simple = edges.iter().all(|e| {
+ *e == BorderEdgeKind::Solid || *e == BorderEdgeKind::None
+ });
+
+ if all_corners_simple && all_edges_simple {
+ let p0 = rect.origin;
+ let p1 = rect.bottom_right();
+ let rect_width = rect.size.width;
+ let rect_height = rect.size.height;
- // Add a solid rectangle for each visible edge/corner combination.
- if top_edge == BorderEdgeKind::Solid {
- self.add_solid_rectangle(scroll_layer_id,
- &LayerRect::new(p0,
- LayerSize::new(rect.size.width, top_len)),
- clip_region,
- &border.top.color,
- PrimitiveFlags::None);
+ // Add a solid rectangle for each visible edge/corner combination.
+ if top_edge == BorderEdgeKind::Solid {
+ self.add_solid_rectangle(clip_id,
+ &LayerRect::new(p0,
+ LayerSize::new(rect_width, top_len)),
+ clip_region,
+ &border.top.color,
+ PrimitiveFlags::None);
+ }
+ if left_edge == BorderEdgeKind::Solid {
+ self.add_solid_rectangle(clip_id,
+ &LayerRect::new(LayerPoint::new(p0.x, p0.y + top_len),
+ LayerSize::new(left_len,
+ rect_height - top_len - bottom_len)),
+ clip_region,
+ &border.left.color,
+ PrimitiveFlags::None);
+ }
+ if right_edge == BorderEdgeKind::Solid {
+ self.add_solid_rectangle(clip_id,
+ &LayerRect::new(LayerPoint::new(p1.x - right_len,
+ p0.y + top_len),
+ LayerSize::new(right_len,
+ rect_height - top_len - bottom_len)),
+ clip_region,
+ &border.right.color,
+ PrimitiveFlags::None);
+ }
+ if bottom_edge == BorderEdgeKind::Solid {
+ self.add_solid_rectangle(clip_id,
+ &LayerRect::new(LayerPoint::new(p0.x, p1.y - bottom_len),
+ LayerSize::new(rect_width, bottom_len)),
+ clip_region,
+ &border.bottom.color,
+ PrimitiveFlags::None);
+ }
+ } else {
+ self.add_normal_border_primitive(rect,
+ border,
+ widths,
+ clip_id,
+ clip_region,
+ true);
}
- if left_edge == BorderEdgeKind::Solid {
- self.add_solid_rectangle(scroll_layer_id,
- &LayerRect::new(LayerPoint::new(p0.x, p0.y + top_len),
- LayerSize::new(left_len,
- rect_height - top_len - bottom_len)),
- clip_region,
- &border.left.color,
- PrimitiveFlags::None);
- }
- if right_edge == BorderEdgeKind::Solid {
- self.add_solid_rectangle(scroll_layer_id,
- &LayerRect::new(LayerPoint::new(p1.x - right_len,
- p0.y + top_len),
- LayerSize::new(right_len,
- rect_height - top_len - bottom_len)),
- clip_region,
- &border.right.color,
- PrimitiveFlags::None);
- }
- if bottom_edge == BorderEdgeKind::Solid {
- self.add_solid_rectangle(scroll_layer_id,
- &LayerRect::new(LayerPoint::new(p0.x, p1.y - bottom_len),
- LayerSize::new(rect_width, bottom_len)),
- clip_region,
- &border.bottom.color,
- PrimitiveFlags::None);
- }
-
- true
}
}
+
+pub trait BorderSideHelpers {
+ fn border_color(&self,
+ scale_factor_0: f32,
+ scale_factor_1: f32,
+ black_color_0: f32,
+ black_color_1: f32) -> ColorF;
+}
+
+impl BorderSideHelpers for BorderSide {
+ fn border_color(&self,
+ scale_factor_0: f32,
+ scale_factor_1: f32,
+ black_color_0: f32,
+ black_color_1: f32) -> ColorF {
+ match self.style {
+ BorderStyle::Inset => {
+ if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+ self.color.scale_rgb(scale_factor_1)
+ } else {
+ ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
+ }
+ }
+ BorderStyle::Outset => {
+ if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+ self.color.scale_rgb(scale_factor_0)
+ } else {
+ ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
+ }
+ }
+ _ => self.color,
+ }
+ }
+}
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -5,20 +5,20 @@
use euclid::Point3D;
use geometry::ray_intersects_rect;
use mask_cache::{ClipSource, MaskCacheInfo, RegionMode};
use prim_store::GpuBlock32;
use renderer::VertexDataStore;
use spring::{DAMPING, STIFFNESS, Spring};
use tiling::PackedLayerIndex;
use util::TransformedRect;
-use webrender_traits::{ClipRegion, LayerPixel, LayerPoint, LayerRect, LayerSize};
+use webrender_traits::{ClipId, ClipRegion, LayerPixel, LayerPoint, LayerRect, LayerSize};
use webrender_traits::{LayerToScrollTransform, LayerToWorldTransform, PipelineId};
-use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerRect, ScrollLocation};
-use webrender_traits::{WorldPoint, WorldPoint4D};
+use webrender_traits::{ScrollEventPhase, ScrollLayerRect, ScrollLocation, WorldPoint};
+use webrender_traits::WorldPoint4D;
#[cfg(target_os = "macos")]
const CAN_OVERSCROLL: bool = true;
#[cfg(not(target_os = "macos"))]
const CAN_OVERSCROLL: bool = false;
#[derive(Clone, Debug)]
@@ -101,28 +101,28 @@ pub struct ClipScrollNode {
/// World transform for content transformed by this node.
pub world_content_transform: LayerToWorldTransform,
/// Pipeline that this layer belongs to
pub pipeline_id: PipelineId,
/// Parent layer. If this is None, we are the root node.
- pub parent: Option<ScrollLayerId>,
+ pub parent: Option<ClipId>,
/// Child layers
- pub children: Vec<ScrollLayerId>,
+ pub children: Vec<ClipId>,
/// Whether or not this node is a reference frame.
pub node_type: NodeType,
}
impl ClipScrollNode {
pub fn new(pipeline_id: PipelineId,
- parent_id: ScrollLayerId,
+ parent_id: ClipId,
content_rect: &LayerRect,
clip_rect: &LayerRect,
clip_info: ClipInfo)
-> ClipScrollNode {
// FIXME(mrobinson): We don't yet handle clipping rectangles that don't start at the origin
// of the node.
let local_viewport_rect = LayerRect::new(content_rect.origin, clip_rect.size);
ClipScrollNode {
@@ -135,17 +135,17 @@ impl ClipScrollNode {
world_content_transform: LayerToWorldTransform::identity(),
parent: Some(parent_id),
children: Vec::new(),
pipeline_id: pipeline_id,
node_type: NodeType::Clip(clip_info),
}
}
- pub fn new_reference_frame(parent_id: Option<ScrollLayerId>,
+ pub fn new_reference_frame(parent_id: Option<ClipId>,
local_viewport_rect: &LayerRect,
content_size: LayerSize,
local_transform: &LayerToScrollTransform,
pipeline_id: PipelineId)
-> ClipScrollNode {
ClipScrollNode {
scrolling: ScrollingState::new(),
content_size: content_size,
@@ -156,17 +156,17 @@ impl ClipScrollNode {
world_content_transform: LayerToWorldTransform::identity(),
parent: parent_id,
children: Vec::new(),
pipeline_id: pipeline_id,
node_type: NodeType::ReferenceFrame(*local_transform),
}
}
- pub fn add_child(&mut self, child: ScrollLayerId) {
+ pub fn add_child(&mut self, child: ClipId) {
self.children.push(child);
}
pub fn finalize(&mut self, scrolling: &ScrollingState) {
self.scrolling = *scrolling;
}
pub fn overscroll_amount(&self) -> LayerSize {
@@ -217,18 +217,18 @@ impl ClipScrollNode {
self.scrolling.bouncing_back = false;
self.scrolling.started_bouncing_back = false;
true
}
pub fn update_transform(&mut self,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_combined_viewport_rect: &ScrollLayerRect,
+ parent_scroll_offset: LayerPoint,
parent_accumulated_scroll_offset: LayerPoint) {
-
let local_transform = match self.node_type {
NodeType::ReferenceFrame(transform) => transform,
NodeType::Clip(_) => LayerToScrollTransform::identity(),
};
let inv_transform = match local_transform.inverse() {
Some(transform) => transform,
None => {
@@ -236,21 +236,21 @@ impl ClipScrollNode {
// to be non-invertible, the object and its content do not get displayed.
self.combined_local_viewport_rect = LayerRect::zero();
return;
}
};
// We are trying to move the combined viewport rectangle of our parent nodes into the
// coordinate system of this node, so we must invert our transformation (only for
- // reference frames) and then apply the scroll offset of all the parent layers.
+ // reference frames) and then apply the scroll offset the parent layer. The combined
+ // local viewport rect doesn't include scrolling offsets so the only one that matters
+ // is the relative offset between us and the parent.
let parent_combined_viewport_in_local_space =
- inv_transform.pre_translated(-parent_accumulated_scroll_offset.x,
- -parent_accumulated_scroll_offset.y,
- 0.0)
+ inv_transform.pre_translated(-parent_scroll_offset.x, -parent_scroll_offset.y, 0.0)
.transform_rect(parent_combined_viewport_rect);
// Now that we have the combined viewport rectangle of the parent nodes in local space,
// we do the intersection and get our combined viewport rect in the coordinate system
// starting from our origin.
self.combined_local_viewport_rect = match self.node_type {
NodeType::Clip(_) => {
parent_combined_viewport_in_local_space.intersection(&self.local_clip_rect)
--- a/gfx/webrender/src/clip_scroll_tree.rs
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -1,114 +1,114 @@
/* 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/. */
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState};
use fnv::FnvHasher;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
-use webrender_traits::{LayerPoint, LayerRect, LayerToScrollTransform, LayerToWorldTransform};
-use webrender_traits::{PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerRect};
+use webrender_traits::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform};
+use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollEventPhase, ScrollLayerRect};
use webrender_traits::{ScrollLayerState, ScrollLocation, WorldPoint, as_scroll_parent_rect};
-pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;
+pub type ScrollStates = HashMap<ClipId, ScrollingState, BuildHasherDefault<FnvHasher>>;
pub struct ClipScrollTree {
- pub nodes: HashMap<ScrollLayerId, ClipScrollNode, BuildHasherDefault<FnvHasher>>,
- pub pending_scroll_offsets: HashMap<ScrollLayerId, LayerPoint>,
+ pub nodes: HashMap<ClipId, ClipScrollNode, BuildHasherDefault<FnvHasher>>,
+ pub pending_scroll_offsets: HashMap<ClipId, LayerPoint>,
- /// The ScrollLayerId of the currently scrolling node. Used to allow the same
+ /// The ClipId of the currently scrolling node. Used to allow the same
/// node to scroll even if a touch operation leaves the boundaries of that node.
- pub current_scroll_layer_id: Option<ScrollLayerId>,
+ pub currently_scrolling_node_id: Option<ClipId>,
/// The current reference frame id, used for giving a unique id to all new
/// reference frames. The ClipScrollTree increments this by one every time a
/// reference frame is created.
current_reference_frame_id: u64,
/// The root reference frame, which is the true root of the ClipScrollTree. Initially
/// this ID is not valid, which is indicated by ```node``` being empty.
- pub root_reference_frame_id: ScrollLayerId,
+ pub root_reference_frame_id: ClipId,
/// The root scroll node which is the first child of the root reference frame.
/// Initially this ID is not valid, which is indicated by ```nodes``` being empty.
- pub topmost_scroll_layer_id: ScrollLayerId,
+ pub topmost_scrolling_node_id: ClipId,
/// A set of pipelines which should be discarded the next time this
/// tree is drained.
pub pipelines_to_discard: HashSet<PipelineId>,
}
impl ClipScrollTree {
pub fn new() -> ClipScrollTree {
let dummy_pipeline = PipelineId(0, 0);
ClipScrollTree {
- nodes: HashMap::with_hasher(Default::default()),
+ nodes: HashMap::default(),
pending_scroll_offsets: HashMap::new(),
- current_scroll_layer_id: None,
- root_reference_frame_id: ScrollLayerId::root_reference_frame(dummy_pipeline),
- topmost_scroll_layer_id: ScrollLayerId::root_scroll_layer(dummy_pipeline),
+ currently_scrolling_node_id: None,
+ root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline),
+ topmost_scrolling_node_id: ClipId::root_scroll_node(dummy_pipeline),
current_reference_frame_id: 0,
pipelines_to_discard: HashSet::new(),
}
}
- pub fn root_reference_frame_id(&self) -> ScrollLayerId {
+ pub fn root_reference_frame_id(&self) -> ClipId {
// TODO(mrobinson): We should eventually make this impossible to misuse.
debug_assert!(!self.nodes.is_empty());
debug_assert!(self.nodes.contains_key(&self.root_reference_frame_id));
self.root_reference_frame_id
}
- pub fn topmost_scroll_layer_id(&self) -> ScrollLayerId {
+ pub fn topmost_scrolling_node_id(&self) -> ClipId {
// TODO(mrobinson): We should eventually make this impossible to misuse.
debug_assert!(!self.nodes.is_empty());
- debug_assert!(self.nodes.contains_key(&self.topmost_scroll_layer_id));
- self.topmost_scroll_layer_id
+ debug_assert!(self.nodes.contains_key(&self.topmost_scrolling_node_id));
+ self.topmost_scrolling_node_id
}
pub fn collect_nodes_bouncing_back(&self)
- -> HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>> {
- let mut nodes_bouncing_back = HashSet::with_hasher(Default::default());
- for (scroll_layer_id, node) in self.nodes.iter() {
+ -> HashSet<ClipId, BuildHasherDefault<FnvHasher>> {
+ let mut nodes_bouncing_back = HashSet::default();
+ for (clip_id, node) in self.nodes.iter() {
if node.scrolling.bouncing_back {
- nodes_bouncing_back.insert(*scroll_layer_id);
+ nodes_bouncing_back.insert(*clip_id);
}
}
nodes_bouncing_back
}
fn find_scrolling_node_at_point_in_node(&self,
cursor: &WorldPoint,
- scroll_layer_id: ScrollLayerId)
- -> Option<ScrollLayerId> {
- self.nodes.get(&scroll_layer_id).and_then(|node| {
+ clip_id: ClipId)
+ -> Option<ClipId> {
+ self.nodes.get(&clip_id).and_then(|node| {
for child_layer_id in node.children.iter().rev() {
if let Some(layer_id) =
self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id) {
return Some(layer_id);
}
}
- if scroll_layer_id.is_reference_frame() {
+ if clip_id.is_reference_frame() {
return None;
}
if node.ray_intersects_node(cursor) {
- Some(scroll_layer_id)
+ Some(clip_id)
} else {
None
}
})
}
- pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
+ pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ClipId {
self.find_scrolling_node_at_point_in_node(cursor, self.root_reference_frame_id())
- .unwrap_or(self.topmost_scroll_layer_id())
+ .unwrap_or(self.topmost_scrolling_node_id())
}
pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
let mut result = vec![];
for (id, node) in self.nodes.iter() {
match node.node_type {
NodeType::Clip(_) => result.push(
ScrollLayerState { id: *id, scroll_offset: node.scrolling.offset }),
@@ -116,28 +116,28 @@ impl ClipScrollTree {
}
}
result
}
pub fn drain(&mut self) -> ScrollStates {
self.current_reference_frame_id = 1;
- let mut scroll_states = HashMap::with_hasher(Default::default());
+ let mut scroll_states = HashMap::default();
for (layer_id, old_node) in &mut self.nodes.drain() {
if !self.pipelines_to_discard.contains(&layer_id.pipeline_id()) {
scroll_states.insert(layer_id, old_node.scrolling);
}
}
self.pipelines_to_discard.clear();
scroll_states
}
- pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ScrollLayerId) -> bool {
+ pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ClipId) -> bool {
if id.is_reference_frame() {
warn!("Tried to scroll a reference frame.");
return false;
}
if self.nodes.is_empty() {
self.pending_scroll_offsets.insert(id, origin);
return false;
@@ -156,194 +156,204 @@ impl ClipScrollTree {
scroll_location: ScrollLocation,
cursor: WorldPoint,
phase: ScrollEventPhase)
-> bool {
if self.nodes.is_empty() {
return false;
}
- let scroll_layer_id = match (
+ let clip_id = match (
phase,
self.find_scrolling_node_at_point(&cursor),
- self.current_scroll_layer_id) {
+ self.currently_scrolling_node_id) {
(ScrollEventPhase::Start, scroll_node_at_point_id, _) => {
- self.current_scroll_layer_id = Some(scroll_node_at_point_id);
+ self.currently_scrolling_node_id = Some(scroll_node_at_point_id);
scroll_node_at_point_id
},
- (_, scroll_node_at_point_id, Some(cached_scroll_layer_id)) => {
- let scroll_layer_id = match self.nodes.get(&cached_scroll_layer_id) {
- Some(_) => cached_scroll_layer_id,
+ (_, scroll_node_at_point_id, Some(cached_clip_id)) => {
+ let clip_id = match self.nodes.get(&cached_clip_id) {
+ Some(_) => cached_clip_id,
None => {
- self.current_scroll_layer_id = Some(scroll_node_at_point_id);
+ self.currently_scrolling_node_id = Some(scroll_node_at_point_id);
scroll_node_at_point_id
},
};
- scroll_layer_id
+ clip_id
},
(_, _, None) => return false,
};
- let topmost_scroll_layer_id = self.topmost_scroll_layer_id();
- let non_root_overscroll = if scroll_layer_id != topmost_scroll_layer_id {
+ let topmost_scrolling_node_id = self.topmost_scrolling_node_id();
+ let non_root_overscroll = if clip_id != topmost_scrolling_node_id {
// true if the current node is overscrolling,
// and it is not the root scroll node.
- let child_node = self.nodes.get(&scroll_layer_id).unwrap();
+ let child_node = self.nodes.get(&clip_id).unwrap();
let overscroll_amount = child_node.overscroll_amount();
overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
} else {
false
};
let switch_node = match phase {
ScrollEventPhase::Start => {
// if this is a new gesture, we do not switch node,
// however we do save the state of non_root_overscroll,
// for use in the subsequent Move phase.
- let mut current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+ let mut current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll = non_root_overscroll;
false
},
ScrollEventPhase::Move(_) => {
// Switch node if movement originated in a new gesture,
// from a non root node in overscroll.
- let current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+ let current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll && non_root_overscroll
},
ScrollEventPhase::End => {
// clean-up when gesture ends.
- let mut current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+ let mut current_node = self.nodes.get_mut(&clip_id).unwrap();
current_node.scrolling.should_handoff_scroll = false;
false
},
};
- let scroll_layer_id = if switch_node {
- topmost_scroll_layer_id
+ let clip_id = if switch_node {
+ topmost_scrolling_node_id
} else {
- scroll_layer_id
+ clip_id
};
- self.nodes.get_mut(&scroll_layer_id).unwrap().scroll(scroll_location, phase)
+ self.nodes.get_mut(&clip_id).unwrap().scroll(scroll_location, phase)
}
pub fn update_all_node_transforms(&mut self, pan: LayerPoint) {
if self.nodes.is_empty() {
return;
}
let root_reference_frame_id = self.root_reference_frame_id();
let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect;
self.update_node_transform(root_reference_frame_id,
&LayerToWorldTransform::create_translation(pan.x, pan.y, 0.0),
&as_scroll_parent_rect(&root_viewport),
+ LayerPoint::zero(),
LayerPoint::zero());
}
fn update_node_transform(&mut self,
- layer_id: ScrollLayerId,
+ layer_id: ClipId,
parent_reference_frame_transform: &LayerToWorldTransform,
parent_viewport_rect: &ScrollLayerRect,
+ parent_scroll_offset: LayerPoint,
parent_accumulated_scroll_offset: LayerPoint) {
// TODO(gw): This is an ugly borrow check workaround to clone these.
// Restructure this to avoid the clones!
- let (reference_frame_transform, viewport_rect, accumulated_scroll_offset, node_children) = {
+ let (reference_frame_transform,
+ viewport_rect,
+ scroll_offset,
+ accumulated_scroll_offset,
+ node_children) = {
match self.nodes.get_mut(&layer_id) {
Some(node) => {
node.update_transform(parent_reference_frame_transform,
parent_viewport_rect,
+ parent_scroll_offset,
parent_accumulated_scroll_offset);
// The transformation we are passing is the transformation of the parent
// reference frame and the offset is the accumulated offset of all the nodes
// between us and the parent reference frame. If we are a reference frame,
// we need to reset both these values.
- let (transform, offset) = match node.node_type {
+ let (transform, offset, accumulated_scroll_offset) = match node.node_type {
NodeType::ReferenceFrame(..) =>
- (node.world_viewport_transform, LayerPoint::zero()),
+ (node.world_viewport_transform, LayerPoint::zero(), LayerPoint::zero()),
NodeType::Clip(_) => {
(*parent_reference_frame_transform,
- parent_accumulated_scroll_offset + node.scrolling.offset)
+ node.scrolling.offset,
+ node.scrolling.offset + parent_accumulated_scroll_offset)
}
};
(transform,
as_scroll_parent_rect(&node.combined_local_viewport_rect),
offset,
+ accumulated_scroll_offset,
node.children.clone())
}
None => return,
}
};
for child_layer_id in node_children {
self.update_node_transform(child_layer_id,
&reference_frame_transform,
&viewport_rect,
+ scroll_offset,
accumulated_scroll_offset);
}
}
pub fn tick_scrolling_bounce_animations(&mut self) {
for (_, node) in &mut self.nodes {
node.tick_scrolling_bounce_animation()
}
}
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
// TODO(gw): These are all independent - can be run through thread pool if it shows up
// in the profile!
- for (scroll_layer_id, node) in &mut self.nodes {
- let scrolling_state = match old_states.get(scroll_layer_id) {
+ for (clip_id, node) in &mut self.nodes {
+ let scrolling_state = match old_states.get(clip_id) {
Some(old_scrolling_state) => *old_scrolling_state,
None => ScrollingState::new(),
};
node.finalize(&scrolling_state);
- if let Some(pending_offset) = self.pending_scroll_offsets.remove(scroll_layer_id) {
+ if let Some(pending_offset) = self.pending_scroll_offsets.remove(clip_id) {
node.set_scroll_origin(&pending_offset);
}
}
}
pub fn add_reference_frame(&mut self,
rect: &LayerRect,
transform: &LayerToScrollTransform,
pipeline_id: PipelineId,
- parent_id: Option<ScrollLayerId>)
- -> ScrollLayerId {
+ parent_id: Option<ClipId>)
+ -> ClipId {
let reference_frame_id =
- ScrollLayerId::ReferenceFrame(self.current_reference_frame_id, pipeline_id);
+ ClipId::ReferenceFrame(self.current_reference_frame_id, pipeline_id);
self.current_reference_frame_id += 1;
let node = ClipScrollNode::new_reference_frame(parent_id,
rect,
rect.size,
transform,
pipeline_id);
self.add_node(node, reference_frame_id);
reference_frame_id
}
- pub fn add_node(&mut self, node: ClipScrollNode, id: ScrollLayerId) {
+ pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) {
// When the parent node is None this means we are adding the root.
match node.parent {
Some(parent_id) => self.nodes.get_mut(&parent_id).unwrap().add_child(id),
None => self.root_reference_frame_id = id,
}
debug_assert!(!self.nodes.contains_key(&id));
self.nodes.insert(id, node);
}
pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
self.pipelines_to_discard.insert(pipeline_id);
- match self.current_scroll_layer_id {
- Some(id) if id.pipeline_id() == pipeline_id => self.current_scroll_layer_id = None,
+ match self.currently_scrolling_node_id {
+ Some(id) if id.pipeline_id() == pipeline_id => self.currently_scrolling_node_id = None,
_ => {}
}
}
}
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -927,19 +927,19 @@ impl Device {
bound_textures: [ TextureId::invalid(); 16 ],
bound_program: ProgramId(0),
bound_vao: VAOId(0),
bound_read_fbo: FBOId(0),
bound_draw_fbo: FBOId(0),
default_read_fbo: 0,
default_draw_fbo: 0,
- textures: HashMap::with_hasher(Default::default()),
- programs: HashMap::with_hasher(Default::default()),
- vaos: HashMap::with_hasher(Default::default()),
+ textures: HashMap::default(),
+ programs: HashMap::default(),
+ vaos: HashMap::default(),
shader_preamble: shader_preamble,
next_vao_id: 1,
//file_watcher: file_watcher,
max_texture_size: max_texture_size,
frame_id: FrameId(0),
@@ -1718,16 +1718,17 @@ impl Device {
}
(get_gl_format_bgra(self.gl()), 4, expanded_data.as_slice())
} else {
(GL_FORMAT_A, 1, data)
}
}
ImageFormat::RGB8 => (gl::RGB, 3, data),
ImageFormat::RGBA8 => (get_gl_format_bgra(self.gl()), 4, data),
+ ImageFormat::RG8 => (gl::RG, 2, data),
ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
};
let row_length = match stride {
Some(value) => value / bpp,
None => width,
};
@@ -2083,16 +2084,17 @@ impl Device {
}
impl Drop for Device {
fn drop(&mut self) {
//self.file_watcher.exit();
}
}
+/// return (gl_internal_format, gl_format)
fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl::GLint, gl::GLuint) {
match format {
ImageFormat::A8 => {
if cfg!(any(target_arch="arm", target_arch="aarch64")) {
(get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl))
} else {
(GL_FORMAT_A as gl::GLint, GL_FORMAT_A)
}
@@ -2104,16 +2106,17 @@ fn gl_texture_formats_for_image_format(g
(gl::RGBA as gl::GLint, get_gl_format_bgra(gl))
}
gl::GlType::Gles => {
(get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl))
}
}
}
ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA),
+ ImageFormat::RG8 => (gl::RG8 as gl::GLint, gl::RG),
ImageFormat::Invalid => unreachable!(),
}
}
fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint {
match format {
ImageFormat::RGBAF32 => gl::FLOAT,
_ => gl::UNSIGNED_BYTE,
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -12,49 +12,49 @@ use frame_builder::{FrameBuilder, FrameB
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use profiler::TextureCacheProfileCounters;
use resource_cache::ResourceCache;
use scene::{Scene, SceneProperties};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
use util::{ComplexClipRegionHelpers, subtract_rect};
-use webrender_traits::{AuxiliaryLists, ClipDisplayItem, ClipRegion, ColorF, DeviceUintRect};
-use webrender_traits::{DeviceUintSize, DisplayItem, Epoch, FilterOp, ImageDisplayItem, LayerPoint};
-use webrender_traits::{LayerRect, LayerSize, LayerToScrollTransform, LayoutRect, LayoutTransform};
-use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId};
+use webrender_traits::{AuxiliaryLists, ClipDisplayItem, ClipId, ClipRegion, ColorF};
+use webrender_traits::{DeviceUintRect, DeviceUintSize, DisplayItem, Epoch, FilterOp};
+use webrender_traits::{ImageDisplayItem, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
+use webrender_traits::{LayoutRect, LayoutTransform, MixBlendMode, PipelineId, ScrollEventPhase};
use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
use webrender_traits::{StackingContext, TileOffset, WorldPoint};
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
pub struct FrameId(pub u32);
static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
struct FlattenContext<'a> {
scene: &'a Scene,
builder: &'a mut FrameBuilder,
resource_cache: &'a mut ResourceCache,
- replacements: Vec<(ScrollLayerId, ScrollLayerId)>,
+ replacements: Vec<(ClipId, ClipId)>,
}
impl<'a> FlattenContext<'a> {
fn new(scene: &'a Scene,
builder: &'a mut FrameBuilder,
resource_cache: &'a mut ResourceCache)
-> FlattenContext<'a> {
FlattenContext {
scene: scene,
builder: builder,
resource_cache: resource_cache,
replacements: Vec::new(),
}
}
- fn scroll_layer_id_with_replacement(&self, id: ScrollLayerId) -> ScrollLayerId {
+ fn clip_id_with_replacement(&self, id: ClipId) -> ClipId {
match self.replacements.last() {
Some(&(to_replace, replacement)) if to_replace == id => replacement,
_ => id,
}
}
}
// TODO: doc
@@ -220,18 +220,18 @@ fn clip_intersection(original_rect: &Lay
ccr.get_inner_rect_full().and_then(|ir| ir.intersection(&combined))
})
})
}
impl Frame {
pub fn new(config: FrameBuilderConfig) -> Frame {
Frame {
- pipeline_epoch_map: HashMap::with_hasher(Default::default()),
- pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
+ pipeline_epoch_map: HashMap::default(),
+ pipeline_auxiliary_lists: HashMap::default(),
clip_scroll_tree: ClipScrollTree::new(),
id: FrameId(0),
frame_builder: None,
frame_builder_config: config,
}
}
pub fn reset(&mut self) -> ScrollStates {
@@ -243,17 +243,17 @@ impl Frame {
self.clip_scroll_tree.drain()
}
pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
self.clip_scroll_tree.get_scroll_node_state()
}
/// Returns true if any nodes actually changed position or false otherwise.
- pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ScrollLayerId) -> bool {
+ pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ClipId) -> bool {
self.clip_scroll_tree.scroll_nodes(origin, id)
}
/// Returns true if any nodes actually changed position or false otherwise.
pub fn scroll(&mut self,
scroll_location: ScrollLocation,
cursor: WorldPoint,
phase: ScrollEventPhase)
@@ -287,18 +287,17 @@ impl Frame {
let display_list = scene.display_lists.get(&root_pipeline_id);
let display_list = match display_list {
Some(display_list) => display_list,
None => return,
};
if window_size.width == 0 || window_size.height == 0 {
- println!("ERROR: Invalid window dimensions! Please call api.set_window_size()");
- return;
+ error!("ERROR: Invalid window dimensions! Please call api.set_window_size()");
}
let old_scrolling_states = self.reset();
self.pipeline_auxiliary_lists = scene.pipeline_auxiliary_lists.clone();
self.pipeline_epoch_map.insert(root_pipeline_id, root_pipeline.epoch);
let (root_stacking_context, root_bounds) = match display_list.starting_stacking_context() {
@@ -319,62 +318,62 @@ impl Frame {
let mut frame_builder = FrameBuilder::new(window_size,
background_color,
self.frame_builder_config);
{
let mut context = FlattenContext::new(scene, &mut frame_builder, resource_cache);
- let scroll_layer_id = context.builder.push_root(root_pipeline_id,
- &root_pipeline.viewport_size,
- &root_bounds.size,
- &mut self.clip_scroll_tree);
+ let clip_id = context.builder.push_root(root_pipeline_id,
+ &root_pipeline.viewport_size,
+ &root_bounds.size,
+ &mut self.clip_scroll_tree);
context.builder.setup_viewport_offset(window_size,
inner_rect,
device_pixel_ratio,
&mut self.clip_scroll_tree);
let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
self.flatten_stacking_context(&mut traversal,
root_pipeline_id,
&mut context,
- scroll_layer_id,
+ clip_id,
LayerPoint::zero(),
0,
root_bounds,
root_stacking_context);
}
self.frame_builder = Some(frame_builder);
self.clip_scroll_tree.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
}
fn flatten_clip<'a>(&mut self,
context: &mut FlattenContext,
pipeline_id: PipelineId,
- parent_id: ScrollLayerId,
+ parent_id: ClipId,
item: &ClipDisplayItem,
content_rect: &LayerRect,
clip: &ClipRegion) {
context.builder.add_clip_scroll_node(item.id,
parent_id,
pipeline_id,
&content_rect,
clip,
&mut self.clip_scroll_tree);
}
fn flatten_stacking_context<'a>(&mut self,
traversal: &mut DisplayListTraversal<'a>,
pipeline_id: PipelineId,
context: &mut FlattenContext,
- context_scroll_layer_id: ScrollLayerId,
+ context_clip_id: ClipId,
mut reference_frame_relative_offset: LayerPoint,
level: i32,
bounds: &LayerRect,
stacking_context: &StackingContext) {
// Avoid doing unnecessary work for empty stacking contexts.
if traversal.current_stacking_context_empty() {
traversal.skip_current_stacking_context();
return;
@@ -389,21 +388,20 @@ impl Frame {
stacking_context.mix_blend_mode_for_compositing())
};
if composition_operations.will_make_invisible() {
traversal.skip_current_stacking_context();
return;
}
- let mut scroll_layer_id =
- context.scroll_layer_id_with_replacement(context_scroll_layer_id);
+ let mut clip_id = context.clip_id_with_replacement(context_clip_id);
if stacking_context.scroll_policy == ScrollPolicy::Fixed {
- context.replacements.push((context_scroll_layer_id,
+ context.replacements.push((context_clip_id,
context.builder.current_reference_frame_id()));
}
// If we have a transformation, we establish a new reference frame. This means
// that fixed position stacking contexts are positioned relative to us.
let is_reference_frame = stacking_context.transform.is_some() ||
stacking_context.perspective.is_some();
if is_reference_frame {
@@ -415,22 +413,22 @@ impl Frame {
LayerToScrollTransform::create_translation(reference_frame_relative_offset.x,
reference_frame_relative_offset.y,
0.0)
.pre_translated(bounds.origin.x, bounds.origin.y, 0.0)
.pre_mul(&transform)
.pre_mul(&perspective);
let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size);
- scroll_layer_id = context.builder.push_reference_frame(Some(scroll_layer_id),
- pipeline_id,
- &reference_frame_bounds,
- &transform,
- &mut self.clip_scroll_tree);
- context.replacements.push((context_scroll_layer_id, scroll_layer_id));
+ clip_id = context.builder.push_reference_frame(Some(clip_id),
+ pipeline_id,
+ &reference_frame_bounds,
+ &transform,
+ &mut self.clip_scroll_tree);
+ context.replacements.push((context_clip_id, clip_id));
reference_frame_relative_offset = LayerPoint::zero();
} else {
reference_frame_relative_offset = LayerPoint::new(
reference_frame_relative_offset.x + bounds.origin.x,
reference_frame_relative_offset.y + bounds.origin.y);
}
// TODO(gw): Int with overflow etc
@@ -443,17 +441,17 @@ impl Frame {
// For the root pipeline, there's no need to add a full screen rectangle
// here, as it's handled by the framebuffer clear.
if level == 0 && context.scene.root_pipeline_id.unwrap() != pipeline_id {
if let Some(pipeline) = context.scene.pipeline_map.get(&pipeline_id) {
if let Some(bg_color) = pipeline.background_color {
// Note: we don't use the original clip region here,
// it's already processed by the node we just pushed.
let background_rect = LayerRect::new(LayerPoint::zero(), bounds.size);
- context.builder.add_solid_rectangle(scroll_layer_id,
+ context.builder.add_solid_rectangle(clip_id,
bounds,
&ClipRegion::simple(&background_rect),
&bg_color,
PrimitiveFlags::None);
}
}
}
@@ -461,38 +459,38 @@ impl Frame {
pipeline_id,
context,
reference_frame_relative_offset,
level);
if level == 0 && self.frame_builder_config.enable_scrollbars {
let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0));
context.builder.add_solid_rectangle(
- scroll_layer_id,
+ clip_id,
&scrollbar_rect,
&ClipRegion::simple(&scrollbar_rect),
&DEFAULT_SCROLLBAR_COLOR,
- PrimitiveFlags::Scrollbar(self.clip_scroll_tree.topmost_scroll_layer_id(), 4.0));
+ PrimitiveFlags::Scrollbar(self.clip_scroll_tree.topmost_scrolling_node_id(), 4.0));
}
if stacking_context.scroll_policy == ScrollPolicy::Fixed {
context.replacements.pop();
}
if is_reference_frame {
context.replacements.pop();
context.builder.pop_reference_frame();
}
context.builder.pop_stacking_context();
}
fn flatten_iframe<'a>(&mut self,
pipeline_id: PipelineId,
- parent_id: ScrollLayerId,
+ parent_id: ClipId,
bounds: &LayerRect,
context: &mut FlattenContext,
reference_frame_relative_offset: LayerPoint) {
let pipeline = match context.scene.pipeline_map.get(&pipeline_id) {
Some(pipeline) => pipeline,
None => return,
};
@@ -521,89 +519,89 @@ impl Frame {
let iframe_reference_frame_id =
context.builder.push_reference_frame(Some(parent_id),
pipeline_id,
&iframe_rect,
&transform,
&mut self.clip_scroll_tree);
- let iframe_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
+ let iframe_clip_id = ClipId::root_scroll_node(pipeline_id);
context.builder.add_clip_scroll_node(
- iframe_scroll_layer_id,
+ iframe_clip_id,
iframe_reference_frame_id,
pipeline_id,
&LayerRect::new(LayerPoint::zero(), iframe_stacking_context_bounds.size),
&ClipRegion::simple(&iframe_rect),
&mut self.clip_scroll_tree);
let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
self.flatten_stacking_context(&mut traversal,
pipeline_id,
context,
- iframe_scroll_layer_id,
+ iframe_clip_id,
LayerPoint::zero(),
0,
iframe_stacking_context_bounds,
iframe_stacking_context);
context.builder.pop_reference_frame();
}
fn flatten_items<'a>(&mut self,
traversal: &mut DisplayListTraversal<'a>,
pipeline_id: PipelineId,
context: &mut FlattenContext,
reference_frame_relative_offset: LayerPoint,
level: i32) {
while let Some(item) = traversal.next() {
- let scroll_layer_id = context.scroll_layer_id_with_replacement(item.scroll_layer_id);
+ let clip_id = context.clip_id_with_replacement(item.clip_id);
match item.item {
SpecificDisplayItem::WebGL(ref info) => {
- context.builder.add_webgl_rectangle(scroll_layer_id,
+ context.builder.add_webgl_rectangle(clip_id,
item.rect,
&item.clip,
info.context_id);
}
SpecificDisplayItem::Image(ref info) => {
let image = context.resource_cache.get_image_properties(info.image_key);
if let Some(tile_size) = image.tiling {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
let image_size = DeviceUintSize::new(image.descriptor.width, image.descriptor.height);
- self.decompose_image(scroll_layer_id,
+ self.decompose_image(clip_id,
context,
&item.rect,
&item.clip,
info,
image_size,
tile_size as u32);
} else {
- context.builder.add_image(scroll_layer_id,
+ context.builder.add_image(clip_id,
item.rect,
&item.clip,
&info.stretch_size,
&info.tile_spacing,
None,
info.image_key,
info.image_rendering,
None);
}
}
SpecificDisplayItem::YuvImage(ref info) => {
- context.builder.add_yuv_image(scroll_layer_id,
+ context.builder.add_yuv_image(clip_id,
item.rect,
&item.clip,
info.y_image_key,
info.u_image_key,
info.v_image_key,
info.color_space);
}
SpecificDisplayItem::Text(ref text_info) => {
- context.builder.add_text(scroll_layer_id,
+ context.builder.add_text(clip_id,
item.rect,
&item.clip,
text_info.font_key,
text_info.size,
text_info.blur_radius,
&text_info.color,
text_info.glyphs,
text_info.glyph_options);
@@ -613,100 +611,100 @@ impl Frame {
.get(&pipeline_id)
.expect("No auxiliary lists?!");
// Try to extract the opaque inner rectangle out of the clipped primitive.
if let Some(opaque_rect) = clip_intersection(&item.rect, &item.clip, auxiliary_lists) {
let mut results = Vec::new();
subtract_rect(&item.rect, &opaque_rect, &mut results);
// The inner rectangle is considered opaque within this layer.
// It may still inherit some masking from the clip stack.
- context.builder.add_solid_rectangle(scroll_layer_id,
+ context.builder.add_solid_rectangle(clip_id,
&opaque_rect,
&ClipRegion::simple(&item.clip.main),
&info.color,
PrimitiveFlags::None);
for transparent_rect in &results {
- context.builder.add_solid_rectangle(scroll_layer_id,
+ context.builder.add_solid_rectangle(clip_id,
transparent_rect,
&item.clip,
&info.color,
PrimitiveFlags::None);
}
} else {
- context.builder.add_solid_rectangle(scroll_layer_id,
+ context.builder.add_solid_rectangle(clip_id,
&item.rect,
&item.clip,
&info.color,
PrimitiveFlags::None);
}
}
SpecificDisplayItem::Gradient(ref info) => {
- context.builder.add_gradient(scroll_layer_id,
+ context.builder.add_gradient(clip_id,
item.rect,
&item.clip,
info.gradient.start_point,
info.gradient.end_point,
info.gradient.stops,
info.gradient.extend_mode,
info.tile_size,
info.tile_spacing);
}
SpecificDisplayItem::RadialGradient(ref info) => {
- context.builder.add_radial_gradient(scroll_layer_id,
+ context.builder.add_radial_gradient(clip_id,
item.rect,
&item.clip,
info.gradient.start_center,
info.gradient.start_radius,
info.gradient.end_center,
info.gradient.end_radius,
info.gradient.ratio_xy,
info.gradient.stops,
info.gradient.extend_mode,
info.tile_size,
info.tile_spacing);
}
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
- context.builder.add_box_shadow(scroll_layer_id,
+ context.builder.add_box_shadow(clip_id,
&box_shadow_info.box_bounds,
&item.clip,
&box_shadow_info.offset,
&box_shadow_info.color,
box_shadow_info.blur_radius,
box_shadow_info.spread_radius,
box_shadow_info.border_radius,
box_shadow_info.clip_mode);
}
SpecificDisplayItem::Border(ref info) => {
- context.builder.add_border(scroll_layer_id,
+ context.builder.add_border(clip_id,
item.rect,
&item.clip,
info);
}
SpecificDisplayItem::PushStackingContext(ref info) => {
self.flatten_stacking_context(traversal,
pipeline_id,
context,
- item.scroll_layer_id,
+ item.clip_id,
reference_frame_relative_offset,
level + 1,
&item.rect,
&info.stacking_context);
}
SpecificDisplayItem::Iframe(ref info) => {
self.flatten_iframe(info.pipeline_id,
- scroll_layer_id,
+ clip_id,
&item.rect,
context,
reference_frame_relative_offset);
}
SpecificDisplayItem::Clip(ref info) => {
let content_rect = &item.rect.translate(&reference_frame_relative_offset);
self.flatten_clip(context,
pipeline_id,
- scroll_layer_id,
+ clip_id,
&info,
&content_rect,
&item.clip);
}
SpecificDisplayItem::PopStackingContext => return,
}
}
}
@@ -718,77 +716,101 @@ impl Frame {
/// In all of the "decompose" methods below, we independently handle horizontal and vertical
/// decomposition. This lets us generate the minimum amount of primitives by, for example,
/// decompositing the repetition horizontally while repeating vertically in the shader (for
/// an image where the width is too bug but the height is not).
///
/// decompose_image and decompose_image_row handle image repetitions while decompose_tiled_image
/// takes care of the decomposition required by the internal tiling of the image.
fn decompose_image(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
context: &mut FlattenContext,
item_rect: &LayerRect,
item_clip: &ClipRegion,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
tile_size: u32) {
let no_vertical_tiling = image_size.height <= tile_size;
let no_vertical_spacing = info.tile_spacing.height == 0.0;
if no_vertical_tiling && no_vertical_spacing {
- self.decompose_image_row(scroll_layer_id, context, item_rect, item_clip, info, image_size, tile_size);
+ self.decompose_image_row(clip_id,
+ context,
+ item_rect,
+ item_clip,
+ info,
+ image_size,
+ tile_size);
return;
}
// Decompose each vertical repetition into rows.
let layout_stride = info.stretch_size.height + info.tile_spacing.height;
let num_repetitions = (item_rect.size.height / layout_stride).ceil() as u32;
for i in 0..num_repetitions {
if let Some(row_rect) = rect(
item_rect.origin.x,
item_rect.origin.y + (i as f32) * layout_stride,
item_rect.size.width,
info.stretch_size.height
).intersection(item_rect) {
- self.decompose_image_row(scroll_layer_id, context, &row_rect, item_clip, info, image_size, tile_size);
+ self.decompose_image_row(clip_id,
+ context,
+ &row_rect,
+ item_clip,
+ info,
+ image_size,
+ tile_size);
}
}
}
fn decompose_image_row(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
context: &mut FlattenContext,
item_rect: &LayerRect,
item_clip: &ClipRegion,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
tile_size: u32) {
let no_horizontal_tiling = image_size.width <= tile_size;
let no_horizontal_spacing = info.tile_spacing.width == 0.0;
if no_horizontal_tiling && no_horizontal_spacing {
- self.decompose_tiled_image(scroll_layer_id, context, item_rect, item_clip, info, image_size, tile_size);
+ self.decompose_tiled_image(clip_id,
+ context,
+ item_rect,
+ item_clip,
+ info,
+ image_size,
+ tile_size);
return;
}
// Decompose each horizontal repetition.
let layout_stride = info.stretch_size.width + info.tile_spacing.width;
let num_repetitions = (item_rect.size.width / layout_stride).ceil() as u32;
for i in 0..num_repetitions {
if let Some(decomposed_rect) = rect(
item_rect.origin.x + (i as f32) * layout_stride,
item_rect.origin.y,
info.stretch_size.width,
item_rect.size.height,
).intersection(item_rect) {
- self.decompose_tiled_image(scroll_layer_id, context, &decomposed_rect, item_clip, info, image_size, tile_size);
+ self.decompose_tiled_image(clip_id,
+ context,
+ &decomposed_rect,
+ item_clip,
+ info,
+ image_size,
+ tile_size);
}
}
}
fn decompose_tiled_image(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
context: &mut FlattenContext,
item_rect: &LayerRect,
item_clip: &ClipRegion,
info: &ImageDisplayItem,
image_size: DeviceUintSize,
tile_size: u32) {
// The image resource is tiled. We have to generate an image primitive
// for each tile.
@@ -857,76 +879,76 @@ impl Frame {
// The size in pixels of the tiles on the right and bottom edges, smaller
// than the regular tile size if the image is not a multiple of the tile size.
// Zero means the image size is a multiple of the tile size.
let leftover = DeviceUintSize::new(image_size.width % tile_size, image_size.height % tile_size);
for ty in 0..num_tiles_y {
for tx in 0..num_tiles_x {
- self.add_tile_primitive(scroll_layer_id,
+ self.add_tile_primitive(clip_id,
context,
item_rect,
item_clip,
info,
TileOffset::new(tx, ty),
stretched_tile_size,
1.0, 1.0,
repeat_x, repeat_y);
}
if leftover.width != 0 {
// Tiles on the right edge that are smaller than the tile size.
- self.add_tile_primitive(scroll_layer_id,
+ self.add_tile_primitive(clip_id,
context,
item_rect,
item_clip,
info,
TileOffset::new(num_tiles_x, ty),
stretched_tile_size,
(leftover.width as f32) / tile_size_f32,
1.0,
repeat_x, repeat_y);
}
}
if leftover.height != 0 {
for tx in 0..num_tiles_x {
// Tiles on the bottom edge that are smaller than the tile size.
- self.add_tile_primitive(scroll_layer_id,
+ self.add_tile_primitive(clip_id,
context,
item_rect,
item_clip,
info,
TileOffset::new(tx, num_tiles_y),
stretched_tile_size,
1.0,
(leftover.height as f32) / tile_size_f32,
repeat_x,
repeat_y);
}
if leftover.width != 0 {
// Finally, the bottom-right tile with a "leftover" size.
- self.add_tile_primitive(scroll_layer_id,
+ self.add_tile_primitive(clip_id,
context,
item_rect,
item_clip,
info,
TileOffset::new(num_tiles_x, num_tiles_y),
stretched_tile_size,
(leftover.width as f32) / tile_size_f32,
(leftover.height as f32) / tile_size_f32,
repeat_x,
repeat_y);
}
}
}
fn add_tile_primitive(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
context: &mut FlattenContext,
item_rect: &LayerRect,
item_clip: &ClipRegion,
info: &ImageDisplayItem,
tile_offset: TileOffset,
stretched_tile_size: LayerSize,
tile_ratio_width: f32,
tile_ratio_height: f32,
@@ -961,17 +983,17 @@ impl Frame {
if repeat_y {
assert_eq!(tile_offset.y, 0);
prim_rect.size.height = item_rect.size.height;
}
// Fix up the primitive's rect if it overflows the original item rect.
if let Some(prim_rect) = prim_rect.intersection(item_rect) {
- context.builder.add_image(scroll_layer_id,
+ context.builder.add_image(clip_id,
prim_rect,
item_clip,
&stretched_size,
&info.tile_spacing,
None,
info.image_key,
info.image_rendering,
Some(tile_offset));
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -1,45 +1,42 @@
/* 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/. */
use app_units::Au;
-use batch_builder::BorderSideHelpers;
use frame::FrameId;
use gpu_store::GpuStoreAddress;
use internal_types::{HardwareCompositeOp, SourceTexture};
use mask_cache::{ClipMode, ClipSource, MaskCacheInfo, RegionMode};
-use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, BoxShadowPrimitiveGpu};
use prim_store::{GradientPrimitiveCpu, GradientPrimitiveGpu, ImagePrimitiveCpu, ImagePrimitiveGpu};
use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu, RadialGradientPrimitiveGpu};
use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextRunPrimitiveGpu};
-use prim_store::{TexelRect, YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
+use prim_store::{BoxShadowPrimitiveGpu, TexelRect, YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
use profiler::{FrameProfileCounters, TextureCacheProfileCounters};
use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
use render_task::RenderTaskLocation;
use resource_cache::ResourceCache;
use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
use clip_scroll_tree::ClipScrollTree;
use std::{cmp, f32, i32, mem, usize};
use euclid::SideOffsets2D;
use tiling::StackingContextIndex;
use tiling::{AuxiliaryListsMap, ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
use tiling::{RenderTargetContext, RenderTaskCollection, ScrollbarPrimitive, StackingContext};
use util::{self, pack_as_float, subtract_rect};
use util::RectHelpers;
-use webrender_traits::{BorderDetails, BorderDisplayItem};
-use webrender_traits::{BoxShadowClipMode, ClipRegion, ColorF, DeviceIntPoint, DeviceIntRect};
-use webrender_traits::{DeviceIntSize, DeviceUintRect, DeviceUintSize, ExtendMode, FontKey};
-use webrender_traits::{FontRenderMode, GlyphOptions, ImageKey, ImageRendering, ItemRange};
-use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
-use webrender_traits::{RepeatMode, ScrollLayerId, TileOffset, WebGLContextId, YuvColorSpace};
-use webrender_traits::{TransformStyle};
+use webrender_traits::{BorderDetails, BorderDisplayItem, BoxShadowClipMode, ClipId, ClipRegion};
+use webrender_traits::{ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect};
+use webrender_traits::{DeviceUintSize, ExtendMode, FontKey, FontRenderMode, GlyphOptions};
+use webrender_traits::{ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect, LayerSize};
+use webrender_traits::{LayerToScrollTransform, PipelineId, RepeatMode, TileOffset, TransformStyle};
+use webrender_traits::{WebGLContextId, YuvColorSpace};
#[derive(Debug, Clone)]
struct ImageBorderSegment {
geom_rect: LayerRect,
sub_rect: TexelRect,
stretch_size: LayerSize,
tile_spacing: LayerSize,
}
@@ -114,17 +111,17 @@ pub struct FrameBuilder {
stacking_context_store: Vec<StackingContext>,
clip_scroll_group_store: Vec<ClipScrollGroup>,
packed_layers: Vec<PackedLayer>,
scrollbar_prims: Vec<ScrollbarPrimitive>,
/// A stack of scroll nodes used during display list processing to properly
/// parent new scroll nodes.
- reference_frame_stack: Vec<ScrollLayerId>,
+ reference_frame_stack: Vec<ClipId>,
/// A stack of stacking contexts used for creating ClipScrollGroups as
/// primitives are added to the frame.
stacking_context_stack: Vec<StackingContextIndex>,
}
impl FrameBuilder {
pub fn new(screen_size: DeviceUintSize,
@@ -140,85 +137,80 @@ impl FrameBuilder {
packed_layers: Vec::new(),
scrollbar_prims: Vec::new(),
config: config,
reference_frame_stack: Vec::new(),
stacking_context_stack: Vec::new(),
}
}
- fn add_primitive(&mut self,
- scroll_layer_id: ScrollLayerId,
- rect: &LayerRect,
- clip_region: &ClipRegion,
- extra_clip: Option<ClipSource>,
- container: PrimitiveContainer)
- -> PrimitiveIndex {
+ pub fn add_primitive(&mut self,
+ clip_id: ClipId,
+ rect: &LayerRect,
+ clip_region: &ClipRegion,
+ extra_clips: &[ClipSource],
+ container: PrimitiveContainer)
+ -> PrimitiveIndex {
let stacking_context_index = *self.stacking_context_stack.last().unwrap();
- if !self.stacking_context_store[stacking_context_index.0]
- .has_clip_scroll_group(scroll_layer_id) {
- let group_index = self.create_clip_scroll_group(stacking_context_index,
- scroll_layer_id);
+ if !self.stacking_context_store[stacking_context_index.0] .has_clip_scroll_group(clip_id) {
+ let group_index = self.create_clip_scroll_group(stacking_context_index, clip_id);
let stacking_context = &mut self.stacking_context_store[stacking_context_index.0];
stacking_context.clip_scroll_groups.push(group_index);
}
let geometry = PrimitiveGeometry {
local_rect: *rect,
local_clip_rect: clip_region.main,
};
let mut clip_sources = Vec::new();
if clip_region.is_complex() {
clip_sources.push(ClipSource::Region(clip_region.clone(), RegionMode::ExcludeRect));
}
- // TODO(gw): Perhaps in the future it's worth passing in an array
- // so that callers can provide an arbitrary number
- // of clips?
- if let Some(extra_clip) = extra_clip {
- clip_sources.push(extra_clip);
- }
+
+ clip_sources.extend(extra_clips.iter().cloned());
+
let clip_info = MaskCacheInfo::new(&clip_sources,
&mut self.prim_store.gpu_data32);
let prim_index = self.prim_store.add_primitive(geometry,
clip_sources,
clip_info,
container);
match self.cmds.last_mut().unwrap() {
&mut PrimitiveRunCmd::PrimitiveRun(_run_prim_index, ref mut count, run_layer_id)
- if run_layer_id == scroll_layer_id => {
+ if run_layer_id == clip_id => {
debug_assert!(_run_prim_index.0 + *count == prim_index.0);
*count += 1;
return prim_index;
}
&mut PrimitiveRunCmd::PrimitiveRun(..) |
&mut PrimitiveRunCmd::PushStackingContext(..) |
&mut PrimitiveRunCmd::PopStackingContext => {}
}
- self.cmds.push(PrimitiveRunCmd::PrimitiveRun(prim_index, 1, scroll_layer_id));
+ self.cmds.push(PrimitiveRunCmd::PrimitiveRun(prim_index, 1, clip_id));
prim_index
}
pub fn create_clip_scroll_group(&mut self,
stacking_context_index: StackingContextIndex,
- scroll_layer_id: ScrollLayerId)
+ clip_id: ClipId)
-> ClipScrollGroupIndex {
let packed_layer_index = PackedLayerIndex(self.packed_layers.len());
self.packed_layers.push(PackedLayer::empty());
self.clip_scroll_group_store.push(ClipScrollGroup {
stacking_context_index: stacking_context_index,
- scroll_layer_id: scroll_layer_id,
+ clip_id: clip_id,
packed_layer_index: packed_layer_index,
xf_rect: None,
});
- ClipScrollGroupIndex(self.clip_scroll_group_store.len() - 1, scroll_layer_id)
+ ClipScrollGroupIndex(self.clip_scroll_group_store.len() - 1, clip_id)
}
pub fn push_stacking_context(&mut self,
reference_frame_offset: &LayerPoint,
pipeline_id: PipelineId,
is_page_root: bool,
composite_ops: CompositeOps,
transform_style: TransformStyle) {
@@ -244,28 +236,28 @@ impl FrameBuilder {
}
pub fn pop_stacking_context(&mut self) {
self.cmds.push(PrimitiveRunCmd::PopStackingContext);
self.stacking_context_stack.pop();
}
pub fn push_reference_frame(&mut self,
- parent_id: Option<ScrollLayerId>,
+ parent_id: Option<ClipId>,
pipeline_id: PipelineId,
rect: &LayerRect,
transform: &LayerToScrollTransform,
clip_scroll_tree: &mut ClipScrollTree)
- -> ScrollLayerId {
+ -> ClipId {
let new_id = clip_scroll_tree.add_reference_frame(rect, transform, pipeline_id, parent_id);
self.reference_frame_stack.push(new_id);
new_id
}
- pub fn current_reference_frame_id(&self) -> ScrollLayerId {
+ pub fn current_reference_frame_id(&self) -> ClipId {
*self.reference_frame_stack.last().unwrap()
}
pub fn setup_viewport_offset(&mut self,
window_size: DeviceUintSize,
inner_rect: DeviceUintRect,
device_pixel_ratio: f32,
clip_scroll_tree: &mut ClipScrollTree) {
@@ -286,46 +278,46 @@ impl FrameBuilder {
if let NodeType::ReferenceFrame(ref mut transform) = root_node.node_type {
*transform = LayerToScrollTransform::create_translation(viewport_offset.x,
viewport_offset.y,
0.0);
}
root_node.local_clip_rect = viewport_clip;
}
- let scroll_layer_id = clip_scroll_tree.topmost_scroll_layer_id();
- if let Some(root_node) = clip_scroll_tree.nodes.get_mut(&scroll_layer_id) {
+ let clip_id = clip_scroll_tree.topmost_scrolling_node_id();
+ if let Some(root_node) = clip_scroll_tree.nodes.get_mut(&clip_id) {
root_node.local_clip_rect = viewport_clip;
}
}
pub fn push_root(&mut self,
pipeline_id: PipelineId,
viewport_size: &LayerSize,
content_size: &LayerSize,
clip_scroll_tree: &mut ClipScrollTree)
- -> ScrollLayerId {
+ -> ClipId {
let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size);
let identity = &LayerToScrollTransform::identity();
self.push_reference_frame(None, pipeline_id, &viewport_rect, identity, clip_scroll_tree);
- let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
- clip_scroll_tree.topmost_scroll_layer_id = topmost_scroll_layer_id;
- self.add_clip_scroll_node(topmost_scroll_layer_id,
+ let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id);
+ clip_scroll_tree.topmost_scrolling_node_id = topmost_scrolling_node_id;
+ self.add_clip_scroll_node(topmost_scrolling_node_id,
clip_scroll_tree.root_reference_frame_id,
pipeline_id,
&LayerRect::new(LayerPoint::zero(), *content_size),
&ClipRegion::simple(&viewport_rect),
clip_scroll_tree);
- topmost_scroll_layer_id
+ topmost_scrolling_node_id
}
pub fn add_clip_scroll_node(&mut self,
- new_node_id: ScrollLayerId,
- parent_id: ScrollLayerId,
+ new_node_id: ClipId,
+ parent_id: ClipId,
pipeline_id: PipelineId,
content_rect: &LayerRect,
clip_region: &ClipRegion,
clip_scroll_tree: &mut ClipScrollTree) {
let clip_info = ClipInfo::new(clip_region,
&mut self.prim_store.gpu_data32,
PackedLayerIndex(self.packed_layers.len()));
let node = ClipScrollNode::new(pipeline_id,
@@ -338,49 +330,49 @@ impl FrameBuilder {
self.packed_layers.push(PackedLayer::empty());
}
pub fn pop_reference_frame(&mut self) {
self.reference_frame_stack.pop();
}
pub fn add_solid_rectangle(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: &LayerRect,
clip_region: &ClipRegion,
color: &ColorF,
flags: PrimitiveFlags) {
if color.a == 0.0 {
return;
}
let prim = RectanglePrimitive {
color: *color,
};
- let prim_index = self.add_primitive(scroll_layer_id,
+ let prim_index = self.add_primitive(clip_id,
rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::Rectangle(prim));
match flags {
PrimitiveFlags::None => {}
- PrimitiveFlags::Scrollbar(scroll_layer_id, border_radius) => {
+ PrimitiveFlags::Scrollbar(clip_id, border_radius) => {
self.scrollbar_prims.push(ScrollbarPrimitive {
prim_index: prim_index,
- scroll_layer_id: scroll_layer_id,
+ clip_id: clip_id,
border_radius: border_radius,
});
}
}
}
pub fn add_border(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
border_item: &BorderDisplayItem) {
let create_segments = |outset: SideOffsets2D<f32>| {
// Calculate the modified rect as specific by border-image-outset
let origin = LayerPoint::new(rect.origin.x - outset.left,
rect.origin.y - outset.top);
let size = LayerSize::new(rect.size.width + outset.left + outset.right,
@@ -506,100 +498,54 @@ impl FrameBuilder {
ImageBorderSegment::new(LayerRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
TexelRect::new(px2, py1, px3, py2),
RepeatMode::Stretch,
border.repeat_vertical),
]);
}
for segment in segments {
- self.add_image(scroll_layer_id,
+ self.add_image(clip_id,
segment.geom_rect,
clip_region,
&segment.stretch_size,
&segment.tile_spacing,
Some(segment.sub_rect),
border.image_key,
ImageRendering::Auto,
None);
}
}
BorderDetails::Normal(ref border) => {
- // Gradually move border types over to a simplified
- // shader and code path that can handle all border
- // cases correctly.
- if self.add_simple_border(&rect,
- border,
- &border_item.widths,
- scroll_layer_id,
- clip_region) {
- return;
- }
-
- let radius = &border.radius;
- let left = &border.left;
- let right = &border.right;
- let top = &border.top;
- let bottom = &border.bottom;
-
- // These colors are used during inset/outset scaling.
- let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
- let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
- let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
- let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);
-
- let prim_cpu = BorderPrimitiveCpu {
- };
-
- let prim_gpu = BorderPrimitiveGpu {
- colors: [ left_color, top_color, right_color, bottom_color ],
- widths: [ border_item.widths.left,
- border_item.widths.top,
- border_item.widths.right,
- border_item.widths.bottom ],
- style: [
- pack_as_float(left.style as u32),
- pack_as_float(top.style as u32),
- pack_as_float(right.style as u32),
- pack_as_float(bottom.style as u32),
- ],
- radii: [
- radius.top_left,
- radius.top_right,
- radius.bottom_right,
- radius.bottom_left,
- ],
- };
-
- self.add_primitive(scroll_layer_id,
- &rect,
- clip_region,
- None,
- PrimitiveContainer::Border(prim_cpu, prim_gpu));
+ self.add_normal_border(&rect,
+ border,
+ &border_item.widths,
+ clip_id,
+ clip_region);
}
BorderDetails::Gradient(ref border) => {
for segment in create_segments(border.outset) {
let segment_rel = segment.origin - rect.origin;
- self.add_gradient(scroll_layer_id,
+ self.add_gradient(clip_id,
segment,
clip_region,
border.gradient.start_point - segment_rel,
border.gradient.end_point - segment_rel,
border.gradient.stops,
border.gradient.extend_mode,
segment.size,
LayerSize::zero());
}
}
BorderDetails::RadialGradient(ref border) => {
for segment in create_segments(border.outset) {
let segment_rel = segment.origin - rect.origin;
- self.add_radial_gradient(scroll_layer_id,
+ self.add_radial_gradient(clip_id,
segment,
clip_region,
border.gradient.start_center - segment_rel,
border.gradient.start_radius,
border.gradient.end_center - segment_rel,
border.gradient.end_radius,
border.gradient.ratio_xy,
border.gradient.stops,
@@ -607,17 +553,17 @@ impl FrameBuilder {
segment.size,
LayerSize::zero());
}
}
}
}
pub fn add_gradient(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
start_point: LayerPoint,
end_point: LayerPoint,
stops: ItemRange,
extend_mode: ExtendMode,
tile_size: LayerSize,
tile_spacing: LayerSize) {
@@ -672,25 +618,25 @@ impl FrameBuilder {
};
let prim = if aligned {
PrimitiveContainer::AlignedGradient(gradient_cpu, gradient_gpu)
} else {
PrimitiveContainer::AngleGradient(gradient_cpu, gradient_gpu)
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
prim);
}
pub fn add_radial_gradient(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
start_center: LayerPoint,
start_radius: f32,
end_center: LayerPoint,
end_radius: f32,
ratio_xy: f32,
stops: ItemRange,
@@ -710,25 +656,25 @@ impl FrameBuilder {
end_radius: end_radius,
ratio_xy: ratio_xy,
extend_mode: pack_as_float(extend_mode as u32),
tile_size: tile_size,
tile_repeat: tile_size + tile_spacing,
padding: [0.0, 0.0, 0.0, 0.0],
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::RadialGradient(radial_gradient_cpu, radial_gradient_gpu));
}
pub fn add_text(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
font_key: FontKey,
size: Au,
blur_radius: Au,
color: &ColorF,
glyph_range: ItemRange,
glyph_options: Option<GlyphOptions>) {
@@ -763,57 +709,114 @@ impl FrameBuilder {
glyph_options: glyph_options,
resource_address: GpuStoreAddress(0),
};
let prim_gpu = TextRunPrimitiveGpu {
color: *color,
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::TextRun(prim_cpu, prim_gpu));
}
+ pub fn add_box_shadow_no_blur(&mut self,
+ clip_id: ClipId,
+ box_bounds: &LayerRect,
+ clip_region: &ClipRegion,
+ box_offset: &LayerPoint,
+ color: &ColorF,
+ spread_radius: f32,
+ border_radius: f32,
+ clip_mode: BoxShadowClipMode) {
+ assert!(spread_radius == 0.0); // TODO: fix cases where this isn't true.
+ let bs_rect = box_bounds.translate(box_offset);
+
+ // We can draw a rectangle instead with the proper border radius clipping.
+ let (bs_clip_mode, rect_to_draw) = match clip_mode {
+ BoxShadowClipMode::Outset |
+ BoxShadowClipMode::None => (ClipMode::Clip, bs_rect),
+ BoxShadowClipMode::Inset => (ClipMode::ClipOut, *box_bounds),
+ };
+
+ let box_clip_mode = !bs_clip_mode;
+
+ // Clip the inside
+ let extra_clips = [ClipSource::Complex(bs_rect,
+ border_radius,
+ bs_clip_mode),
+ // Clip the outside of the box
+ ClipSource::Complex(*box_bounds,
+ border_radius,
+ box_clip_mode)];
+
+ let prim = RectanglePrimitive {
+ color: *color,
+ };
+
+ self.add_primitive(clip_id,
+ &rect_to_draw,
+ clip_region,
+ &extra_clips,
+ PrimitiveContainer::Rectangle(prim));
+ }
+
pub fn add_box_shadow(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
box_bounds: &LayerRect,
clip_region: &ClipRegion,
box_offset: &LayerPoint,
color: &ColorF,
blur_radius: f32,
spread_radius: f32,
border_radius: f32,
clip_mode: BoxShadowClipMode) {
if color.a == 0.0 {
return
}
- // Fast path.
- if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None {
- self.add_solid_rectangle(scroll_layer_id,
- box_bounds,
- clip_region,
- color,
- PrimitiveFlags::None);
- return;
- }
-
// The local space box shadow rect. It is the element rect
// translated by the box shadow offset and inflated by the
// box shadow spread.
let inflate_amount = match clip_mode {
BoxShadowClipMode::Outset | BoxShadowClipMode::None => spread_radius,
BoxShadowClipMode::Inset => -spread_radius,
};
let bs_rect = box_bounds.translate(box_offset)
.inflate(inflate_amount, inflate_amount);
+ // If we have negative inflate amounts.
+ // Have to explicitly check this since euclid::TypedRect relies on negative rects
+ let bs_rect_empty = bs_rect.size.width <= 0.0 || bs_rect.size.height <= 0.0;
+
+ // Just draw a rectangle
+ if (blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None)
+ || bs_rect_empty {
+ self.add_solid_rectangle(clip_id,
+ box_bounds,
+ clip_region,
+ color,
+ PrimitiveFlags::None);
+ return;
+ }
+
+ if blur_radius == 0.0 && spread_radius == 0.0 && border_radius != 0.0 {
+ self.add_box_shadow_no_blur(clip_id,
+ box_bounds,
+ clip_region,
+ box_offset,
+ color,
+ spread_radius,
+ border_radius,
+ clip_mode);
+ return;
+ }
// Get the outer rectangle, based on the blur radius.
let outside_edge_size = 2.0 * blur_radius;
let inside_edge_size = outside_edge_size.max(border_radius);
let edge_size = outside_edge_size + inside_edge_size;
let outer_rect = bs_rect.inflate(outside_edge_size, outside_edge_size);
// Box shadows are often used for things like text underline and other
@@ -869,17 +872,17 @@ impl FrameBuilder {
BoxShadowKind::Shadow(rects)
}
}
};
match shadow_kind {
BoxShadowKind::Simple(rects) => {
for rect in &rects {
- self.add_solid_rectangle(scroll_layer_id,
+ self.add_solid_rectangle(clip_id,
rect,
clip_region,
color,
PrimitiveFlags::None)
}
}
BoxShadowKind::Shadow(rects) => {
let inverted = match clip_mode {
@@ -889,69 +892,68 @@ impl FrameBuilder {
// Outset box shadows with border radius
// need a clip out of the center box.
let extra_clip_mode = match clip_mode {
BoxShadowClipMode::Outset | BoxShadowClipMode::None => ClipMode::ClipOut,
BoxShadowClipMode::Inset => ClipMode::Clip,
};
- let extra_clip = if border_radius > 0.0 {
- Some(ClipSource::Complex(*box_bounds,
- border_radius,
- extra_clip_mode))
- } else {
- None
- };
+ let mut extra_clips = Vec::new();
+ if border_radius >= 0.0 {
+ extra_clips.push(ClipSource::Complex(*box_bounds,
+ border_radius,
+ extra_clip_mode));
+ }
let prim_gpu = BoxShadowPrimitiveGpu {
src_rect: *box_bounds,
bs_rect: bs_rect,
color: *color,
blur_radius: blur_radius,
border_radius: border_radius,
edge_size: edge_size,
inverted: inverted,
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&outer_rect,
clip_region,
- extra_clip,
+ extra_clips.as_slice(),
PrimitiveContainer::BoxShadow(prim_gpu, rects));
}
}
}
pub fn add_webgl_rectangle(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
context_id: WebGLContextId) {
let prim_cpu = ImagePrimitiveCpu {
kind: ImagePrimitiveKind::WebGL(context_id),
color_texture_id: SourceTexture::Invalid,
resource_address: GpuStoreAddress(0),
sub_rect: None,
};
let prim_gpu = ImagePrimitiveGpu {
stretch_size: rect.size,
tile_spacing: LayerSize::zero(),
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::Image(prim_cpu, prim_gpu));
}
pub fn add_image(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
stretch_size: &LayerSize,
tile_spacing: &LayerSize,
sub_rect: Option<TexelRect>,
image_key: ImageKey,
image_rendering: ImageRendering,
tile: Option<TileOffset>) {
@@ -965,44 +967,44 @@ impl FrameBuilder {
sub_rect: sub_rect,
};
let prim_gpu = ImagePrimitiveGpu {
stretch_size: *stretch_size,
tile_spacing: *tile_spacing,
};
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::Image(prim_cpu, prim_gpu));
}
pub fn add_yuv_image(&mut self,
- scroll_layer_id: ScrollLayerId,
+ clip_id: ClipId,
rect: LayerRect,
clip_region: &ClipRegion,
y_image_key: ImageKey,
u_image_key: ImageKey,
v_image_key: ImageKey,
color_space: YuvColorSpace) {
let prim_cpu = YuvImagePrimitiveCpu {
yuv_key: [y_image_key, u_image_key, v_image_key],
yuv_texture_id: [SourceTexture::Invalid, SourceTexture::Invalid, SourceTexture::Invalid],
yuv_resource_address: GpuStoreAddress(0),
};
let prim_gpu = YuvImagePrimitiveGpu::new(rect.size, color_space);
- self.add_primitive(scroll_layer_id,
+ self.add_primitive(clip_id,
&rect,
clip_region,
- None,
+ &[],
PrimitiveContainer::YuvImage(prim_cpu, prim_gpu));
}
/// Compute the contribution (bounding rectangles, and resources) of layers and their
/// primitives in screen space.
fn build_layer_screen_rects_and_cull_layers(&mut self,
screen_rect: &DeviceIntRect,
clip_scroll_tree: &mut ClipScrollTree,
@@ -1020,17 +1022,17 @@ impl FrameBuilder {
device_pixel_ratio);
}
fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree) {
let distance_from_edge = 8.0;
for scrollbar_prim in &self.scrollbar_prims {
let mut geom = (*self.prim_store.gpu_geometry.get(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32))).clone();
- let clip_scroll_node = &clip_scroll_tree.nodes[&scrollbar_prim.scroll_layer_id];
+ let clip_scroll_node = &clip_scroll_tree.nodes[&scrollbar_prim.clip_id];
let scrollable_distance = clip_scroll_node.scrollable_height();
if scrollable_distance <= 0.0 {
geom.local_clip_rect.size = LayerSize::zero();
*self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom;
continue;
}
@@ -1160,27 +1162,27 @@ impl FrameBuilder {
next_z);
next_z += 1;
prev_task.as_alpha_batch().items.push(item);
prev_task.children.push(current_task);
prev_task.children.push(readback_task);
current_task = prev_task;
}
}
- PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count, scroll_layer_id) => {
+ PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count, clip_id) => {
let stacking_context_index = *sc_stack.last().unwrap();
let stacking_context = &self.stacking_context_store[stacking_context_index.0];
if !stacking_context.is_visible {
continue;
}
let stacking_context_index = *sc_stack.last().unwrap();
let group_index = self.stacking_context_store[stacking_context_index.0]
- .clip_scroll_group(scroll_layer_id);
+ .clip_scroll_group(clip_id);
if self.clip_scroll_group_store[group_index.0].xf_rect.is_none() {
continue
}
for i in 0..prim_count {
let prim_index = PrimitiveIndex(first_prim_index.0 + i);
if self.prim_store.cpu_bounding_rects[prim_index.0].is_some() {
@@ -1325,17 +1327,17 @@ struct LayerRectCalculationAndCullingPas
/// A cached clip info stack, which should handle the most common situation,
/// which is that we are using the same clip info stack that we were using
/// previously.
current_clip_stack: Vec<(PackedLayerIndex, MaskCacheInfo)>,
/// Information about the cached clip stack, which is used to avoid having
/// to recalculate it for every primitive.
- current_clip_info: Option<(ScrollLayerId, Option<DeviceIntRect>)>
+ current_clip_info: Option<(ClipId, Option<DeviceIntRect>)>
}
impl<'a> LayerRectCalculationAndCullingPass<'a> {
fn create_and_run(frame_builder: &'a mut FrameBuilder,
screen_rect: &'a DeviceIntRect,
clip_scroll_tree: &'a mut ClipScrollTree,
auxiliary_lists_map: &'a AuxiliaryListsMap,
resource_cache: &'a mut ResourceCache,
@@ -1362,18 +1364,18 @@ impl<'a> LayerRectCalculationAndCullingP
self.recalculate_clip_scroll_nodes();
self.compute_stacking_context_visibility();
let commands = mem::replace(&mut self.frame_builder.cmds, Vec::new());
for cmd in &commands {
match *cmd {
PrimitiveRunCmd::PushStackingContext(stacking_context_index) =>
self.handle_push_stacking_context(stacking_context_index),
- PrimitiveRunCmd::PrimitiveRun(prim_index, prim_count, scroll_layer_id) =>
- self.handle_primitive_run(prim_index, prim_count, scroll_layer_id),
+ PrimitiveRunCmd::PrimitiveRun(prim_index, prim_count, clip_id) =>
+ self.handle_primitive_run(prim_index, prim_count, clip_id),
PrimitiveRunCmd::PopStackingContext => self.handle_pop_stacking_context(),
}
}
mem::replace(&mut self.frame_builder.cmds, commands);
}
fn recalculate_clip_scroll_nodes(&mut self) {
@@ -1429,17 +1431,17 @@ impl<'a> LayerRectCalculationAndCullingP
}
fn recalculate_clip_scroll_groups(&mut self) {
for ref mut group in &mut self.frame_builder.clip_scroll_group_store {
let stacking_context_index = group.stacking_context_index;
let stacking_context = &mut self.frame_builder
.stacking_context_store[stacking_context_index.0];
- let node = &self.clip_scroll_tree.nodes[&group.scroll_layer_id];
+ let node = &self.clip_scroll_tree.nodes[&group.clip_id];
let packed_layer = &mut self.frame_builder.packed_layers[group.packed_layer_index.0];
// The world content transform is relative to the containing reference frame,
// so we translate into the origin of the stacking context itself.
let transform = node.world_content_transform
.pre_translated(stacking_context.reference_frame_offset.x,
stacking_context.reference_frame_offset.y,
0.0);
@@ -1505,17 +1507,17 @@ impl<'a> LayerRectCalculationAndCullingP
// calculate the device bounding rect. In the future, we could cache this during
// the initial adding of items for the common case (where there is only a single
// scroll layer for items in a stacking context).
let stacking_context = &mut self.frame_builder
.stacking_context_store[stacking_context_index.0];
stacking_context.bounding_rect = DeviceIntRect::zero();
}
- fn rebuild_clip_info_stack_if_necessary(&mut self, id: ScrollLayerId) -> Option<DeviceIntRect> {
+ fn rebuild_clip_info_stack_if_necessary(&mut self, id: ClipId) -> Option<DeviceIntRect> {
if let Some((current_scroll_id, bounding_rect)) = self.current_clip_info {
if current_scroll_id == id {
return bounding_rect;
}
}
// TODO(mrobinson): If we notice that this process is expensive, we can special-case
// more common situations, such as moving from a child or a parent.
@@ -1544,32 +1546,32 @@ impl<'a> LayerRectCalculationAndCullingP
self.current_clip_info = Some((id, bounding_rect));
bounding_rect
}
fn handle_primitive_run(&mut self,
prim_index: PrimitiveIndex,
prim_count: usize,
- scroll_layer_id: ScrollLayerId) {
+ clip_id: ClipId) {
let stacking_context_index = *self.stacking_context_stack.last().unwrap();
let (packed_layer_index, pipeline_id) = {
let stacking_context =
&self.frame_builder.stacking_context_store[stacking_context_index.0];
if !stacking_context.is_visible {
return;
}
- let group_index = stacking_context.clip_scroll_group(scroll_layer_id);
+ let group_index = stacking_context.clip_scroll_group(clip_id);
let clip_scroll_group = &self.frame_builder.clip_scroll_group_store[group_index.0];
(clip_scroll_group.packed_layer_index, stacking_context.pipeline_id)
};
- let node_clip_bounds = self.rebuild_clip_info_stack_if_necessary(scroll_layer_id);
+ let node_clip_bounds = self.rebuild_clip_info_stack_if_necessary(clip_id);
if node_clip_bounds.map_or(false, |bounds| bounds.is_empty()) {
return;
}
let stacking_context =
&mut self.frame_builder.stacking_context_store[stacking_context_index.0];
let packed_layer = &self.frame_builder.packed_layers[packed_layer_index.0];
let auxiliary_lists = self.auxiliary_lists_map.get(&pipeline_id)
@@ -1617,17 +1619,17 @@ impl<'a> LayerRectCalculationAndCullingP
if !self.current_clip_stack.is_empty() {
// If the primitive doesn't have a specific clip, key the task ID off the
// stacking context. This means that two primitives which are only clipped
// by the stacking context stack can share clip masks during render task
// assignment to targets.
let node_clip_bounds = node_clip_bounds.unwrap_or_else(DeviceIntRect::zero);
let (mask_key, mask_rect) = match prim_clip_info {
Some(..) => (MaskCacheKey::Primitive(prim_index), prim_bounding_rect),
- None => (MaskCacheKey::ScrollLayer(scroll_layer_id), node_clip_bounds)
+ None => (MaskCacheKey::ClipNode(clip_id), node_clip_bounds)
};
let mask_opt =
RenderTask::new_mask(mask_rect, mask_key, &self.current_clip_stack);
match mask_opt {
MaskResult::Outside => { // Primitive is completely clipped out.
prim_metadata.clip_task = None;
self.frame_builder.prim_store.cpu_bounding_rects[prim_index.0] = None;
visible = false;
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -10,21 +10,18 @@ use profiler::BackendProfileCounters;
use std::collections::{HashMap, HashSet};
use std::f32;
use std::hash::BuildHasherDefault;
use std::{i32, usize};
use std::path::PathBuf;
use std::sync::Arc;
use tiling;
use renderer::BlendMode;
-use webrender_traits::{Epoch, ColorF, PipelineId};
-use webrender_traits::{ImageFormat, NativeFontHandle};
-use webrender_traits::{ExternalImageData, ExternalImageId, ScrollLayerId};
-use webrender_traits::{ImageData};
-use webrender_traits::{DeviceUintRect};
+use webrender_traits::{ClipId, ColorF, DeviceUintRect, Epoch, ExternalImageData, ExternalImageId};
+use webrender_traits::{ImageData, ImageFormat, NativeFontHandle, PipelineId};
// An ID for a texture that is owned by the
// texture cache module. This can include atlases
// or standalone textures allocated via the
// texture cache (e.g. if an image is too large
// to be added to an atlas). The texture cache
// manages the allocation and freeing of these
// IDs, and the rendering thread maintains a
@@ -325,24 +322,24 @@ impl TextureUpdateList {
/// Mostly wraps a tiling::Frame, adding a bit of extra information.
pub struct RendererFrame {
/// The last rendered epoch for each pipeline present in the frame.
/// This information is used to know if a certain transformation on the layout has
/// been rendered, which is necessary for reftests.
pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
/// The layers that are currently affected by the over-scrolling animation.
- pub layers_bouncing_back: HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>>,
+ pub layers_bouncing_back: HashSet<ClipId, BuildHasherDefault<FnvHasher>>,
pub frame: Option<tiling::Frame>,
}
impl RendererFrame {
pub fn new(pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
- layers_bouncing_back: HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>>,
+ layers_bouncing_back: HashSet<ClipId, BuildHasherDefault<FnvHasher>>,
frame: Option<tiling::Frame>)
-> RendererFrame {
RendererFrame {
pipeline_epoch_map: pipeline_epoch_map,
layers_bouncing_back: layers_bouncing_back,
frame: frame,
}
}
--- a/gfx/webrender/src/lib.rs
+++ b/gfx/webrender/src/lib.rs
@@ -40,17 +40,16 @@
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate thread_profiler;
-mod batch_builder;
mod border;
mod clip_scroll_node;
mod clip_scroll_tree;
mod debug_colors;
mod debug_font_data;
mod debug_render;
mod device;
mod frame;
--- a/gfx/webrender/src/mask_cache.rs
+++ b/gfx/webrender/src/mask_cache.rs
@@ -5,26 +5,38 @@
use gpu_store::GpuStoreAddress;
use prim_store::{ClipData, GpuBlock32, PrimitiveStore};
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
use renderer::VertexDataStore;
use util::{ComplexClipRegionHelpers, MatrixHelpers, TransformedRect};
use webrender_traits::{AuxiliaryLists, BorderRadius, ClipRegion, ComplexClipRegion, ImageMask};
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
use webrender_traits::{LayerRect, LayerPoint, LayerSize};
+use std::ops::Not;
const MAX_CLIP: f32 = 1000000.0;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ClipMode {
Clip, // Pixels inside the region are visible.
ClipOut, // Pixels outside the region are visible.
}
+impl Not for ClipMode {
+ type Output = ClipMode;
+
+ fn not(self) -> ClipMode {
+ match self {
+ ClipMode::Clip => ClipMode::ClipOut,
+ ClipMode::ClipOut => ClipMode::Clip
+ }
+ }
+}
+
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum RegionMode {
IncludeRect,
ExcludeRect,
}
#[derive(Clone, Debug)]
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -186,16 +186,19 @@ impl YuvImagePrimitiveGpu {
color_space: color_space as u32 as f32,
padding: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct BorderPrimitiveCpu {
+ // TODO(gw): Remove this when all border kinds are switched
+ // over to the new border path!
+ pub use_new_border_path: bool,
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct BorderPrimitiveGpu {
pub style: [f32; 4],
pub widths: [f32; 4],
pub colors: [ColorF; 4],
--- a/gfx/webrender/src/profiler.rs
+++ b/gfx/webrender/src/profiler.rs
@@ -266,24 +266,26 @@ impl FrameProfileCounters {
}
}
#[derive(Clone)]
pub struct TextureCacheProfileCounters {
pub pages_a8: ResourceProfileCounter,
pub pages_rgb8: ResourceProfileCounter,
pub pages_rgba8: ResourceProfileCounter,
+ pub pages_rg8: ResourceProfileCounter,
}
impl TextureCacheProfileCounters {
pub fn new() -> TextureCacheProfileCounters {
TextureCacheProfileCounters {
pages_a8: ResourceProfileCounter::new("Texture A8 cached pages"),
pages_rgb8: ResourceProfileCounter::new("Texture RGB8 cached pages"),
pages_rgba8: ResourceProfileCounter::new("Texture RGBA8 cached pages"),
+ pages_rg8: ResourceProfileCounter::new("Texture RG8 cached pages"),
}
}
}
#[derive(Clone)]
pub struct BackendProfileCounters {
pub font_templates: ResourceProfileCounter,
pub image_templates: ResourceProfileCounter,
@@ -649,16 +651,23 @@ impl Profiler {
debug_renderer: &mut DebugRenderer) {
let _gm = GpuMarker::new(device.rc_gl(), "profile");
self.x_left = 20.0;
self.y_left = 40.0;
self.x_right = 400.0;
self.y_right = 40.0;
+ let mut gpu_time = 0;
+ let gpu_samples = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
+ for sample in &gpu_samples {
+ gpu_time += sample.time_ns;
+ }
+ renderer_timers.gpu_time.set(gpu_time);
+
self.draw_counters(&[
&renderer_profile.frame_counter,
&renderer_profile.frame_time,
], debug_renderer, true);
self.draw_counters(&[
&frame_profile.total_primitives,
&frame_profile.visible_primitives,
@@ -671,34 +680,30 @@ impl Profiler {
&backend_profile.font_templates,
&backend_profile.image_templates,
], debug_renderer, true);
self.draw_counters(&[
&backend_profile.texture_cache.pages_a8,
&backend_profile.texture_cache.pages_rgb8,
&backend_profile.texture_cache.pages_rgba8,
+ &backend_profile.texture_cache.pages_rg8,
], debug_renderer, true);
self.draw_counters(&[
&renderer_profile.draw_calls,
&renderer_profile.vertices,
], debug_renderer, true);
self.draw_counters(&[
&backend_profile.total_time,
&renderer_timers.cpu_time,
&renderer_timers.gpu_time,
], debug_renderer, false);
- let mut gpu_time = 0;
- let gpu_samples = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
- for sample in &gpu_samples {
- gpu_time += sample.time_ns;
- }
self.backend_time.push(backend_profile.total_time.nanoseconds);
self.compositor_time.push(renderer_timers.cpu_time.nanoseconds);
self.gpu_time.push(gpu_time);
self.gpu_frames.push(gpu_time, gpu_samples);
let rect = self.backend_time.draw_graph(self.x_left, self.y_left, "CPU (backend)", debug_renderer);
self.y_left += rect.size.height + PROFILE_PADDING;
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -250,18 +250,18 @@ impl RenderBackend {
match frame {
Some(frame) => {
self.publish_frame(frame, &mut profile_counters);
self.notify_compositor_of_new_scroll_frame(true)
}
None => self.notify_compositor_of_new_scroll_frame(false),
}
}
- ApiMsg::ScrollLayerWithId(origin, id) => {
- profile_scope!("ScrollLayerWithScrollId");
+ ApiMsg::ScrollNodeWithId(origin, id) => {
+ profile_scope!("ScrollNodeWithScrollId");
let frame = {
let counters = &mut profile_counters.texture_cache;
profile_counters.total_time.profile(|| {
if self.frame.scroll_nodes(origin, id) {
Some(self.render(counters))
} else {
None
}
@@ -287,20 +287,19 @@ impl RenderBackend {
})
};
self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
}
ApiMsg::TranslatePointToLayerSpace(..) => {
panic!("unused api - remove from webrender_traits");
}
- ApiMsg::GetScrollLayerState(tx) => {
- profile_scope!("GetScrollLayerState");
- tx.send(self.frame.get_scroll_node_state())
- .unwrap()
+ ApiMsg::GetScrollNodeState(tx) => {
+ profile_scope!("GetScrollNodeState");
+ tx.send(self.frame.get_scroll_node_state()).unwrap()
}
ApiMsg::RequestWebGLContext(size, attributes, tx) => {
if let Some(ref wrapper) = self.webrender_context_handle {
let dispatcher: Option<Box<GLContextDispatcher>> = if cfg!(target_os = "windows") {
Some(Box::new(WebRenderGLDispatcher {
dispatcher: Arc::clone(&self.main_thread_dispatcher)
}))
} else {
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -3,18 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use internal_types::{HardwareCompositeOp, LowLevelFilterOp};
use mask_cache::{MaskBounds, MaskCacheInfo};
use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
use std::{cmp, f32, i32, mem, usize};
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind, StackingContextIndex};
-use webrender_traits::{DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
-use webrender_traits::{MixBlendMode, ScrollLayerId};
+use webrender_traits::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
+use webrender_traits::MixBlendMode;
const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct RenderTaskIndex(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum RenderTaskKey {
@@ -28,17 +28,17 @@ pub enum RenderTaskKey {
HorizontalBlur(i32, PrimitiveIndex),
/// Allocate a block of space in target for framebuffer copy.
CopyFramebuffer(StackingContextIndex),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum MaskCacheKey {
Primitive(PrimitiveIndex),
- ScrollLayer(ScrollLayerId),
+ ClipNode(ClipId),
}
#[derive(Debug, Copy, Clone)]
pub enum RenderTaskId {
Static(RenderTaskIndex),
Dynamic(RenderTaskKey),
}
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -71,16 +71,18 @@ const GPU_TAG_PRIM_BLEND: GpuProfileTag
const GPU_TAG_PRIM_HW_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "HwComposite", color: debug_colors::DODGERBLUE };
const GPU_TAG_PRIM_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "Composite", color: debug_colors::MAGENTA };
const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag { label: "TextRun", color: debug_colors::BLUE };
const GPU_TAG_PRIM_GRADIENT: GpuProfileTag = GpuProfileTag { label: "Gradient", color: debug_colors::YELLOW };
const GPU_TAG_PRIM_ANGLE_GRADIENT: GpuProfileTag = GpuProfileTag { label: "AngleGradient", color: debug_colors::POWDERBLUE };
const GPU_TAG_PRIM_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag { label: "RadialGradient", color: debug_colors::LIGHTPINK };
const GPU_TAG_PRIM_BOX_SHADOW: GpuProfileTag = GpuProfileTag { label: "BoxShadow", color: debug_colors::CYAN };
const GPU_TAG_PRIM_BORDER: GpuProfileTag = GpuProfileTag { label: "Border", color: debug_colors::ORANGE };
+const GPU_TAG_PRIM_BORDER_CORNER: GpuProfileTag = GpuProfileTag { label: "BorderCorner", color: debug_colors::DARKSLATEGREY };
+const GPU_TAG_PRIM_BORDER_EDGE: GpuProfileTag = GpuProfileTag { label: "BorderEdge", color: debug_colors::LAVENDER };
const GPU_TAG_PRIM_CACHE_IMAGE: GpuProfileTag = GpuProfileTag { label: "CacheImage", color: debug_colors::SILVER };
const GPU_TAG_BLUR: GpuProfileTag = GpuProfileTag { label: "Blur", color: debug_colors::VIOLET };
#[derive(Debug, Copy, Clone)]
pub enum RendererKind {
Native,
OSMesa,
}
@@ -465,16 +467,18 @@ pub struct Renderer {
ps_rectangle: PrimitiveShader,
ps_rectangle_clip: PrimitiveShader,
ps_text_run: PrimitiveShader,
ps_text_run_subpixel: PrimitiveShader,
ps_image: PrimitiveShader,
ps_image_rect: PrimitiveShader,
ps_yuv_image: PrimitiveShader,
ps_border: PrimitiveShader,
+ ps_border_corner: PrimitiveShader,
+ ps_border_edge: PrimitiveShader,
ps_gradient: PrimitiveShader,
ps_angle_gradient: PrimitiveShader,
ps_radial_gradient: PrimitiveShader,
ps_box_shadow: PrimitiveShader,
ps_cache_image: PrimitiveShader,
ps_blend: LazilyCompiledShader,
ps_hw_composite: LazilyCompiledShader,
@@ -689,16 +693,30 @@ impl Renderer {
let ps_border = try!{
PrimitiveShader::new("ps_border",
&mut device,
&[],
options.precache_shaders)
};
+ let ps_border_corner = try!{
+ PrimitiveShader::new("ps_border_corner",
+ &mut device,
+ &[],
+ options.precache_shaders)
+ };
+
+ let ps_border_edge = try!{
+ PrimitiveShader::new("ps_border_edge",
+ &mut device,
+ &[],
+ options.precache_shaders)
+ };
+
let ps_box_shadow = try!{
PrimitiveShader::new("ps_box_shadow",
&mut device,
&[],
options.precache_shaders)
};
let ps_gradient = try!{
@@ -824,17 +842,16 @@ impl Renderer {
GpuDataTextures::new(&mut device),
];
let x0 = 0.0;
let y0 = 0.0;
let x1 = 1.0;
let y1 = 1.0;
- // TODO(gw): Consider separate VBO for quads vs border corners if VS ever shows up in profile!
let quad_indices: [u16; 6] = [ 0, 1, 2, 2, 1, 3 ];
let quad_vertices = [
PackedVertex {
pos: [x0, y0],
},
PackedVertex {
pos: [x1, y0],
},
@@ -920,16 +937,18 @@ impl Renderer {
ps_rectangle: ps_rectangle,
ps_rectangle_clip: ps_rectangle_clip,
ps_text_run: ps_text_run,
ps_text_run_subpixel: ps_text_run_subpixel,
ps_image: ps_image,
ps_image_rect: ps_image_rect,
ps_yuv_image: ps_yuv_image,
ps_border: ps_border,
+ ps_border_corner: ps_border_corner,
+ ps_border_edge: ps_border_edge,
ps_box_shadow: ps_box_shadow,
ps_gradient: ps_gradient,
ps_angle_gradient: ps_angle_gradient,
ps_radial_gradient: ps_radial_gradient,
ps_cache_image: ps_cache_image,
ps_blend: ps_blend,
ps_hw_composite: ps_hw_composite,
ps_composite: ps_composite,
@@ -947,23 +966,23 @@ impl Renderer {
color_render_targets: Vec::new(),
alpha_render_targets: Vec::new(),
gpu_profile: gpu_profile,
prim_vao_id: prim_vao_id,
blur_vao_id: blur_vao_id,
clip_vao_id: clip_vao_id,
gdt_index: 0,
gpu_data_textures: gpu_data_textures,
- pipeline_epoch_map: HashMap::with_hasher(Default::default()),
+ pipeline_epoch_map: HashMap::default(),
main_thread_dispatcher: main_thread_dispatcher,
cache_texture_id_map: Vec::new(),
dummy_cache_texture_id: dummy_cache_texture_id,
dither_matrix_texture_id: dither_matrix_texture_id,
external_image_handler: None,
- external_images: HashMap::with_hasher(Default::default()),
+ external_images: HashMap::default(),
vr_compositor_handler: vr_compositor,
cpu_profiles: VecDeque::new(),
gpu_profiles: VecDeque::new(),
};
let sender = RenderApiSender::new(api_tx, payload_tx);
Ok((renderer, sender))
}
@@ -1001,17 +1020,17 @@ impl Renderer {
/// Returns the Epoch of the current frame in a pipeline.
pub fn current_epoch(&self, pipeline_id: PipelineId) -> Option<Epoch> {
self.pipeline_epoch_map.get(&pipeline_id).cloned()
}
/// Returns a HashMap containing the pipeline ids that have been received by the renderer and
/// their respective epochs since the last time the method was called.
pub fn flush_rendered_epochs(&mut self) -> HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>> {
- mem::replace(&mut self.pipeline_epoch_map, HashMap::with_hasher(Default::default()))
+ mem::replace(&mut self.pipeline_epoch_map, HashMap::default())
}
/// Processes the result queue.
///
/// Should be called before `render()`, as texture cache updates are done here.
pub fn update(&mut self) {
profile_scope!("update");
@@ -1365,16 +1384,24 @@ impl Renderer {
AlphaBatchKind::YuvImage => {
let shader = self.ps_yuv_image.get(&mut self.device, transform_kind);
(GPU_TAG_PRIM_YUV_IMAGE, shader)
}
AlphaBatchKind::Border => {
let shader = self.ps_border.get(&mut self.device, transform_kind);
(GPU_TAG_PRIM_BORDER, shader)
}
+ AlphaBatchKind::BorderCorner => {
+ let shader = self.ps_border_corner.get(&mut self.device, transform_kind);
+ (GPU_TAG_PRIM_BORDER_CORNER, shader)
+ }
+ AlphaBatchKind::BorderEdge => {
+ let shader = self.ps_border_edge.get(&mut self.device, transform_kind);
+ (GPU_TAG_PRIM_BORDER_EDGE, shader)
+ }
AlphaBatchKind::AlignedGradient => {
let shader = self.ps_gradient.get(&mut self.device, transform_kind);
(GPU_TAG_PRIM_GRADIENT, shader)
}
AlphaBatchKind::AngleGradient => {
let shader = self.ps_angle_gradient.get(&mut self.device, transform_kind);
(GPU_TAG_PRIM_ANGLE_GRADIENT, shader)
}
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -124,18 +124,18 @@ struct CachedImageInfo {
pub struct ResourceClassCache<K,V> {
resources: HashMap<K, V, BuildHasherDefault<FnvHasher>>,
last_access_times: HashMap<K, FrameId, BuildHasherDefault<FnvHasher>>,
}
impl<K,V> ResourceClassCache<K,V> where K: Clone + Hash + Eq + Debug, V: Resource {
fn new() -> ResourceClassCache<K,V> {
ResourceClassCache {
- resources: HashMap::with_hasher(Default::default()),
- last_access_times: HashMap::with_hasher(Default::default()),
+ resources: HashMap::default(),
+ last_access_times: HashMap::default(),
}
}
fn contains_key(&self, key: &K) -> bool {
self.resources.contains_key(key)
}
fn get(&self, key: &K, frame: FrameId) -> &V {
@@ -230,20 +230,20 @@ impl ResourceCache {
workers: Arc<Mutex<ThreadPool>>,
blob_image_renderer: Option<Box<BlobImageRenderer>>,
enable_aa: bool) -> ResourceCache {
let (glyph_cache_tx, glyph_cache_result_queue) = spawn_glyph_cache_thread(workers);
ResourceCache {
cached_glyphs: Some(ResourceClassCache::new()),
cached_images: ResourceClassCache::new(),
- webgl_textures: HashMap::with_hasher(Default::default()),
- font_templates: HashMap::with_hasher(Default::default()),
- image_templates: HashMap::with_hasher(Default::default()),
- cached_glyph_dimensions: HashMap::with_hasher(Default::default()),
+ webgl_textures: HashMap::default(),
+ font_templates: HashMap::default(),
+ image_templates: HashMap::default(),
+ cached_glyph_dimensions: HashMap::default(),
texture_cache: texture_cache,
state: State::Idle,
enable_aa: enable_aa,
current_frame_id: FrameId(0),
pending_image_requests: Vec::new(),
glyph_cache_tx: glyph_cache_tx,
glyph_cache_result_queue: glyph_cache_result_queue,
pending_external_image_update_list: ExternalImageUpdateList::new(),
--- a/gfx/webrender/src/scene.rs
+++ b/gfx/webrender/src/scene.rs
@@ -16,18 +16,18 @@ use webrender_traits::{PropertyBinding,
pub struct SceneProperties {
transform_properties: HashMap<PropertyBindingId, LayoutTransform>,
float_properties: HashMap<PropertyBindingId, f32>,
}
impl SceneProperties {
pub fn new() -> SceneProperties {
SceneProperties {
- transform_properties: HashMap::with_hasher(Default::default()),
- float_properties: HashMap::with_hasher(Default::default()),
+ transform_properties: HashMap::default(),
+ float_properties: HashMap::default(),
}
}
/// Set the current property list for this display list.
pub fn set_properties(&mut self, properties: DynamicProperties) {
self.transform_properties.clear();
self.float_properties.clear();
@@ -97,19 +97,19 @@ pub struct Scene {
pub display_lists: HashMap<PipelineId, Vec<DisplayItem>, BuildHasherDefault<FnvHasher>>,
pub properties: SceneProperties,
}
impl Scene {
pub fn new() -> Scene {
Scene {
root_pipeline_id: None,
- pipeline_map: HashMap::with_hasher(Default::default()),
- pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
- display_lists: HashMap::with_hasher(Default::default()),
+ pipeline_map: HashMap::default(),
+ pipeline_auxiliary_lists: HashMap::default(),
+ display_lists: HashMap::default(),
properties: SceneProperties::new(),
}
}
pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
self.root_pipeline_id = Some(pipeline_id);
}
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -460,30 +460,33 @@ impl TextureCacheItem {
}
}
}
struct TextureCacheArena {
pages_a8: Vec<TexturePage>,
pages_rgb8: Vec<TexturePage>,
pages_rgba8: Vec<TexturePage>,
+ pages_rg8: Vec<TexturePage>,
}
impl TextureCacheArena {
fn new() -> TextureCacheArena {
TextureCacheArena {
pages_a8: Vec::new(),
pages_rgb8: Vec::new(),
pages_rgba8: Vec::new(),
+ pages_rg8: Vec::new(),
}
}
fn texture_page_for_id(&mut self, id: CacheTextureId) -> Option<&mut TexturePage> {
for page in self.pages_a8.iter_mut().chain(self.pages_rgb8.iter_mut())
- .chain(self.pages_rgba8.iter_mut()) {
+ .chain(self.pages_rgba8.iter_mut())
+ .chain(self.pages_rg8.iter_mut()) {
if page.texture_id == id {
return Some(page)
}
}
None
}
}
@@ -541,17 +544,17 @@ pub struct AllocationResult {
impl TextureCache {
pub fn new(mut max_texture_size: u32) -> TextureCache {
if max_texture_size * max_texture_size > MAX_RGBA_PIXELS_PER_TEXTURE {
max_texture_size = SQRT_MAX_RGBA_PIXELS_PER_TEXTURE;
}
TextureCache {
cache_id_list: CacheTextureIdList::new(),
- free_texture_levels: HashMap::with_hasher(Default::default()),
+ free_texture_levels: HashMap::default(),
items: FreeList::new(),
pending_updates: TextureUpdateList::new(),
arena: TextureCacheArena::new(),
max_texture_size: max_texture_size,
}
}
pub fn max_texture_size(&self) -> u32 {
@@ -602,16 +605,17 @@ impl TextureCache {
}
}
let mode = RenderTargetMode::SimpleRenderTarget;
let (page_list, page_profile) = match format {
ImageFormat::A8 => (&mut self.arena.pages_a8, &mut profile.pages_a8),
ImageFormat::RGBA8 => (&mut self.arena.pages_rgba8, &mut profile.pages_rgba8),
ImageFormat::RGB8 => (&mut self.arena.pages_rgb8, &mut profile.pages_rgb8),
+ ImageFormat::RG8 => (&mut self.arena.pages_rg8, &mut profile.pages_rg8),
ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
};
// TODO(gw): Handle this sensibly (support failing to render items that can't fit?)
assert!(requested_size.width <= self.max_texture_size);
assert!(requested_size.height <= self.max_texture_size);
let mut page_id = None; //using ID here to please the borrow checker
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -18,22 +18,21 @@ use render_task::{RenderTaskId, RenderTa
use render_task::RenderTaskLocation;
use renderer::BlendMode;
use resource_cache::ResourceCache;
use std::{f32, i32, mem, usize};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use texture_cache::TexturePage;
use util::{TransformedRect, TransformedRectKind};
-use webrender_traits::{AuxiliaryLists, ColorF, DeviceIntPoint, DeviceIntRect};
-use webrender_traits::{DeviceIntSize, DeviceUintPoint};
-use webrender_traits::{DeviceUintSize, FontRenderMode, ImageRendering, LayerPoint, LayerRect};
-use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, ScrollLayerId};
-use webrender_traits::{TransformStyle, WorldPoint4D, WorldToLayerTransform};
-use webrender_traits::{ExternalImageType};
+use webrender_traits::{AuxiliaryLists, ClipId, ColorF, DeviceIntPoint, DeviceIntRect};
+use webrender_traits::{DeviceIntSize, DeviceUintPoint, DeviceUintSize, ExternalImageType};
+use webrender_traits::{FontRenderMode, ImageRendering, LayerPoint, LayerRect};
+use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, TransformStyle};
+use webrender_traits::{WorldPoint4D, WorldToLayerTransform};
// Special sentinel value recognized by the shader. It is considered to be
// a dummy task that doesn't mask out anything.
const OPAQUE_TASK_INDEX: RenderTaskIndex = RenderTaskIndex(i32::MAX as usize);
pub type AuxiliaryListsMap = HashMap<PipelineId,
AuxiliaryLists,
@@ -103,32 +102,32 @@ impl AlphaBatchHelpers for PrimitiveStor
}
}
}
}
}
#[derive(Debug)]
pub struct ScrollbarPrimitive {
- pub scroll_layer_id: ScrollLayerId,
+ pub clip_id: ClipId,
pub prim_index: PrimitiveIndex,
pub border_radius: f32,
}
#[derive(Debug)]
pub enum PrimitiveRunCmd {
PushStackingContext(StackingContextIndex),
PopStackingContext,
- PrimitiveRun(PrimitiveIndex, usize, ScrollLayerId),
+ PrimitiveRun(PrimitiveIndex, usize, ClipId),
}
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveFlags {
None,
- Scrollbar(ScrollLayerId, f32)
+ Scrollbar(ClipId, f32)
}
#[derive(Debug, Copy, Clone)]
pub struct RenderTargetIndex(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct RenderPassIndex(isize);
@@ -141,17 +140,17 @@ pub struct RenderTaskCollection {
pub render_task_data: Vec<RenderTaskData>,
dynamic_tasks: HashMap<(RenderTaskKey, RenderPassIndex), DynamicTaskInfo, BuildHasherDefault<FnvHasher>>,
}
impl RenderTaskCollection {
pub fn new(static_render_task_count: usize) -> RenderTaskCollection {
RenderTaskCollection {
render_task_data: vec![RenderTaskData::empty(); static_render_task_count],
- dynamic_tasks: HashMap::with_hasher(Default::default()),
+ dynamic_tasks: HashMap::default(),
}
}
fn add(&mut self, task: &RenderTask, pass: RenderPassIndex) -> RenderTaskIndex {
match task.id {
RenderTaskId::Static(index) => {
self.render_task_data[index.0] = task.write_task_data();
index
@@ -219,16 +218,24 @@ pub struct BatchList {
impl BatchList {
fn new() -> BatchList {
BatchList {
alpha_batches: Vec::new(),
opaque_batches: Vec::new(),
}
}
+ fn with_suitable_batch<F>(&mut self,
+ key: &AlphaBatchKey,
+ item_bounding_rect: &DeviceIntRect,
+ f: F) where F: Fn(&mut PrimitiveBatch) {
+ let batch = self.get_suitable_batch(key, item_bounding_rect);
+ f(batch)
+ }
+
fn get_suitable_batch(&mut self,
key: &AlphaBatchKey,
item_bounding_rect: &DeviceIntRect) -> &mut PrimitiveBatch {
let (batches, check_intersections) = match key.blend_mode {
BlendMode::None => {
(&mut self.opaque_batches, false)
}
BlendMode::Alpha | BlendMode::PremultipliedAlpha | BlendMode::Subpixel(..) => {
@@ -409,20 +416,39 @@ impl AlphaRenderItem {
prim_address: prim_address,
sub_index: 0,
user_data: [0, 0],
z_sort_index: z,
};
match prim_metadata.prim_kind {
PrimitiveKind::Border => {
- let key = AlphaBatchKey::new(AlphaBatchKind::Border, flags, blend_mode, textures);
- let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
- for border_segment in 0..8 {
- batch.add_instance(base_instance.build(border_segment, 0, 0));
+ let border_cpu = &ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0];
+ if border_cpu.use_new_border_path {
+ // TODO(gw): Select correct blend mode for edges and corners!!
+ let corner_key = AlphaBatchKey::new(AlphaBatchKind::BorderCorner, flags, blend_mode, textures);
+ let edge_key = AlphaBatchKey::new(AlphaBatchKind::BorderEdge, flags, blend_mode, textures);
+
+ batch_list.with_suitable_batch(&corner_key, item_bounding_rect, |batch| {
+ for border_segment in 0..4 {
+ batch.add_instance(base_instance.build(border_segment, 0, 0));
+ }
+ });
+
+ batch_list.with_suitable_batch(&edge_key, item_bounding_rect, |batch| {
+ for border_segment in 0..4 {
+ batch.add_instance(base_instance.build(border_segment, 0, 0));
+ }
+ });
+ } else {
+ let key = AlphaBatchKey::new(AlphaBatchKind::Border, flags, blend_mode, textures);
+ let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
+ for border_segment in 0..8 {
+ batch.add_instance(base_instance.build(border_segment, 0, 0));
+ }
}
}
PrimitiveKind::Rectangle => {
let key = AlphaBatchKey::new(AlphaBatchKind::Rectangle, flags, blend_mode, textures);
let batch = batch_list.get_suitable_batch(&key, item_bounding_rect);
batch.add_instance(base_instance);
}
PrimitiveKind::Image => {
@@ -1093,16 +1119,18 @@ pub enum AlphaBatchKind {
ImageRect,
YuvImage,
Border,
AlignedGradient,
AngleGradient,
RadialGradient,
BoxShadow,
CacheImage,
+ BorderCorner,
+ BorderEdge,
}
bitflags! {
pub flags AlphaBatchKeyFlags: u8 {
const NEEDS_CLIPPING = 0b00000001,
const AXIS_ALIGNED = 0b00000010,
}
}
@@ -1279,44 +1307,44 @@ impl StackingContext {
composite_ops: composite_ops,
clip_scroll_groups: Vec::new(),
should_isolate: transform_style == TransformStyle::Preserve3D, //TODO
is_page_root: is_page_root,
is_visible: false,
}
}
- pub fn clip_scroll_group(&self, scroll_layer_id: ScrollLayerId) -> ClipScrollGroupIndex {
+ pub fn clip_scroll_group(&self, clip_id: ClipId) -> ClipScrollGroupIndex {
// Currently there is only one scrolled stacking context per context,
// but eventually this will be selected from the vector based on the
// scroll layer of this primitive.
for group in &self.clip_scroll_groups {
- if group.1 == scroll_layer_id {
+ if group.1 == clip_id {
return *group;
}
}
unreachable!("Looking for non-existent ClipScrollGroup");
}
pub fn can_contribute_to_scene(&self) -> bool {
!self.composite_ops.will_make_invisible()
}
- pub fn has_clip_scroll_group(&self, id: ScrollLayerId) -> bool {
+ pub fn has_clip_scroll_group(&self, id: ClipId) -> bool {
self.clip_scroll_groups.iter().rev().any(|index| index.1 == id)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub struct ClipScrollGroupIndex(pub usize, pub ScrollLayerId);
+pub struct ClipScrollGroupIndex(pub usize, pub ClipId);
#[derive(Debug)]
pub struct ClipScrollGroup {
pub stacking_context_index: StackingContextIndex,
- pub scroll_layer_id: ScrollLayerId,
+ pub clip_id: ClipId,
pub packed_layer_index: PackedLayerIndex,
pub xf_rect: Option<TransformedRect>,
}
impl ClipScrollGroup {
pub fn is_visible(&self) -> bool {
self.xf_rect.is_some()
}
--- a/gfx/webrender/src/util.rs
+++ b/gfx/webrender/src/util.rs
@@ -296,25 +296,23 @@ impl ComplexClipRegionHelpers for Comple
}
}
#[inline]
fn extract_inner_rect_impl<U>(rect: &TypedRect<f32, U>,
radii: &BorderRadius,
k: f32) -> Option<TypedRect<f32, U>> {
// `k` defines how much border is taken into account
+ // We enforce the offsets to be rounded to pixel boundaries
+ // by `ceil`-ing and `floor`-ing them
- let xl = rect.origin.x +
- k * radii.top_left.width.max(radii.bottom_left.width);
- let xr = rect.origin.x + rect.size.width -
- k * radii.top_right.width.max(radii.bottom_right.width);
- let yt = rect.origin.y +
- k * radii.top_left.height.max(radii.top_right.height);
- let yb = rect.origin.y + rect.size.height -
- k * radii.bottom_left.height.max(radii.bottom_right.height);
+ let xl = (k * radii.top_left.width.max(radii.bottom_left.width)).ceil();
+ let xr = (rect.size.width - k * radii.top_right.width.max(radii.bottom_right.width)).floor();
+ let yt = (k * radii.top_left.height.max(radii.top_right.height)).ceil();
+ let yb = (rect.size.height - k * radii.bottom_left.height.max(radii.bottom_right.height)).floor();
if xl <= xr && yt <= yb {
- Some(TypedRect::new(TypedPoint2D::new(xl, yt),
+ Some(TypedRect::new(TypedPoint2D::new(rect.origin.x + xl, rect.origin.y + yt),
TypedSize2D::new(xr-xl, yb-yt)))
} else {
None
}
}
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "webrender_traits"
-version = "0.32.0"
+version = "0.33.0"
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
license = "MPL-2.0"
repository = "https://github.com/servo/webrender"
[features]
nightly = ["euclid/unstable", "serde/unstable"]
ipc = ["ipc-channel"]
webgl = ["offscreen_gl_context"]
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -4,19 +4,19 @@
use channel::{self, MsgSender, Payload, PayloadSenderHelperMethods, PayloadSender};
#[cfg(feature = "webgl")]
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use std::cell::Cell;
use std::fmt;
use std::marker::PhantomData;
use {AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList, BuiltDisplayListDescriptor};
-use {ColorF, DeviceIntPoint, DeviceIntSize, DeviceUintRect, DeviceUintSize, FontKey};
+use {ClipId, ColorF, DeviceIntPoint, DeviceIntSize, DeviceUintRect, DeviceUintSize, FontKey};
use {GlyphDimensions, GlyphKey, ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutSize};
-use {LayoutTransform, NativeFontHandle, ScrollLayerId, WorldPoint};
+use {LayoutTransform, NativeFontHandle, WorldPoint};
#[cfg(feature = "webgl")]
use {WebGLCommand, WebGLContextId};
pub type TileSize = u16;
#[derive(Clone, Deserialize, Serialize)]
pub enum ApiMsg {
AddRawFont(FontKey, Vec<u8>),
@@ -43,20 +43,20 @@ pub enum ApiMsg {
AuxiliaryListsDescriptor,
bool),
SetPageZoom(ZoomFactor),
SetPinchZoom(ZoomFactor),
SetPan(DeviceIntPoint),
SetRootPipeline(PipelineId),
SetWindowParameters(DeviceUintSize, DeviceUintRect),
Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
- ScrollLayerWithId(LayoutPoint, ScrollLayerId),
+ ScrollNodeWithId(LayoutPoint, ClipId),
TickScrollingBounce,
TranslatePointToLayerSpace(WorldPoint, MsgSender<(LayoutPoint, PipelineId)>),
- GetScrollLayerState(MsgSender<Vec<ScrollLayerState>>),
+ GetScrollNodeState(MsgSender<Vec<ScrollLayerState>>),
RequestWebGLContext(DeviceIntSize, GLContextAttributes, MsgSender<Result<(WebGLContextId, GLLimits), String>>),
ResizeWebGLContext(WebGLContextId, DeviceIntSize),
WebGLCommand(WebGLContextId, WebGLCommand),
GenerateFrame(Option<DynamicProperties>),
// WebVR commands that must be called in the WebGL render thread.
VRCompositorCommand(WebGLContextId, VRCompositorCommand),
/// An opaque handle that must be passed to the render notifier. It is used by Gecko
/// to forward gecko-specific messages to the render thread preserving the ordering
@@ -74,20 +74,20 @@ impl fmt::Debug for ApiMsg {
ApiMsg::GetGlyphDimensions(..) => "ApiMsg::GetGlyphDimensions",
ApiMsg::AddImage(..) => "ApiMsg::AddImage",
ApiMsg::UpdateImage(..) => "ApiMsg::UpdateImage",
ApiMsg::DeleteImage(..) => "ApiMsg::DeleteImage",
ApiMsg::CloneApi(..) => "ApiMsg::CloneApi",
ApiMsg::SetDisplayList(..) => "ApiMsg::SetDisplayList",
ApiMsg::SetRootPipeline(..) => "ApiMsg::SetRootPipeline",
ApiMsg::Scroll(..) => "ApiMsg::Scroll",
- ApiMsg::ScrollLayerWithId(..) => "ApiMsg::ScrollLayerWithId",
+ ApiMsg::ScrollNodeWithId(..) => "ApiMsg::ScrollNodeWithId",
ApiMsg::TickScrollingBounce => "ApiMsg::TickScrollingBounce",
ApiMsg::TranslatePointToLayerSpace(..) => "ApiMsg::TranslatePointToLayerSpace",
- ApiMsg::GetScrollLayerState(..) => "ApiMsg::GetScrollLayerState",
+ ApiMsg::GetScrollNodeState(..) => "ApiMsg::GetScrollNodeState",
ApiMsg::RequestWebGLContext(..) => "ApiMsg::RequestWebGLContext",
ApiMsg::ResizeWebGLContext(..) => "ApiMsg::ResizeWebGLContext",
ApiMsg::WebGLCommand(..) => "ApiMsg::WebGLCommand",
ApiMsg::GenerateFrame(..) => "ApiMsg::GenerateFrame",
ApiMsg::VRCompositorCommand(..) => "ApiMsg::VRCompositorCommand",
ApiMsg::ExternalEvent(..) => "ApiMsg::ExternalEvent",
ApiMsg::ShutDown => "ApiMsg::ShutDown",
ApiMsg::SetPageZoom(..) => "ApiMsg::SetPageZoom",
@@ -329,18 +329,18 @@ impl RenderApi {
///
/// WebRender looks for the layer closest to the user
/// which has `ScrollPolicy::Scrollable` set.
pub fn scroll(&self, scroll_location: ScrollLocation, cursor: WorldPoint, phase: ScrollEventPhase) {
let msg = ApiMsg::Scroll(scroll_location, cursor, phase);
self.api_sender.send(msg).unwrap();
}
- pub fn scroll_layer_with_id(&self, new_scroll_origin: LayoutPoint, id: ScrollLayerId) {
- let msg = ApiMsg::ScrollLayerWithId(new_scroll_origin, id);
+ pub fn scroll_node_with_id(&self, new_scroll_origin: LayoutPoint, id: ClipId) {
+ let msg = ApiMsg::ScrollNodeWithId(new_scroll_origin, id);
self.api_sender.send(msg).unwrap();
}
pub fn set_page_zoom(&self, page_zoom: ZoomFactor) {
let msg = ApiMsg::SetPageZoom(page_zoom);
self.api_sender.send(msg).unwrap();
}
@@ -370,19 +370,19 @@ impl RenderApi {
pub fn translate_point_to_layer_space(&self, point: &WorldPoint)
-> (LayoutPoint, PipelineId) {
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::TranslatePointToLayerSpace(*point, tx);
self.api_sender.send(msg).unwrap();
rx.recv().unwrap()
}
- pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
+ pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
let (tx, rx) = channel::msg_channel().unwrap();
- let msg = ApiMsg::GetScrollLayerState(tx);
+ let msg = ApiMsg::GetScrollNodeState(tx);
self.api_sender.send(msg).unwrap();
rx.recv().unwrap()
}
pub fn request_webgl_context(&self, size: &DeviceIntSize, attributes: GLContextAttributes)
-> Result<(WebGLContextId, GLLimits), String> {
let (tx, rx) = channel::msg_channel().unwrap();
let msg = ApiMsg::RequestWebGLContext(*size, attributes, tx);
@@ -452,17 +452,17 @@ pub enum ScrollEventPhase {
/// down, if a touchpad is in use. (If false, the event is a touchpad fling.)
Move(bool),
/// The user ended scrolling.
End,
}
#[derive(Clone, Deserialize, Serialize)]
pub struct ScrollLayerState {
- pub id: ScrollLayerId,
+ pub id: ClipId,
pub scroll_offset: LayoutPoint,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum ScrollLocation {
/// Scroll by a certain amount.
Delta(LayoutPoint),
/// Scroll to very top of element.
--- a/gfx/webrender_traits/src/display_item.rs
+++ b/gfx/webrender_traits/src/display_item.rs
@@ -9,17 +9,17 @@ use {ColorF, FontKey, ImageKey, Pipeline
use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
use {PropertyBinding};
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct DisplayItem {
pub item: SpecificDisplayItem,
pub rect: LayoutRect,
pub clip: ClipRegion,
- pub scroll_layer_id: ScrollLayerId,
+ pub clip_id: ClipId,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum SpecificDisplayItem {
Clip(ClipDisplayItem),
Rectangle(RectangleDisplayItem),
Text(TextDisplayItem),
Image(ImageDisplayItem),
@@ -38,18 +38,18 @@ pub enum SpecificDisplayItem {
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ItemRange {
pub start: usize,
pub length: usize,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ClipDisplayItem {
- pub id: ScrollLayerId,
- pub parent_id: ScrollLayerId,
+ pub id: ClipId,
+ pub parent_id: ClipId,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct RectangleDisplayItem {
pub color: ColorF,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
@@ -498,49 +498,49 @@ impl ComplexClipRegion {
ComplexClipRegion {
rect: rect,
radii: radii,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub enum ScrollLayerId {
+pub enum ClipId {
Clip(u64, PipelineId),
ClipExternalId(u64, PipelineId),
ReferenceFrame(u64, PipelineId),
}
-impl ScrollLayerId {
- pub fn root_scroll_layer(pipeline_id: PipelineId) -> ScrollLayerId {
- ScrollLayerId::Clip(0, pipeline_id)
+impl ClipId {
+ pub fn root_scroll_node(pipeline_id: PipelineId) -> ClipId {
+ ClipId::Clip(0, pipeline_id)
}
- pub fn root_reference_frame(pipeline_id: PipelineId) -> ScrollLayerId {
- ScrollLayerId::ReferenceFrame(0, pipeline_id)
+ pub fn root_reference_frame(pipeline_id: PipelineId) -> ClipId {
+ ClipId::ReferenceFrame(0, pipeline_id)
}
- pub fn new(id: u64, pipeline_id: PipelineId) -> ScrollLayerId {
- ScrollLayerId::ClipExternalId(id, pipeline_id)
+ pub fn new(id: u64, pipeline_id: PipelineId) -> ClipId {
+ ClipId::ClipExternalId(id, pipeline_id)
}
pub fn pipeline_id(&self) -> PipelineId {
match *self {
- ScrollLayerId::Clip(_, pipeline_id) |
- ScrollLayerId::ClipExternalId(_, pipeline_id) |
- ScrollLayerId::ReferenceFrame(_, pipeline_id) => pipeline_id,
+ ClipId::Clip(_, pipeline_id) |
+ ClipId::ClipExternalId(_, pipeline_id) |
+ ClipId::ReferenceFrame(_, pipeline_id) => pipeline_id,
}
}
pub fn is_reference_frame(&self) -> bool {
match *self {
- ScrollLayerId::ReferenceFrame(..) => true,
+ ClipId::ReferenceFrame(..) => true,
_ => false,
}
}
pub fn external_id(&self) -> Option<u64> {
match *self {
- ScrollLayerId::ClipExternalId(id, _) => Some(id),
+ ClipId::ClipExternalId(id, _) => Some(id),
_ => None,
}
}
}
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -1,24 +1,23 @@
/* 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/. */
use app_units::Au;
use std::mem;
use std::slice;
use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
-use {ClipDisplayItem, ClipRegion, ColorF, ComplexClipRegion, DisplayItem, ExtendMode, FilterOp};
-use {FontKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem, GradientStop};
+use {ClipDisplayItem, ClipId, ClipRegion, ColorF, ComplexClipRegion, DisplayItem, ExtendMode};
+use {FilterOp, FontKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem, GradientStop};
use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering, ItemRange};
-use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use {TransformStyle, MixBlendMode, PipelineId};
+use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode, PipelineId};
use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
-use {RectangleDisplayItem, ScrollLayerId, ScrollPolicy, SpecificDisplayItem, StackingContext};
-use {TextDisplayItem, WebGLContextId, WebGLDisplayItem, YuvColorSpace, YuvImageDisplayItem};
+use {RectangleDisplayItem, ScrollPolicy, SpecificDisplayItem, StackingContext, TextDisplayItem};
+use {TransformStyle, WebGLContextId, WebGLDisplayItem, YuvColorSpace, YuvImageDisplayItem};
#[derive(Clone, Deserialize, Serialize)]
pub struct AuxiliaryLists {
/// The concatenation of: gradient stops, complex clip regions, filters, and glyph instances,
/// in that order.
data: Vec<u8>,
descriptor: AuxiliaryListsDescriptor,
}
@@ -77,71 +76,71 @@ impl BuiltDisplayList {
}
pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
&self.descriptor
}
pub fn all_display_items(&self) -> &[DisplayItem] {
unsafe {
- convert_blob_to_pod(&self.data[0..self.descriptor.display_list_items_size])
+ convert_blob_to_pod(&self.data)
}
}
pub fn into_display_items(self) -> Vec<DisplayItem> {
unsafe {
convert_vec_blob_to_pod(self.data)
}
}
}
#[derive(Clone)]
pub struct DisplayListBuilder {
pub list: Vec<DisplayItem>,
auxiliary_lists_builder: AuxiliaryListsBuilder,
pub pipeline_id: PipelineId,
- clip_stack: Vec<ScrollLayerId>,
- next_scroll_layer_id: u64,
+ clip_stack: Vec<ClipId>,
+ next_clip_id: u64,
}
impl DisplayListBuilder {
pub fn new(pipeline_id: PipelineId) -> DisplayListBuilder {
DisplayListBuilder {
list: Vec::new(),
auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
pipeline_id: pipeline_id,
- clip_stack: vec![ScrollLayerId::root_scroll_layer(pipeline_id)],
+ clip_stack: vec![ClipId::root_scroll_node(pipeline_id)],
// We start at 1 here, because the root scroll id is always 0.
- next_scroll_layer_id: 1,
+ next_clip_id: 1,
}
}
pub fn print_display_list(&mut self) {
for item in &self.list {
println!("{:?}", item);
}
}
fn push_item(&mut self, item: SpecificDisplayItem, rect: LayoutRect, clip: ClipRegion) {
self.list.push(DisplayItem {
item: item,
rect: rect,
clip: clip,
- scroll_layer_id: *self.clip_stack.last().unwrap(),
+ clip_id: *self.clip_stack.last().unwrap(),
});
}
fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
self.list.push(DisplayItem {
item: item,
rect: LayoutRect::zero(),
clip: ClipRegion::simple(&LayoutRect::zero()),
- scroll_layer_id: *self.clip_stack.last().unwrap(),
+ clip_id: *self.clip_stack.last().unwrap(),
});
}
pub fn push_rect(&mut self,
rect: LayoutRect,
clip: ClipRegion,
color: ColorF) {
let item = SpecificDisplayItem::Rectangle(RectangleDisplayItem {
@@ -192,17 +191,17 @@ impl DisplayListBuilder {
context_id: context_id,
});
self.push_item(item, rect, clip);
}
pub fn push_text(&mut self,
rect: LayoutRect,
clip: ClipRegion,
- glyphs: Vec<GlyphInstance>,
+ glyphs: &[GlyphInstance],
font_key: FontKey,
color: ColorF,
size: Au,
blur_radius: Au,
glyph_options: Option<GlyphOptions>) {
// Sanity check - anything with glyphs bigger than this
// is probably going to consume too much memory to render
// efficiently anyway. This is specifically to work around
@@ -448,53 +447,53 @@ impl DisplayListBuilder {
pub fn pop_stacking_context(&mut self) {
self.push_new_empty_item(SpecificDisplayItem::PopStackingContext);
}
pub fn define_clip(&mut self,
content_rect: LayoutRect,
clip: ClipRegion,
- id: Option<ScrollLayerId>)
- -> ScrollLayerId {
+ id: Option<ClipId>)
+ -> ClipId {
let id = match id {
Some(id) => id,
None => {
- self.next_scroll_layer_id += 1;
- ScrollLayerId::Clip(self.next_scroll_layer_id - 1, self.pipeline_id)
+ self.next_clip_id += 1;
+ ClipId::Clip(self.next_clip_id - 1, self.pipeline_id)
}
};
let item = SpecificDisplayItem::Clip(ClipDisplayItem {
id: id,
parent_id: *self.clip_stack.last().unwrap(),
});
self.push_item(item, content_rect, clip);
id
}
- pub fn push_scroll_layer(&mut self,
- clip: ClipRegion,
- content_rect: LayoutRect,
- id: Option<ScrollLayerId>) {
+ pub fn push_clip_node(&mut self,
+ clip: ClipRegion,
+ content_rect: LayoutRect,
+ id: Option<ClipId>) {
let id = self.define_clip(content_rect, clip, id);
self.clip_stack.push(id);
}
- pub fn push_clip_id(&mut self, id: ScrollLayerId) {
+ pub fn push_clip_id(&mut self, id: ClipId) {
self.clip_stack.push(id);
}
pub fn pop_clip_id(&mut self) {
self.clip_stack.pop();
assert!(self.clip_stack.len() > 0);
}
- pub fn pop_scroll_layer(&mut self) {
+ pub fn pop_clip_node(&mut self) {
self.pop_clip_id();
}
pub fn push_iframe(&mut self, rect: LayoutRect, clip: ClipRegion, pipeline_id: PipelineId) {
let item = SpecificDisplayItem::Iframe(IframeDisplayItem { pipeline_id: pipeline_id });
self.push_item(item, rect, clip);
}
@@ -523,17 +522,17 @@ impl DisplayListBuilder {
}
Iframe(_) | Clip(_) => {
// We don't support relocating these
panic!();
}
_ => {}
}
i.clip.complex = self.auxiliary_lists_builder.add_complex_clip_regions(aux.complex_clip_regions(&i.clip.complex));
- i.scroll_layer_id = *self.clip_stack.last().unwrap();
+ i.clip_id = *self.clip_stack.last().unwrap();
self.list.push(i);
}
}
pub fn new_clip_region(&mut self,
rect: &LayoutRect,
complex: Vec<ComplexClipRegion>,
image_mask: Option<ImageMask>)
--- a/gfx/webrender_traits/src/image.rs
+++ b/gfx/webrender_traits/src/image.rs
@@ -13,36 +13,39 @@ impl ImageKey {
pub fn new(key0: u32, key1: u32) -> ImageKey {
ImageKey(key0, key1)
}
}
/// An arbitrary identifier for an external image provided by the
/// application. It must be a unique identifier for each external
/// image.
+#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ExternalImageId(pub u64);
#[repr(u32)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ImageFormat {
Invalid = 0,
A8 = 1,
RGB8 = 2,
RGBA8 = 3,
RGBAF32 = 4,
+ RG8 = 5,
}
impl ImageFormat {
pub fn bytes_per_pixel(self) -> Option<u32> {
match self {
ImageFormat::A8 => Some(1),
ImageFormat::RGB8 => Some(3),
ImageFormat::RGBA8 => Some(4),
ImageFormat::RGBAF32 => Some(16),
+ ImageFormat::RG8 => Some(2),
ImageFormat::Invalid => None,
}
}
}
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ImageDescriptor {
pub format: ImageFormat,