# Common Ancestor Clip
[CommonAncestorClip](https://source.chromium.org/chromium/chromium/src/+/main:cc/base/features.cc;l=63;drc=3caf2592a8080d7a4949467119361062b61819eb) or render surface is a feature in cc to introduce new logic on computing clip rect.
This feature changes the logic to compute the clip rect for ClipTree.
Let's see the logic with the feature enabled.
## Setting Clip Rect
[SetSurfaceClipRect](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=649;drc=e63cbaf6fdcfdac0f04883d956b00e83330bd0a2), which is called on computing surface draw properties, will set the clip rect to render surface.
If RenderSurface is not clipped, gfx::Rect() is set as a clip rect.
If not, for the root surface, it sets clip of the ClipNode corresponding to the effect tree index.
For else, it [ComputeAccumulatedClip](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=230;drc=3caf2592a8080d7a4949467119361062b61819eb) from common ancestor clip di and the target node.
[`target_id`](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/effect_node.h;l=164;drc=3caf2592a8080d7a4949467119361062b61819eb) is set inside [UpdateRenderTarget](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=835-845;drc=3caf2592a8080d7a4949467119361062b61819eb).
```cpp=
if (i == kContentsRootPropertyNodeId) {
// Render target of the node corresponding to root is itself.
node->target_id = kContentsRootPropertyNodeId;
} else if (effect_tree->parent(node)->HasRenderSurface()) {
node->target_id = node->parent_id;
} else {
node->target_id = effect_tree->parent(node)->target_id;
}
```
For the root surface, target id is just root surface.
For others, target id would be it's parent.
Going back to [ComputeAccumulatedClip](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=230;drc=3caf2592a8080d7a4949467119361062b61819eb).
If clip is cached in [cached_clip_rects](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/clip_node.h;l=58;drc=3caf2592a8080d7a4949467119361062b61819eb), it sets `cached_clip.clip_rect` as accumulated clip.
TODO(elkurin): Check caching logic.
If not, we need to calculate the accumulated clip from [ComputeCurrentClip](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=147;drc=3caf2592a8080d7a4949467119361062b61819eb).
The following is the rough logic:
```cpp=
if (clip_node->transform_id != target_transform_id) {
return ComputeLocalRectInTargetSpace(...);
}
if (surface_contents_scale.x() > 0 && surface_contents_scale.y() > 0 &&
clip_node->transform_id != kRootPropertyNodeId) {
current_clip.Scale(surface_contents_scale.x(), surface_contents_scale.y());
}
return ConditionalClip{true /* is_clipped */, current_clip};
```
If `transform_id` and `target_transform_id` is different, it [ComputeLocalRectInTargetSpace](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=126;drc=3caf2592a8080d7a4949467119361062b61819eb).
If they are the same, we apply to transform effect, but not for viewport node which is represented as `kRootPropertyNodeId`.
[ComputeLocalRectInTargetSpace](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=126;drc=3caf2592a8080d7a4949467119361062b61819eb) will get the transform to the target using [PropertyTrees::GetToTarget](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/property_tree.cc;l=2396;drc=3caf2592a8080d7a4949467119361062b61819eb) and then scale with
- [MapClipRect](https://source.chromium.org/chromium/chromium/src/+/main:cc/base/math_util.cc;l=281;drc=3caf2592a8080d7a4949467119361062b61819eb)
- [ProjectClippedRect](https://source.chromium.org/chromium/chromium/src/+/main:cc/base/math_util.cc;l=314;drc=3caf2592a8080d7a4949467119361062b61819eb)
Both metohods are in MathUtil library and they return the axis-aligned rect enclosing the correctly clipped transformed polygon.
## When RenderSurface is clipped
[SetSurfaceIsClipped](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/draw_property_utils.cc;l=568;drc=3caf2592a8080d7a4949467119361062b61819eb) is the one called to set `is_clipped` property.
If root render's effect node is `kContentRootPropertyNodeId` which is 1 equal to Viewport node, `is_clipped` is always true.
TODO(elkurin): maybe we need to change this?
If not, assuming that CommenAncestorClip is enabled, the following logic is used:
```cpp=
int parent_target_clip_id =
render_surface->render_target()->common_ancestor_clip_id();
for (const ClipNode* clip_node =
clip_tree.Node(render_surface->common_ancestor_clip_id());
clip_node && clip_node->id != parent_target_clip_id;
clip_node = clip_tree.parent(clip_node)) {
if (clip_node->AppliesLocalClip()) {
is_clipped = true;
break;
}
}
```
It goes up the parent hierarchy of the clip tree.
It jumps to `common_ancestor_clip_id` as a first step instead of simply following the parent id, and then it goes up by `parent` in clip tree one by one.
[AppliesLocalClip](https://source.chromium.org/chromium/chromium/src/+/main:cc/trees/clip_node.cc;l=26;drc=3caf2592a8080d7a4949467119361062b61819eb) returns true if the id is valid, so the above logic is equal to whether there is a meaningful clip above common ancestor clip.
## Note
Looking at codes, ClipTree hierarchy and EffectTree hierarhcy seems to be independent. Changing ClipTree hierarchy won't break the cahin of transform.