gecko-dev/gfx/webrender/doc/CLIPPING.md

4.2 KiB

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.

pub struct ClipRegion {
    pub main: LayoutRect,
    pub complex: ItemRange<ComplexClip>,
    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:

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:

let id = ClipId::new(my_internal_id, pipeline_id);
let generated_id = define_clip(content_rect, clip, id);
assert!(id == generated_id);

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.

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)

  2. 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)