Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sliver Optimization #225

Merged
merged 4 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions webf/lib/rendering.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export 'src/rendering/viewport.dart';
export 'src/rendering/paragraph.dart';
export 'src/rendering/line_break.dart';
export 'src/rendering/image.dart';
export 'src/rendering/webf_render_list.dart';
38 changes: 24 additions & 14 deletions webf/lib/src/dom/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -830,25 +830,15 @@ abstract class Element extends Node with ElementBase, ElementEventMixin, Element
}
}

bool _obtainSliverChild() {
if (parentElement?.renderStyle.display == CSSDisplay.sliver) {
// Sliver should not create renderer here, but need to trigger
// render sliver list dynamical rebuild child by element tree.
parentElement?._renderLayoutBox?.markNeedsLayout();
return true;
}
return false;
}

// Attach renderObject of current node to parent
@override
void attachTo(Node parent, {RenderBox? after}) {
applyStyle(style);

if (_obtainSliverChild()) {
// Rebuild all the sliver children.
RenderLayoutBox? parentRenderBoxModel = parentElement!.renderBoxModel as RenderLayoutBox?;
parentRenderBoxModel?.removeAll();
if (parentElement?.renderStyle.display == CSSDisplay.sliver) {
// Sliver should not create renderer here, but need to trigger
// render sliver list dynamical rebuild child by element tree.
parentElement?._renderLayoutBox?.markNeedsLayout();
} else {
willAttachRenderer();
}
Expand Down Expand Up @@ -1003,6 +993,26 @@ abstract class Element extends Node with ElementBase, ElementEventMixin, Element
}
}

// Remove all element after the new node, when parent is sliver
// Sliver's children if change sort need relayout
if(renderStyle.display == CSSDisplay.sliver
&& referenceNode is Element
&& referenceNode.renderer != null
&& referenceNode.isRendererAttached) {
while(referenceIndex + 1 < childNodes.length) {
Node reference = childNodes[referenceIndex + 1];
if(reference.isRendererAttached && reference is Element) {
if(reference.renderer != null &&
reference.renderer!.parent != null &&
reference.renderer!.parent is RenderSliverRepaintProxy) {
(renderer as RenderSliverListLayout).remove(reference.renderer!.parent as RenderSliverRepaintProxy);
}
reference.unmountRenderObject(deep: true);
}
referenceIndex++;
}
}

// Renderer of referenceNode may not moved to a difference place compared to its original place
// in the dom tree due to position absolute/fixed.
// Use the renderPositionPlaceholder to get the same place as dom tree in this case.
Expand Down
34 changes: 33 additions & 1 deletion webf/lib/src/dom/sliver_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ class RenderSliverElementChildManager implements RenderSliverBoxChildManager {
// If renderer is not created, use an empty RenderBox to occupy the position, but not do layout or paint.
RenderBox child = childNode.renderer ?? _createEmptyRenderObject();

if(!child.isRepaintBoundary) {
RenderSliverRepaintProxy? repaintBoundary = _createRepaintRenderObject(child);
child = repaintBoundary;
}

if (_hasLayout) {
_sliverListLayout.insertSliverChild(child, after: after);
}
Expand All @@ -68,6 +73,10 @@ class RenderSliverElementChildManager implements RenderSliverBoxChildManager {
return _RenderSliverItemProxy();
}

RenderSliverRepaintProxy _createRepaintRenderObject(RenderBox? child) {
return RenderSliverRepaintProxy(child);
}

@override
bool debugAssertChildListLocked() => true;

Expand All @@ -79,14 +88,18 @@ class RenderSliverElementChildManager implements RenderSliverBoxChildManager {

@override
void removeChild(RenderBox child) {
if (child is RenderBoxModel) {
if (child is RenderBoxModel || child is RenderSliverRepaintProxy &&
child.parentData is SliverMultiBoxAdaptorParentData) {
SliverMultiBoxAdaptorParentData parentData = child.parentData as SliverMultiBoxAdaptorParentData;
// The index of sliver list.
int index = parentData.index!;

Iterable<Node> renderNodes = _renderNodes;
if (index < renderNodes.length) {
renderNodes.elementAt(index).unmountRenderObject(deep: true, keepFixedAlive: true);
if(child is RenderSliverRepaintProxy && child.parent is ContainerRenderObjectMixin) {
(child.parent as ContainerRenderObjectMixin).remove(child);
}
return;
}
}
Expand Down Expand Up @@ -132,3 +145,22 @@ class RenderSliverElementChildManager implements RenderSliverBoxChildManager {

/// Used for the placeholder for empty sliver item.
class _RenderSliverItemProxy extends RenderProxyBox {}

/// Used for the sliver item which is not RepaintBoundary
class RenderSliverRepaintProxy extends RenderProxyBox {
RenderSliverRepaintProxy(RenderBox? child):super(child);

@override
bool get isRepaintBoundary => true;

@override
void detach() {
super.detach();
if(child != null) {
RenderObject? parentRenderObject = child!.parent as RenderObject?;
if(parentRenderObject is RenderObjectWithChildMixin) {
parentRenderObject.child = null;
}
}
}
}
4 changes: 2 additions & 2 deletions webf/lib/src/rendering/box_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,7 @@ class RenderBoxModel extends RenderBox
// @FIXME: Normally constraints is calculated in getConstraints by parent RenderLayoutBox in Kraken,
// except in sliver layout, constraints is calculated by [RenderSliverList] which kraken can not control,
// so it needs to invoke getConstraints here for sliver container's direct child.
if (parent is RenderSliverList) {
if (parent is RenderSliverRepaintProxy || parent is RenderSliverList) {
contentConstraints = getConstraints();
} else {
// Constraints is already calculated in parent layout.
Expand Down Expand Up @@ -1198,7 +1198,7 @@ class RenderBoxModel extends RenderBox
));
}

// Reaint native EngineLayer sources with LayerHandle.
// Repaint native EngineLayer sources with LayerHandle.
final LayerHandle<ColorFilterLayer> _colorFilterLayer = LayerHandle<ColorFilterLayer>();

void paintColorFilter(PaintingContext context, Offset offset, PaintingContextCallback callback) {
Expand Down
8 changes: 4 additions & 4 deletions webf/lib/src/rendering/sliver_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class RenderSliverListLayout extends RenderLayoutBox {
late RenderViewport _renderViewport;

// The sliver list render object reference.
RenderSliverList? _renderSliverList;
WebFRenderSliverList? _renderSliverList;

// The scrollable context to handle gestures.
late WebFScrollable scrollable;
Expand Down Expand Up @@ -56,7 +56,7 @@ class RenderSliverListLayout extends RenderLayoutBox {
break;
}

RenderSliverList renderSliverList = _renderSliverList = _buildRenderSliverList();
WebFRenderSliverList renderSliverList = _renderSliverList = _buildRenderSliverList();
_renderViewport = RenderViewport(
offset: scrollable.position!,
axisDirection: scrollable.axisDirection,
Expand Down Expand Up @@ -132,8 +132,8 @@ class RenderSliverListLayout extends RenderLayoutBox {
}

@protected
RenderSliverList _buildRenderSliverList() {
return _renderSliverList = RenderSliverList(childManager: _renderSliverBoxChildManager);
WebFRenderSliverList _buildRenderSliverList() {
return _renderSliverList = WebFRenderSliverList(childManager: _renderSliverBoxChildManager);
}

// Trigger sliver list to rebuild children.
Expand Down
Loading