[LBSE] Defer per-element SVG transform-attribute work without style recalc
// Source/WebCore/dom/Document.cpp
+ if (kind == Style::SVGRendererUpdateType::TransformAttributeOnly) {
+ if (CheckedPtr layerRenderer = dynamicDowncast<RenderLayerModelObject>(element.renderer())) {
+ if (RefPtr frameView = view())
+ frameView->layoutContext().addPendingSVGTransformAttributeUpdate(*layerRenderer);
+ }
+ return;
+ }
LBSE(Layout-Based SVG Engine)는 SVG를 특수 케이스로 처리하던 기존 방식 대신, 표준 CSS layout pipeline에 통합하는 방향으로 SVG rendering backend를 재작성한 결과물입니다. SVG 요소는 실제 RenderLayer 객체를 갖기 때문에, transform 변경 사항은 HTML 요소와 동일한 layer compositing 메커니즘을 통해 전파되어야 합니다. 이전에는 SVG transform의 attribute가 변경될 때마다 즉시 repaint/relayout cycle이 발생했습니다.
이 commit은 변경 발생 시마다 동기적으로 호출하던 방식을 LocalFrameViewLayoutContext 위에 구성된 프레임 단위 batched queue로 대체했습니다. flush는 세 단계로 진행됩니다. 먼저 변경 전 repaint rect를 snapshot으로 저장하고, transform을 변경한 뒤, delta repaint를 방출합니다. 한편 RenderSVGContainer와 RenderSVGRoot에 dirty bit가 추가되어 bounding box의 지연 재계산이 가능해졌습니다. 이를 통해 layout 비용을 치르지 않고도 getBBox()가 최신 상태를 유지할 수 있습니다.
Significance
SVG 애니메이션 실행 중 프레임당 2N번 발생하던 동기 repaint() 호출이 제거되었으며, MotionMark/Suits 벤치마크에서 약 10% 성능 향상이 확인되었습니다. 다만 이번 재구성으로 queued renderer 참조, 새로운 flush 순서 불변식, 지연 무효화 경로가 도입되어 복잡도가 증가했습니다.
Audit directions
- Flush-before-re-entrancy-check ordering.
updateLayoutIfDimensionsOutOfDate에서 queue flush는isInRenderTreeLayout()guard보다 먼저 실행됩니다. 상위 frame의 layout이 진행 중인 상태에서도 세 단계 flush가 실행될 수 있습니다. 이때 2단계 중 re-entrant geometry query가 발생하면, 부분적으로 변경된 transform 상태를 관찰하게 될 가능성이 있습니다. - Renderer lifetime vs. queue. queue는
CheckedPtr<RenderLayerModelObject>참조를 보관합니다. rAF 중 DOM 변경 등으로 renderer가 enqueue와 flush 사이에 detach되면CheckedPtr는 null이 되지만, flush 로직이 null 항목을 UB 없이 처리하는지 확인이 필요합니다. detach 시RenderElement의 dirty bit가 정상적으로 초기화되는지도 살펴볼 필요가 있습니다. - Dirty-bit coverage for
getBBox()staleness. 이 queue를 거치지 않고 하위 요소의 transform을 변경하는 경로(style recalc, SMIL engine, 직접 property 변경 등)에서 dirty bit를 설정하지 않으면, JS에 stale bounding box가 조용히 반환됩니다. 마이그레이션되지 않은 기존repaintOrRelayoutAfterSVGTransformChange()호출 지점을 전수 점검할 필요가 있습니다. - Three-phase atomicity. 단계 사이에 JS microtask나 style callback이 실행되면, 3단계의 delta repaint가 잘못된 geometry를 기반으로 계산될 가능성이 있습니다.