diff --git a/webf/lib/src/css/transform.dart b/webf/lib/src/css/transform.dart index bf1bfc0739..2937d23780 100644 --- a/webf/lib/src/css/transform.dart +++ b/webf/lib/src/css/transform.dart @@ -6,6 +6,7 @@ import 'package:flutter/rendering.dart'; import 'package:webf/css.dart'; import 'package:webf/rendering.dart'; +import 'package:vector_math/vector_math_64.dart' show Vector3; const Offset _DEFAULT_TRANSFORM_OFFSET = Offset.zero; const Alignment _DEFAULT_TRANSFORM_ALIGNMENT = Alignment.center; @@ -99,8 +100,8 @@ mixin CSSTransformMixin on RenderStyle { Offset? get effectiveTransformOffset { // Make sure it is used after renderBoxModel been created. assert(renderBoxModel != null); - Offset? offset = MatrixUtils.getAsTranslation(effectiveTransformMatrix); - return offset; + Vector3 translation = effectiveTransformMatrix.getTranslation(); + return Offset(translation[0],translation[1]); } Offset get transformOffset => _transformOffset; diff --git a/webf/lib/src/rendering/box_model.dart b/webf/lib/src/rendering/box_model.dart index 6337ca45f4..ff6c92e201 100644 --- a/webf/lib/src/rendering/box_model.dart +++ b/webf/lib/src/rendering/box_model.dart @@ -15,6 +15,7 @@ import 'package:webf/gesture.dart'; import 'package:webf/webf.dart'; import 'package:webf/rendering.dart'; +import 'box_overflow.dart'; import 'debug_overlay.dart'; // The hashCode of all the renderBox which is in layout. @@ -218,6 +219,45 @@ class RenderLayoutBox extends RenderBoxModel _paintingOrder = null; } + + // iterate add child to overflowLayout + void addOverflowLayoutFromChildren(List children) { + children.forEach((child) { + addOverflowLayoutFromChild(child); + }); + } + + void addOverflowLayoutFromChild(RenderBox child) { + final RenderLayoutParentData childParentData = child.parentData as RenderLayoutParentData; + if (child is RenderTextBox || child is RenderPositionPlaceholder || !child.hasSize || child is RenderConstrainedBox) { + return; + } + CSSRenderStyle style = (child as RenderBoxModel).renderStyle; + Rect overflowRect = Rect.fromLTWH(childParentData.offset.dx, childParentData.offset.dy, child.boxSize!.width, child.boxSize!.height); + + if (style.effectiveTransformOffset != null) { + overflowRect = overflowRect.shift(style.effectiveTransformOffset!); + } + // child overflowLayout effect parent overflowLayout when child effectiveOverflow is visible or auto + if (child.renderStyle.effectiveOverflowX == CSSOverflowType.visible || + child.renderStyle.effectiveOverflowX == CSSOverflowType.auto || + child.renderStyle.effectiveOverflowY == CSSOverflowType.auto || + child.renderStyle.effectiveOverflowY == CSSOverflowType.visible) { + Rect childOverflowLayoutRect = child.overflowRect!.shift(Offset.zero); + + // child overflowLayout rect need transform for parent`s cartesian coordinates + final Matrix4 transform = Matrix4.identity(); + applyLayoutTransform(child, transform, false); + Offset tlOffset = MatrixUtils.transformPoint(transform,Offset(childOverflowLayoutRect.left,childOverflowLayoutRect.top)); + overflowRect = Rect.fromLTRB(math.min(overflowRect.left, tlOffset.dx), + math.min(overflowRect.top, tlOffset.dy), + math.max(overflowRect.right, tlOffset.dx + childOverflowLayoutRect.width), + math.max(overflowRect.bottom,tlOffset.dy + childOverflowLayoutRect.height)); + } + + addLayoutOverflow(overflowRect); + } + // Sort children by zIndex, used for paint and hitTest. List? _paintingOrder; List get paintingOrder { @@ -608,16 +648,17 @@ mixin RenderBoxModelBase on RenderBox { } class RenderBoxModel extends RenderBox - with - RenderBoxModelBase, - RenderBoxDecorationMixin, - RenderTransformMixin, - RenderOverflowMixin, - RenderOpacityMixin, - RenderIntersectionObserverMixin, - RenderContentVisibilityMixin, - RenderEventListenerMixin, - RenderObjectWithControllerMixin { + with + RenderBoxModelBase, + RenderBoxDecorationMixin, + RenderBoxOverflowLayout, + RenderTransformMixin, + RenderOverflowMixin, + RenderOpacityMixin, + RenderIntersectionObserverMixin, + RenderContentVisibilityMixin, + RenderEventListenerMixin, + RenderObjectWithControllerMixin { RenderBoxModel({ required this.renderStyle, }) : super(); @@ -1027,6 +1068,7 @@ class RenderBoxModel extends RenderBox // Deflate padding constraints. contentConstraints = renderStyle.deflatePaddingConstraints(contentConstraints); _contentConstraints = contentConstraints; + clearOverflowLayout(); } /// Find scroll container diff --git a/webf/lib/src/rendering/box_overflow.dart b/webf/lib/src/rendering/box_overflow.dart new file mode 100644 index 0000000000..316a203264 --- /dev/null +++ b/webf/lib/src/rendering/box_overflow.dart @@ -0,0 +1,63 @@ +import 'dart:math'; +import 'dart:ui'; + +import '../../rendering.dart'; + + +/// OverflowLayout is a class for tracking content that spills out of a box +/// This class is used by RenderBox +mixin RenderBoxOverflowLayout on RenderBoxModelBase { + Rect? _layoutOverflowRect; + Rect? _visualOverflowRect; + + void initOverflowLayout(Rect layoutRect, Rect visualRect) { + _layoutOverflowRect = layoutRect; + _visualOverflowRect = visualRect; + } + + Rect? get overflowRect { + return _layoutOverflowRect; + } + + Rect? get visualOverflowRect { + return _visualOverflowRect; + } + + void addLayoutOverflow(Rect rect) { + assert(_layoutOverflowRect != null, 'add overflow rect failed, _layoutOverflowRect not init'); + _layoutOverflowRect = Rect.fromLTRB( + min(_layoutOverflowRect!.left, rect.left), + min(_layoutOverflowRect!.top, rect.top), + max(_layoutOverflowRect!.right, rect.right), + max(_layoutOverflowRect!.bottom, rect.bottom)); + } + + void addVisualOverflow(Rect rect) { + assert(_visualOverflowRect != null, 'add overflow rect failed, _visualOverflowRect not init'); + _visualOverflowRect = Rect.fromLTWH( + min(_visualOverflowRect!.left, rect.left), + min(_visualOverflowRect!.top, rect.top), + max(_visualOverflowRect!.right, rect.right), + max(_visualOverflowRect!.bottom, rect.bottom)); + } + + void moveOverflowLayout(Offset offset) { + assert(_layoutOverflowRect != null, 'add overflow rect failed, _layoutOverflowRect not init'); + _layoutOverflowRect = _layoutOverflowRect!.shift(offset); + assert(_visualOverflowRect != null, 'add overflow rect failed, _visualOverflowRect not init'); + _visualOverflowRect = _visualOverflowRect!.shift(offset); + } + + void setLayoutOverflow(Rect rect) { + _layoutOverflowRect = rect; + } + + void setVisualOverflow(Rect rect) { + _layoutOverflowRect = rect; + } + + void clearOverflowLayout() { + _layoutOverflowRect = null; + _visualOverflowRect = null; + } +} diff --git a/webf/lib/src/rendering/flex.dart b/webf/lib/src/rendering/flex.dart index 348f7e2d74..b1ddf0c14e 100644 --- a/webf/lib/src/rendering/flex.dart +++ b/webf/lib/src/rendering/flex.dart @@ -630,6 +630,12 @@ class RenderFlexLayout extends RenderLayoutBox { // placeholder of positioned element). _layoutFlexItems(_flexItemChildren); + // init overflowLayout size + initOverflowLayout(Rect.fromLTRB(0, 0, size.width, size.height), Rect.fromLTRB(0, 0, size.width, size.height)); + + // calculate all flexItem child overflow size + addOverflowLayoutFromChildren(_flexItemChildren); + // Every placeholder of positioned element should be layouted in a separated layer in flex layout // which is different from the placeholder in flow layout which layout in the same flow as // other elements in normal flow. @@ -642,6 +648,7 @@ class RenderFlexLayout extends RenderLayoutBox { CSSPositionedLayout.applyPositionedChildOffset(this, child); // Position of positioned element affect the scroll size of container. extendMaxScrollableSize(child); + addOverflowLayoutFromChild(child); } // Set offset of sticky element on each layout. @@ -709,6 +716,7 @@ class RenderFlexLayout extends RenderLayoutBox { _setChildrenOffset(_runMetrics); } + // Layout children in normal flow order to calculate metrics of flex lines according to its constraints // and flex-wrap property. List<_RunMetrics> _computeRunMetrics( diff --git a/webf/lib/src/rendering/flow.dart b/webf/lib/src/rendering/flow.dart index 245c0aefe6..da027d3812 100644 --- a/webf/lib/src/rendering/flow.dart +++ b/webf/lib/src/rendering/flow.dart @@ -184,11 +184,19 @@ class RenderFlowLayout extends RenderLayoutBox { // placeholder of positioned element). _layoutChildren(_nonPositionedChildren); + // init overflowLayout size + initOverflowLayout(Rect.fromLTRB(0, 0, size.width, size.height), Rect.fromLTRB(0, 0, size.width, size.height)); + + // calculate all flexItem child overflow size + addOverflowLayoutFromChildren(_nonPositionedChildren); + + // Set offset of positioned element after flex box size is set. for (RenderBoxModel child in _positionedChildren) { CSSPositionedLayout.applyPositionedChildOffset(this, child); // Position of positioned element affect the scroll size of container. extendMaxScrollableSize(child); + addOverflowLayoutFromChild(child); } // Set offset of sticky element on each layout.