2017-04-11 14:00:41 +00:00
|
|
|
# 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,
|
2017-05-10 14:28:39 +00:00
|
|
|
pub complex: ItemRange<ComplexClip>,
|
2017-04-11 14:00:41 +00:00
|
|
|
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.
|
2017-04-18 15:18:02 +00:00
|
|
|
Display items can be assigned a clip display item using the `clip_id`
|
2017-04-11 14:00:41 +00:00
|
|
|
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 {
|
2017-04-18 15:18:02 +00:00
|
|
|
pub id: ClipId,
|
|
|
|
pub parent_id: ClipId,
|
2017-04-11 14:00:41 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
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
|
2017-04-18 15:18:02 +00:00
|
|
|
here are those created with `ClipId::new(...)`. If this argument is not
|
2017-04-11 14:00:41 +00:00
|
|
|
provided `define_clip` will return a uniquely generated id. Thus, the following
|
|
|
|
should always be true:
|
|
|
|
|
|
|
|
```rust
|
2017-04-18 15:18:02 +00:00
|
|
|
let id = ClipId::new(my_internal_id, pipeline_id);
|
2017-04-11 14:00:41 +00:00
|
|
|
let generated_id = define_clip(content_rect, clip, id);
|
|
|
|
assert!(id == generated_id);
|
|
|
|
```
|
|
|
|
|
2017-04-26 14:33:14 +00:00
|
|
|
Note that calling `define_clip` multiple times with the same `clip_id` value
|
|
|
|
results in undefined behaviour, and should be avoided. There is a debug mode
|
|
|
|
assertion to catch this.
|
|
|
|
|
2017-04-11 14:00:41 +00:00
|
|
|
## Pending changes
|
2017-04-18 15:18:02 +00:00
|
|
|
1. Normalize the way that clipping coordinates are defined. Having them
|
2017-04-11 14:00:41 +00:00
|
|
|
specified in two different ways makes for a confusing API. This should be
|
|
|
|
fixed. ([github issue](https://github.com/servo/webrender/issues/1090))
|
|
|
|
|
2017-04-18 15:18:02 +00:00
|
|
|
1. It should be possible to specify more than one predefined clip for an item.
|
2017-04-11 14:00:41 +00:00
|
|
|
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))
|