From b9ab70545485c6d1445e0fe7d06d43ed4e8a13ee Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Fri, 19 Nov 2021 15:56:22 +0800 Subject: [PATCH 01/17] feat: cache logical content width/height to avoid recursive computation in nested layout --- kraken/lib/src/css/render_style.dart | 132 ++++++++++++++++++++++++ kraken/lib/src/rendering/box_model.dart | 12 ++- 2 files changed, 140 insertions(+), 4 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 05f146f28c..736efdc0e2 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -239,6 +239,79 @@ class RenderStyle } } + double? computeLogicalContentWidth() { + RenderBoxModel current = renderBoxModel!; + RenderStyle renderStyle = this; + double? logicalWidth; + + CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay; + switch (effectiveDisplay) { + case CSSDisplay.block: + case CSSDisplay.flex: + case CSSDisplay.sliver: + // Use width directly if defined. + if (renderStyle.width.isNotAuto) { + logicalWidth = renderStyle.width.computedValue; + + // Use tight constraints if constraints is tight and width not exist. + } else if (current.hasSize && current.constraints.hasTightWidth) { + logicalWidth = current.constraints.maxWidth; + + // Block element (except replaced element) will stretch to the content width of its parent. + } else if (current is! RenderIntrinsic && + current.parent != null && + current.parent is RenderBoxModel + ) { + RenderBoxModel parent = current.parent as RenderBoxModel; + logicalWidth = parent.logicalContentWidth; + } + break; + case CSSDisplay.inlineBlock: + case CSSDisplay.inlineFlex: + if (renderStyle.width.isNotAuto) { + logicalWidth = renderStyle.width.computedValue; + } else if (current.hasSize && current.constraints.hasTightWidth) { + logicalWidth = current.constraints.maxWidth; + } + break; + case CSSDisplay.inline: + break; + default: + break; + } + + double? intrinsicRatio = current.intrinsicRatio; + + // Get width by intrinsic ratio for replaced element if width is auto. + if (logicalWidth == null && intrinsicRatio != null) { + logicalWidth = renderStyle.getWidthByIntrinsicRatio(); + } + + // Constrain width by min-width and max-width. + if (renderStyle.minWidth.isNotAuto) { + double minWidth = renderStyle.minWidth.computedValue; + if (logicalWidth != null && logicalWidth < minWidth) { + logicalWidth = minWidth; + } + } + if (renderStyle.maxWidth.isNotNone) { + double maxWidth = renderStyle.maxWidth.computedValue; + if (logicalWidth != null && logicalWidth > maxWidth) { + logicalWidth = maxWidth; + } + } + + double? logicalContentWidth; + // Subtract padding and border width to get content width. + if (logicalWidth != null) { + logicalContentWidth = logicalWidth - + renderStyle.border.horizontal - + renderStyle.padding.horizontal; + } + + return logicalContentWidth; + } + // Content width of render box model calculated from style. double? getLogicalContentWidth() { RenderStyle renderStyle = this; @@ -340,6 +413,65 @@ class RenderStyle } } + double? computeLogicalContentHeight() { + RenderBoxModel current = renderBoxModel!; + RenderStyle renderStyle = this; + double? logicalHeight; + + CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay; + + // Inline element has no height. + if (effectiveDisplay != CSSDisplay.inline) { + if (renderStyle.height.isNotAuto) { + logicalHeight = renderStyle.height.computedValue; + + // Use tight constraints if constraints is tight and height not exist. + } else if (current.hasSize && current.constraints.hasTightHeight) { + logicalHeight = current.constraints.maxHeight; + + } else { + if (current.parent != null && current.parent is RenderBoxModel) { + RenderBoxModel parent = current.parent as RenderBoxModel; + RenderStyle parentRenderStyle = parent.renderStyle; + if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { + logicalHeight = parent.logicalContentHeight; + } + } + } + } + + double? intrinsicRatio = current.intrinsicRatio; + + // Get height by intrinsic ratio for replaced element if height is auto. + if (logicalHeight == null && intrinsicRatio != null) { + logicalHeight = renderStyle.getHeightByIntrinsicRatio(); + } + + // Constrain height by min-height and max-height. + if (renderStyle.minHeight.isNotAuto) { + double minHeight = renderStyle.minHeight.computedValue; + if (logicalHeight != null && logicalHeight < minHeight) { + logicalHeight = minHeight; + } + } + if (renderStyle.maxHeight.isNotNone) { + double maxHeight = renderStyle.maxHeight.computedValue; + if (logicalHeight != null && logicalHeight > maxHeight) { + logicalHeight = maxHeight; + } + } + + double? logicalContentHeight; + // Subtract padding and border width to get content width. + if (logicalHeight != null) { + logicalContentHeight = logicalHeight - + renderStyle.border.horizontal - + renderStyle.padding.horizontal; + } + + return logicalContentHeight; + } + // Content height of render box model calculated from style. double? getLogicalContentHeight() { RenderStyle renderStyle = this; diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index c332f43021..88619c27a6 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -873,8 +873,10 @@ class RenderBoxModel extends RenderBox double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; // Content size calculated from style - logicalContentWidth = renderStyle.getLogicalContentWidth(); - logicalContentHeight = renderStyle.getLogicalContentHeight(); + logicalContentWidth = renderStyle.computeLogicalContentWidth(); +// logicalContentWidth = renderStyle.getLogicalContentWidth(); + logicalContentHeight = renderStyle.computeLogicalContentHeight(); +// logicalContentHeight = renderStyle.getLogicalContentHeight(); // Box size calculated from style double? logicalWidth = logicalContentWidth != null @@ -1027,8 +1029,10 @@ class RenderBoxModel extends RenderBox // Deflate padding constraints. boxConstraints = renderStyle.deflatePaddingConstraints(boxConstraints); - logicalContentWidth = renderStyle.getLogicalContentWidth(); - logicalContentHeight = renderStyle.getLogicalContentHeight(); +// logicalContentWidth = renderStyle.getLogicalContentWidth(); + logicalContentWidth = renderStyle.computeLogicalContentWidth(); +// logicalContentHeight = renderStyle.getLogicalContentHeight(); + logicalContentHeight = renderStyle.computeLogicalContentHeight(); if (!isScrollingContentBox && (logicalContentWidth != null || logicalContentHeight != null)) { double minWidth; From 67d27e50702c482488b6c41980108c2e008c6e22 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Fri, 19 Nov 2021 20:04:47 +0800 Subject: [PATCH 02/17] fix: content width/height should not be negative --- kraken/lib/src/css/render_style.dart | 10 ++++++++-- kraken/lib/src/rendering/box_model.dart | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 736efdc0e2..10bc02ebff 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -307,6 +307,9 @@ class RenderStyle logicalContentWidth = logicalWidth - renderStyle.border.horizontal - renderStyle.padding.horizontal; + // Logical width may be smaller than its border and padding width, + // in this case, content width will be negative which is illegal. + logicalContentWidth = math.max(0, logicalContentWidth); } return logicalContentWidth; @@ -465,8 +468,11 @@ class RenderStyle // Subtract padding and border width to get content width. if (logicalHeight != null) { logicalContentHeight = logicalHeight - - renderStyle.border.horizontal - - renderStyle.padding.horizontal; + renderStyle.border.vertical - + renderStyle.padding.vertical; + // Logical height may be smaller than its border and padding width, + // in this case, content height will be negative which is illegal. + logicalContentHeight = math.max(0, logicalContentHeight); } return logicalContentHeight; diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index f13f461f8a..ea387aa740 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -870,10 +870,10 @@ class RenderBoxModel extends RenderBox double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; // Content size calculated from style - logicalContentWidth = renderStyle.computeLogicalContentWidth(); // logicalContentWidth = renderStyle.getLogicalContentWidth(); - logicalContentHeight = renderStyle.computeLogicalContentHeight(); // logicalContentHeight = renderStyle.getLogicalContentHeight(); + logicalContentWidth = renderStyle.computeLogicalContentWidth(); + logicalContentHeight = renderStyle.computeLogicalContentHeight(); // Box size calculated from style double? logicalWidth = logicalContentWidth != null @@ -1027,9 +1027,9 @@ class RenderBoxModel extends RenderBox boxConstraints = renderStyle.deflatePaddingConstraints(boxConstraints); // logicalContentWidth = renderStyle.getLogicalContentWidth(); - logicalContentWidth = renderStyle.computeLogicalContentWidth(); // logicalContentHeight = renderStyle.getLogicalContentHeight(); - logicalContentHeight = renderStyle.computeLogicalContentHeight(); +// logicalContentWidth = renderStyle.computeLogicalContentWidth(); +// logicalContentHeight = renderStyle.computeLogicalContentHeight(); if (!isScrollingContentBox && (logicalContentWidth != null || logicalContentHeight != null)) { double minWidth; From a328f72dd8590833430270f8c5c51b04587f0c5b Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Tue, 23 Nov 2021 11:08:56 +0800 Subject: [PATCH 03/17] fix: margin should be subtracted when calculating logical width/height --- kraken/lib/src/css/render_style.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 10bc02ebff..dc691409f7 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -264,6 +264,10 @@ class RenderStyle ) { RenderBoxModel parent = current.parent as RenderBoxModel; logicalWidth = parent.logicalContentWidth; + // Should subtract horizontal margin of own from its parent content width. + if (logicalWidth != null) { + logicalWidth -= renderStyle.margin.horizontal; + } } break; case CSSDisplay.inlineBlock: @@ -438,6 +442,10 @@ class RenderStyle RenderStyle parentRenderStyle = parent.renderStyle; if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { logicalHeight = parent.logicalContentHeight; + // Should subtract vertical margin of own from its parent content height. + if (logicalHeight != null) { + logicalHeight -= renderStyle.margin.vertical; + } } } } From 3f52aee66e395c28892e6e385f3f8af023d90daa Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Tue, 23 Nov 2021 19:10:44 +0800 Subject: [PATCH 04/17] feat: move logicalContentWidth/height from renderBoxModel to renderStyle --- kraken/lib/src/css/render_style.dart | 17 +++++++---- kraken/lib/src/rendering/box_model.dart | 39 +++++++++++-------------- kraken/lib/src/rendering/flex.dart | 20 +++++++------ kraken/lib/src/rendering/flow.dart | 4 --- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index dc691409f7..0385f66dc1 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -57,6 +57,12 @@ class RenderStyle required this.target, }); + // Content width which is calculated from render style. + double? logicalContentWidth; + + // Content height which is calculated from render style. + double? logicalContentHeight; + dynamic getProperty(String name) { RenderStyle renderStyle = this; switch (name) { @@ -259,11 +265,10 @@ class RenderStyle // Block element (except replaced element) will stretch to the content width of its parent. } else if (current is! RenderIntrinsic && - current.parent != null && - current.parent is RenderBoxModel + renderStyle.parent != null ) { - RenderBoxModel parent = current.parent as RenderBoxModel; - logicalWidth = parent.logicalContentWidth; + RenderStyle parentRenderStyle = renderStyle.parent!; + logicalWidth = parentRenderStyle.logicalContentWidth; // Should subtract horizontal margin of own from its parent content width. if (logicalWidth != null) { logicalWidth -= renderStyle.margin.horizontal; @@ -437,11 +442,11 @@ class RenderStyle logicalHeight = current.constraints.maxHeight; } else { - if (current.parent != null && current.parent is RenderBoxModel) { + if (current.parent != null && renderStyle.parent != null) { RenderBoxModel parent = current.parent as RenderBoxModel; RenderStyle parentRenderStyle = parent.renderStyle; if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { - logicalHeight = parent.logicalContentHeight; + logicalHeight = parentRenderStyle.logicalContentHeight; // Should subtract vertical margin of own from its parent content height. if (logicalHeight != null) { logicalHeight -= renderStyle.margin.vertical; diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index ea387aa740..2970ea4fd4 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -380,8 +380,6 @@ class RenderLayoutBox extends RenderBoxModel /// Common layout size (including flow and flexbox layout) calculation logic Size getLayoutSize({ - double? logicalContentWidth, - double? logicalContentHeight, double? contentWidth, double? contentHeight, }) { @@ -389,8 +387,8 @@ class RenderLayoutBox extends RenderBoxModel double? layoutHeight = contentHeight; // Size which is specified by sizing styles - double? specifiedWidth = logicalContentWidth; - double? specifiedHeight = logicalContentHeight; + double? specifiedWidth = renderStyle.logicalContentWidth; + double? specifiedHeight = renderStyle.logicalContentHeight; // Flex basis takes priority over main size in flex item. if (parent is RenderFlexLayout) { RenderBoxModel? parentRenderBoxModel = parent as RenderBoxModel?; @@ -872,15 +870,15 @@ class RenderBoxModel extends RenderBox // Content size calculated from style // logicalContentWidth = renderStyle.getLogicalContentWidth(); // logicalContentHeight = renderStyle.getLogicalContentHeight(); - logicalContentWidth = renderStyle.computeLogicalContentWidth(); - logicalContentHeight = renderStyle.computeLogicalContentHeight(); + renderStyle.logicalContentWidth = renderStyle.computeLogicalContentWidth(); + renderStyle.logicalContentHeight = renderStyle.computeLogicalContentHeight(); // Box size calculated from style - double? logicalWidth = logicalContentWidth != null - ? logicalContentWidth! + horizontalPaddingLength + horizontalBorderLength + double? logicalWidth = renderStyle.logicalContentWidth != null + ? renderStyle.logicalContentWidth! + horizontalPaddingLength + horizontalBorderLength : null; - double? logicalHeight = logicalContentHeight != null - ? logicalContentHeight! + verticalPaddingLength + verticalBorderLength + double? logicalHeight = renderStyle.logicalContentHeight != null + ? renderStyle.logicalContentHeight! + verticalPaddingLength + verticalBorderLength : null; // Constraints @@ -997,12 +995,6 @@ class RenderBoxModel extends RenderBox Size? _contentSize; Size get contentSize => _contentSize ?? Size.zero; - /// Logical content width calculated from style - double? logicalContentWidth; - - /// Logical content height calculated from style - double? logicalContentHeight; - double get clientWidth { double width = contentSize.width; width += renderStyle.padding.horizontal; @@ -1031,11 +1023,14 @@ class RenderBoxModel extends RenderBox // logicalContentWidth = renderStyle.computeLogicalContentWidth(); // logicalContentHeight = renderStyle.computeLogicalContentHeight(); + double? logicalContentWidth = renderStyle.logicalContentWidth; + double? logicalContentHeight = renderStyle.logicalContentHeight; + if (!isScrollingContentBox && (logicalContentWidth != null || logicalContentHeight != null)) { double minWidth; - double? maxWidth; + double maxWidth; double minHeight; - double? maxHeight; + double maxHeight; if (boxConstraints.hasTightWidth) { minWidth = maxWidth = boxConstraints.maxWidth; @@ -1063,21 +1058,21 @@ class RenderBoxModel extends RenderBox minHeight = minWidth * intrinsicRatio!; } if (!renderStyle.maxWidth.isNone && renderStyle.maxHeight.isNone) { - maxHeight = maxWidth! * intrinsicRatio!; + maxHeight = maxWidth * intrinsicRatio!; } if (renderStyle.minWidth.isAuto && !renderStyle.minHeight.isAuto) { minWidth = minHeight / intrinsicRatio!; } if (renderStyle.maxWidth.isNone && !renderStyle.maxHeight.isNone) { - maxWidth = maxHeight! / intrinsicRatio!; + maxWidth = maxHeight / intrinsicRatio!; } } _contentConstraints = BoxConstraints( minWidth: minWidth, - maxWidth: maxWidth!, + maxWidth: maxWidth, minHeight: minHeight, - maxHeight: maxHeight! + maxHeight: maxHeight ); } else { _contentConstraints = boxConstraints; diff --git a/kraken/lib/src/rendering/flex.dart b/kraken/lib/src/rendering/flex.dart index 1ede6f5b4b..82730202f9 100644 --- a/kraken/lib/src/rendering/flex.dart +++ b/kraken/lib/src/rendering/flex.dart @@ -495,8 +495,9 @@ class RenderFlexLayout extends RenderLayoutBox { : child.intrinsicHeight!; minMainSize = math.min(contentSize, transferredSize); } else if (child is RenderBoxModel) { - double? specifiedMainSize = - _isHorizontalFlexDirection ? child.logicalContentWidth : child.logicalContentHeight; + double? specifiedMainSize = _isHorizontalFlexDirection + ? child.renderStyle.logicalContentWidth + : child.renderStyle.logicalContentHeight; minMainSize = specifiedMainSize != null ? math.min(contentSize, specifiedMainSize) : contentSize; @@ -724,8 +725,6 @@ class RenderFlexLayout extends RenderLayoutBox { /// If no child exists, stop layout. if (childCount == 0) { Size layoutSize = getLayoutSize( - logicalContentWidth: logicalContentWidth, - logicalContentHeight: logicalContentHeight, contentWidth: 0, contentHeight: 0, ); @@ -761,6 +760,9 @@ class RenderFlexLayout extends RenderLayoutBox { containerSizeMap, ); + double? logicalContentWidth = renderStyle.logicalContentWidth; + double? logicalContentHeight = renderStyle.logicalContentHeight; + /// If no non positioned child exists, stop layout if (runMetrics.isEmpty) { Size preferredSize = Size( @@ -1238,6 +1240,8 @@ class RenderFlexLayout extends RenderLayoutBox { Map containerSizeMap, ) { RenderBox? child = placeholderChild ?? firstChild; + double? logicalContentWidth = renderStyle.logicalContentWidth; + double? logicalContentHeight = renderStyle.logicalContentHeight; // Container's width specified by style or inherited from parent double? containerWidth = 0; @@ -1302,7 +1306,7 @@ class RenderFlexLayout extends RenderLayoutBox { // Flexbox with no size on main axis should adapt the main axis size with children. double initialFreeSpace = mainSizeType != BoxSizeType.automatic ? - maxMainSize! - totalSpace : 0; + maxMainSize - totalSpace : 0; bool isFlexGrow = initialFreeSpace > 0 && totalFlexGrow > 0; bool isFlexShrink = initialFreeSpace < 0 && totalFlexShrink > 0; @@ -1344,8 +1348,8 @@ class RenderFlexLayout extends RenderLayoutBox { if (child is RenderBoxModel && child.hasSize) { Size? childSize = _getChildSize(child); - double? childContentWidth = child.logicalContentWidth; - double? childContentHeight = child.logicalContentHeight; + double? childContentWidth = child.renderStyle.logicalContentWidth; + double? childContentHeight = child.renderStyle.logicalContentHeight; double paddingLeft = child.renderStyle.paddingLeft.computedValue; double paddingRight = child.renderStyle.paddingRight.computedValue; double paddingTop = child.renderStyle.paddingTop.computedValue; @@ -1596,8 +1600,6 @@ class RenderFlexLayout extends RenderLayoutBox { ? containerSizeMap['cross'] : maxAllocatedMainSize; Size layoutSize = getLayoutSize( - logicalContentWidth: logicalContentWidth, - logicalContentHeight: logicalContentHeight, contentWidth: contentWidth, contentHeight: contentHeight, ); diff --git a/kraken/lib/src/rendering/flow.dart b/kraken/lib/src/rendering/flow.dart index de277fd1f7..b98cb24b8e 100644 --- a/kraken/lib/src/rendering/flow.dart +++ b/kraken/lib/src/rendering/flow.dart @@ -475,8 +475,6 @@ class RenderFlowLayout extends RenderLayoutBox { // If no child exists, stop layout. if (childCount == 0) { Size layoutSize = getLayoutSize( - logicalContentWidth: logicalContentWidth, - logicalContentHeight: logicalContentHeight, contentWidth: 0, contentHeight: 0, ); @@ -699,8 +697,6 @@ class RenderFlowLayout extends RenderLayoutBox { final int runCount = runMetrics.length; Size layoutSize = getLayoutSize( - logicalContentWidth: logicalContentWidth, - logicalContentHeight: logicalContentHeight, contentWidth: mainAxisExtent, contentHeight: crossAxisExtent, ); From cb2e2a58429fed49425d1cbfe82175ddecb8b537 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Tue, 23 Nov 2021 20:44:11 +0800 Subject: [PATCH 05/17] fix: get parent constraints if width not exist and display is block --- kraken/lib/src/css/render_style.dart | 44 +++++++++++++------------ kraken/lib/src/rendering/box_model.dart | 12 +++---- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 0385f66dc1..2deefcd121 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -258,20 +258,22 @@ class RenderStyle // Use width directly if defined. if (renderStyle.width.isNotAuto) { logicalWidth = renderStyle.width.computedValue; - - // Use tight constraints if constraints is tight and width not exist. - } else if (current.hasSize && current.constraints.hasTightWidth) { - logicalWidth = current.constraints.maxWidth; - - // Block element (except replaced element) will stretch to the content width of its parent. - } else if (current is! RenderIntrinsic && - renderStyle.parent != null - ) { + } else if (renderStyle.parent != null) { RenderStyle parentRenderStyle = renderStyle.parent!; - logicalWidth = parentRenderStyle.logicalContentWidth; - // Should subtract horizontal margin of own from its parent content width. - if (logicalWidth != null) { - logicalWidth -= renderStyle.margin.horizontal; + RenderBoxModel parent = parentRenderStyle.renderBoxModel!; + + // Use parent's tight constraints if constraints is tight and width not exist. + if (parent.hasSize && parent.constraints.hasTightWidth) { + logicalWidth = parent.constraints.maxWidth; + + // Block element (except replaced element) will stretch to the content width of its parent in flow layout. + // Replaced element also stretch in flex layout if align-items is stretch. + } else if (current is! RenderIntrinsic || parent is RenderFlexLayout) { + logicalWidth = parentRenderStyle.logicalContentWidth; + // Should subtract horizontal margin of own from its parent content width. + if (logicalWidth != null) { + logicalWidth -= renderStyle.margin.horizontal; + } } } break; @@ -437,15 +439,15 @@ class RenderStyle if (renderStyle.height.isNotAuto) { logicalHeight = renderStyle.height.computedValue; - // Use tight constraints if constraints is tight and height not exist. - } else if (current.hasSize && current.constraints.hasTightHeight) { - logicalHeight = current.constraints.maxHeight; - } else { - if (current.parent != null && renderStyle.parent != null) { - RenderBoxModel parent = current.parent as RenderBoxModel; - RenderStyle parentRenderStyle = parent.renderStyle; - if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { + if (renderStyle.parent != null) { + RenderStyle parentRenderStyle = renderStyle.parent!; + RenderBoxModel parent = parentRenderStyle.renderBoxModel!; + + // Use parent's tight constraints if constraints is tight and height not exist. + if (parent.hasSize && parent.constraints.hasTightHeight) { + logicalHeight = parent.constraints.maxHeight; + } else if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { logicalHeight = parentRenderStyle.logicalContentHeight; // Should subtract vertical margin of own from its parent content height. if (logicalHeight != null) { diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index 2970ea4fd4..6fdfc7e05f 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -868,8 +868,8 @@ class RenderBoxModel extends RenderBox double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; // Content size calculated from style -// logicalContentWidth = renderStyle.getLogicalContentWidth(); -// logicalContentHeight = renderStyle.getLogicalContentHeight(); +// renderStyle.logicalContentWidth = renderStyle.getLogicalContentWidth(); +// renderStyle.logicalContentHeight = renderStyle.getLogicalContentHeight(); renderStyle.logicalContentWidth = renderStyle.computeLogicalContentWidth(); renderStyle.logicalContentHeight = renderStyle.computeLogicalContentHeight(); @@ -1018,10 +1018,10 @@ class RenderBoxModel extends RenderBox // Deflate padding constraints. boxConstraints = renderStyle.deflatePaddingConstraints(boxConstraints); -// logicalContentWidth = renderStyle.getLogicalContentWidth(); -// logicalContentHeight = renderStyle.getLogicalContentHeight(); -// logicalContentWidth = renderStyle.computeLogicalContentWidth(); -// logicalContentHeight = renderStyle.computeLogicalContentHeight(); +// renderStyle.logicalContentWidth = renderStyle.getLogicalContentWidth(); +// renderStyle.logicalContentHeight = renderStyle.getLogicalContentHeight(); +// renderStyle.logicalContentWidth = renderStyle.computeLogicalContentWidth(); +// renderStyle.logicalContentHeight = renderStyle.computeLogicalContentHeight(); double? logicalContentWidth = renderStyle.logicalContentWidth; double? logicalContentHeight = renderStyle.logicalContentHeight; From 40b8e4a806311c2ecc31064e823f66a5b382f0e0 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 00:16:12 +0800 Subject: [PATCH 06/17] fix: height stretch logic --- kraken/lib/src/css/render_style.dart | 55 +++++++++++++++++++++++----- kraken/lib/src/css/sizing.dart | 30 --------------- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 2deefcd121..53c212099f 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -444,14 +444,16 @@ class RenderStyle RenderStyle parentRenderStyle = renderStyle.parent!; RenderBoxModel parent = parentRenderStyle.renderBoxModel!; - // Use parent's tight constraints if constraints is tight and height not exist. - if (parent.hasSize && parent.constraints.hasTightHeight) { - logicalHeight = parent.constraints.maxHeight; - } else if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, renderStyle)) { - logicalHeight = parentRenderStyle.logicalContentHeight; - // Should subtract vertical margin of own from its parent content height. - if (logicalHeight != null) { - logicalHeight -= renderStyle.margin.vertical; + if (renderStyle.isHeightStretch) { + // Use parent's tight constraints if constraints is tight and height not exist. + if (parent.hasSize && parent.constraints.hasTightHeight) { + logicalHeight = parent.constraints.maxHeight; + } else { + logicalHeight = parentRenderStyle.logicalContentHeight; + // Should subtract vertical margin of own from its parent content height. + if (logicalHeight != null) { + logicalHeight -= renderStyle.margin.vertical; + } } } } @@ -523,7 +525,7 @@ class RenderStyle } RenderBoxModel parentRenderBoxModel = parentRenderStyle!.renderBoxModel!; - if (CSSSizingMixin.isStretchChildHeight(parentRenderStyle, currentRenderStyle)) { + if (currentRenderStyle.isHeightStretch) { if (parentRenderStyle.height.isNotAuto) { height = parentRenderStyle.height.computedValue; cropHeight = _getCropHeightByPaddingBorder(parentRenderStyle, cropHeight); @@ -565,6 +567,41 @@ class RenderStyle } } + // Whether height is stretched to fill its parent's content height. + bool get isHeightStretch { + RenderStyle renderStyle = this; + if (renderStyle.parent == null) { + return false; + } + bool isStretch = false; + RenderStyle parentRenderStyle = renderStyle.parent!; + + bool isParentFlex = parentRenderStyle.display == CSSDisplay.flex || + parentRenderStyle.display == CSSDisplay.inlineFlex; + bool isHorizontalDirection = false; + bool isFlexNoWrap = false; + bool isChildStretchSelf = false; + if (isParentFlex) { + isHorizontalDirection = CSSFlex.isHorizontalFlexDirection(parentRenderStyle.flexDirection); + isFlexNoWrap = parentRenderStyle.flexWrap != FlexWrap.wrap && + parentRenderStyle.flexWrap != FlexWrap.wrapReverse; + isChildStretchSelf = renderStyle.alignSelf != AlignSelf.auto + ? renderStyle.alignSelf == AlignSelf.stretch + : parentRenderStyle.effectiveAlignItems == AlignItems.stretch; + } + + CSSLengthValue marginTop = renderStyle.marginTop; + CSSLengthValue marginBottom = renderStyle.marginBottom; + + // Display as block if flex vertical layout children and stretch children + if (marginTop.isNotAuto && marginBottom.isNotAuto && + isParentFlex && isHorizontalDirection && isFlexNoWrap && isChildStretchSelf) { + isStretch = true; + } + + return isStretch; + } + // Max constraints width of content, used in calculating the remaining space for line wrapping // in the stage of layout. double get contentMaxConstraintsWidth { diff --git a/kraken/lib/src/css/sizing.dart b/kraken/lib/src/css/sizing.dart index 42b8de38ab..0ecd8f2b08 100644 --- a/kraken/lib/src/css/sizing.dart +++ b/kraken/lib/src/css/sizing.dart @@ -136,34 +136,4 @@ mixin CSSSizingMixin on RenderStyleBase { } } - // Whether current node should stretch children's height - static bool isStretchChildHeight(RenderStyle renderStyle, RenderStyle childRenderStyle) { - bool isStretch = false; - bool isFlex = renderStyle.renderBoxModel is RenderFlexLayout; - bool isHorizontalDirection = false; - bool isAlignItemsStretch = false; - bool isFlexNoWrap = false; - bool isChildAlignSelfStretch = false; - bool isChildStretchSelf = false; - if (isFlex) { - isHorizontalDirection = CSSFlex.isHorizontalFlexDirection(renderStyle.flexDirection); - isAlignItemsStretch = renderStyle.effectiveAlignItems == AlignItems.stretch; - isFlexNoWrap = renderStyle.flexWrap != FlexWrap.wrap && - childRenderStyle.flexWrap != FlexWrap.wrapReverse; - isChildAlignSelfStretch = childRenderStyle.alignSelf == AlignSelf.stretch; - isChildStretchSelf = childRenderStyle.alignSelf != AlignSelf.auto ? - isChildAlignSelfStretch : isAlignItemsStretch; - } - - CSSLengthValue marginTop = childRenderStyle.marginTop; - CSSLengthValue marginBottom = childRenderStyle.marginBottom; - - // Display as block if flex vertical layout children and stretch children - if (!marginTop.isAuto && !marginBottom.isAuto && - isFlex && isHorizontalDirection && isFlexNoWrap && isChildStretchSelf) { - isStretch = true; - } - - return isStretch; - } } From 341b3b70217f2e63806e92a49970ba3c3e7c98c1 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 00:59:16 +0800 Subject: [PATCH 07/17] fix: isNotAuto --- kraken/lib/src/css/values/length.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kraken/lib/src/css/values/length.dart b/kraken/lib/src/css/values/length.dart index 14bcacc90d..91279d191b 100644 --- a/kraken/lib/src/css/values/length.dart +++ b/kraken/lib/src/css/values/length.dart @@ -335,7 +335,7 @@ class CSSLengthValue { } bool get isNotAuto { - return type != CSSLengthType.AUTO; + return !isAuto; } bool get isNone { From ba9113ef42fa1ae423a9610ce221a58b49603f3f Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 01:30:10 +0800 Subject: [PATCH 08/17] fix: should ignore renderStyle of display inline when searching for ancestors to stretch width. --- kraken/lib/src/css/render_style.dart | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 53c212099f..8cddc47fe3 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -245,6 +245,19 @@ class RenderStyle } } + // Find ancestor render style with display of not inline. + RenderStyle? _findAncestoreWithNoDisplayInline() { + RenderStyle renderStyle = this; + RenderStyle? parentRenderStyle = renderStyle.parent; + while(parentRenderStyle != null) { + if (parentRenderStyle.effectiveDisplay != CSSDisplay.inline) { + break; + } + parentRenderStyle = parentRenderStyle.parent; + } + return parentRenderStyle; + } + double? computeLogicalContentWidth() { RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; @@ -269,10 +282,14 @@ class RenderStyle // Block element (except replaced element) will stretch to the content width of its parent in flow layout. // Replaced element also stretch in flex layout if align-items is stretch. } else if (current is! RenderIntrinsic || parent is RenderFlexLayout) { - logicalWidth = parentRenderStyle.logicalContentWidth; - // Should subtract horizontal margin of own from its parent content width. - if (logicalWidth != null) { - logicalWidth -= renderStyle.margin.horizontal; + RenderStyle? targetParentRenderStyle = _findAncestoreWithNoDisplayInline(); + // Should ignore renderStyle of display inline when searching for ancestors to stretch width. + if (targetParentRenderStyle != null) { + logicalWidth = targetParentRenderStyle.logicalContentWidth; + // Should subtract horizontal margin of own from its parent content width. + if (logicalWidth != null) { + logicalWidth -= renderStyle.margin.horizontal; + } } } } From ab7103877b48f070327ea5f20fa4c73ce7d33af6 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 15:16:07 +0800 Subject: [PATCH 09/17] refactor: unify logical content size to contentBoxLogicalWidth & contentBoxLogicalHeight --- .../specs/css/css-sizing/min-height.ts | 2 +- .../specs/css/css-sizing/min-width.ts | 2 +- kraken/lib/src/css/render_style.dart | 61 +++++----- kraken/lib/src/rendering/box_model.dart | 115 ++++-------------- kraken/lib/src/rendering/flex.dart | 32 ++--- 5 files changed, 69 insertions(+), 143 deletions(-) diff --git a/integration_tests/specs/css/css-sizing/min-height.ts b/integration_tests/specs/css/css-sizing/min-height.ts index 6f92059aeb..2c7d5a3462 100644 --- a/integration_tests/specs/css/css-sizing/min-height.ts +++ b/integration_tests/specs/css/css-sizing/min-height.ts @@ -28,7 +28,7 @@ describe('min-height', () => { await snapshot(); }); - fit("should work with padding exist and height not exist", async () => { + it("should work with padding exist and height not exist", async () => { let containingBlock = createElement('div', { style: { border: '2px solid #000', diff --git a/integration_tests/specs/css/css-sizing/min-width.ts b/integration_tests/specs/css/css-sizing/min-width.ts index 47855af044..c5fd9ac2a4 100644 --- a/integration_tests/specs/css/css-sizing/min-width.ts +++ b/integration_tests/specs/css/css-sizing/min-width.ts @@ -28,7 +28,7 @@ describe('min-width', () => { await snapshot(); }); - fit("should work with padding exist and width not exist", async () => { + it("should work with padding exist and width not exist", async () => { let containingBlock = createElement('div', { style: { border: '2px solid #000', diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 8cddc47fe3..b7e3170f42 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -57,12 +57,6 @@ class RenderStyle required this.target, }); - // Content width which is calculated from render style. - double? logicalContentWidth; - - // Content height which is calculated from render style. - double? logicalContentHeight; - dynamic getProperty(String name) { RenderStyle renderStyle = this; switch (name) { @@ -258,7 +252,7 @@ class RenderStyle return parentRenderStyle; } - double? computeLogicalContentWidth() { + void computeContentBoxLogicalWidth() { RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; double? logicalWidth; @@ -285,7 +279,7 @@ class RenderStyle RenderStyle? targetParentRenderStyle = _findAncestoreWithNoDisplayInline(); // Should ignore renderStyle of display inline when searching for ancestors to stretch width. if (targetParentRenderStyle != null) { - logicalWidth = targetParentRenderStyle.logicalContentWidth; + logicalWidth = targetParentRenderStyle.contentBoxLogicalWidth; // Should subtract horizontal margin of own from its parent content width. if (logicalWidth != null) { logicalWidth -= renderStyle.margin.horizontal; @@ -340,7 +334,7 @@ class RenderStyle logicalContentWidth = math.max(0, logicalContentWidth); } - return logicalContentWidth; + _contentBoxLogicalWidth = logicalContentWidth; } // Content width of render box model calculated from style. @@ -444,7 +438,7 @@ class RenderStyle } } - double? computeLogicalContentHeight() { + void computeContentBoxLogicalHeight() { RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; double? logicalHeight; @@ -466,7 +460,7 @@ class RenderStyle if (parent.hasSize && parent.constraints.hasTightHeight) { logicalHeight = parent.constraints.maxHeight; } else { - logicalHeight = parentRenderStyle.logicalContentHeight; + logicalHeight = parentRenderStyle.contentBoxLogicalHeight; // Should subtract vertical margin of own from its parent content height. if (logicalHeight != null) { logicalHeight -= renderStyle.margin.vertical; @@ -476,7 +470,6 @@ class RenderStyle } } } - double? intrinsicRatio = current.intrinsicRatio; // Get height by intrinsic ratio for replaced element if height is auto. @@ -509,7 +502,7 @@ class RenderStyle logicalContentHeight = math.max(0, logicalContentHeight); } - return logicalContentHeight; + _contentBoxLogicalHeight = logicalContentHeight; } // Content height of render box model calculated from style. @@ -692,34 +685,36 @@ class RenderStyle // Content width calculated from renderStyle tree. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - // @TODO: add cache to avoid recalculate every time. + double? _contentBoxLogicalWidth; double? get contentBoxLogicalWidth { // If renderBox has tight width, its logical size equals max size. - if (renderBoxModel != null && - renderBoxModel!.hasSize && - renderBoxModel!.constraints.hasTightWidth - ) { - return renderBoxModel!.constraints.maxWidth - - effectiveBorderLeftWidth.computedValue - effectiveBorderRightWidth.computedValue - - paddingLeft.computedValue - paddingRight.computedValue; - } - return getLogicalContentWidth(); +// if (renderBoxModel != null && +// renderBoxModel!.hasSize && +// renderBoxModel!.constraints.hasTightWidth +// ) { +// return renderBoxModel!.constraints.maxWidth - +// effectiveBorderLeftWidth.computedValue - effectiveBorderRightWidth.computedValue - +// paddingLeft.computedValue - paddingRight.computedValue; +// } + return _contentBoxLogicalWidth; +// return getLogicalContentWidth(); } // Content height calculated from renderStyle tree. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - // @TODO: add cache to avoid recalculate every time. + double? _contentBoxLogicalHeight; double? get contentBoxLogicalHeight { // If renderBox has tight height, its logical size equals max size. - if (renderBoxModel != null && - renderBoxModel!.hasSize && - renderBoxModel!.constraints.hasTightHeight - ) { - return renderBoxModel!.constraints.maxHeight - - effectiveBorderTopWidth.computedValue - effectiveBorderBottomWidth.computedValue - - paddingTop.computedValue - paddingBottom.computedValue; - } - return getLogicalContentHeight(); +// if (renderBoxModel != null && +// renderBoxModel!.hasSize && +// renderBoxModel!.constraints.hasTightHeight +// ) { +// return renderBoxModel!.constraints.maxHeight - +// effectiveBorderTopWidth.computedValue - effectiveBorderBottomWidth.computedValue - +// paddingTop.computedValue - paddingBottom.computedValue; +// } + return _contentBoxLogicalHeight; +// return getLogicalContentHeight(); } // Padding box width calculated from renderStyle tree. diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index c750875a99..79c4966916 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -388,8 +388,8 @@ class RenderLayoutBox extends RenderBoxModel double finalContentHeight = contentHeight; // Size which is specified by sizing styles - double? specifiedContentWidth = renderStyle.logicalContentWidth; - double? specifiedContentHeight = renderStyle.logicalContentHeight; + double? specifiedContentWidth = renderStyle.contentBoxLogicalWidth; + double? specifiedContentHeight = renderStyle.contentBoxLogicalHeight; // Flex basis takes priority over main size in flex item. if (parent is RenderFlexLayout) { RenderBoxModel? parentRenderBoxModel = parent as RenderBoxModel?; @@ -845,7 +845,7 @@ class RenderBoxModel extends RenderBox super.layout(newConstraints, parentUsesSize: parentUsesSize); } - /// Calculate renderBoxModel constraints + // Calculate constraints of renderBoxModel on layout stage. BoxConstraints getConstraints() { // Inner scrolling content box of overflow element inherits constraints from parent // but has indefinite max constraints to allow children overflow @@ -873,44 +873,25 @@ class RenderBoxModel extends RenderBox CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay; bool isDisplayInline = effectiveDisplay == CSSDisplay.inline; - EdgeInsets borderEdge = renderStyle.border; - EdgeInsetsGeometry? padding = renderStyle.padding; - - double horizontalBorderLength = borderEdge.horizontal; - double verticalBorderLength = borderEdge.vertical; - double horizontalPaddingLength = padding.horizontal; - double verticalPaddingLength = padding.vertical; - double? minWidth = renderStyle.minWidth.isAuto ? null : renderStyle.minWidth.computedValue; double? maxWidth = renderStyle.maxWidth.isNone ? null : renderStyle.maxWidth.computedValue; double? minHeight = renderStyle.minHeight.isAuto ? null : renderStyle.minHeight.computedValue; double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; - // Content size calculated from style -// renderStyle.logicalContentWidth = renderStyle.getLogicalContentWidth(); -// renderStyle.logicalContentHeight = renderStyle.getLogicalContentHeight(); - renderStyle.logicalContentWidth = renderStyle.computeLogicalContentWidth(); - renderStyle.logicalContentHeight = renderStyle.computeLogicalContentHeight(); - - // Box size calculated from style - double? logicalWidth = renderStyle.logicalContentWidth != null - ? renderStyle.logicalContentWidth! + horizontalPaddingLength + horizontalBorderLength - : null; - double? logicalHeight = renderStyle.logicalContentHeight != null - ? renderStyle.logicalContentHeight! + verticalPaddingLength + verticalBorderLength - : null; - - // Constraints + // Need to calculated logic content size on every layout. + renderStyle.computeContentBoxLogicalWidth(); + renderStyle.computeContentBoxLogicalHeight(); + // Width should be not smaller than border and padding in horizontal direction // when box-sizing is border-box which is only supported. double minConstraintWidth = renderStyle.effectiveBorderLeftWidth.computedValue + renderStyle.effectiveBorderRightWidth.computedValue + renderStyle.paddingLeft.computedValue + renderStyle.paddingRight.computedValue; - double maxConstraintWidth = logicalWidth ?? double.infinity; + double maxConstraintWidth = renderStyle.borderBoxLogicalWidth ?? double.infinity; // Height should be not smaller than border and padding in vertical direction // when box-sizing is border-box which is only supported. double minConstraintHeight = renderStyle.effectiveBorderTopWidth.computedValue + renderStyle.effectiveBorderBottomWidth.computedValue + renderStyle.paddingTop.computedValue + renderStyle.paddingBottom.computedValue; - double maxConstraintHeight = logicalHeight ?? double.infinity; + double maxConstraintHeight = renderStyle.borderBoxLogicalHeight ?? double.infinity; if (parent is RenderFlexLayout) { double? flexBasis = renderStyle.flexBasis == CSSLengthValue.auto ? null : renderStyle.flexBasis?.computedValue; @@ -1022,72 +1003,22 @@ class RenderBoxModel extends RenderBox // Base layout methods to compute content constraints before content box layout. // Call this method before content box layout. void beforeLayout() { - BoxConstraints boxConstraints = constraints; - // Deflate border constraints. - boxConstraints = renderStyle.deflateBorderConstraints(boxConstraints); - - // Deflate padding constraints. - boxConstraints = renderStyle.deflatePaddingConstraints(boxConstraints); - -// renderStyle.logicalContentWidth = renderStyle.getLogicalContentWidth(); -// renderStyle.logicalContentHeight = renderStyle.getLogicalContentHeight(); -// renderStyle.logicalContentWidth = renderStyle.computeLogicalContentWidth(); -// renderStyle.logicalContentHeight = renderStyle.computeLogicalContentHeight(); - - double? logicalContentWidth = renderStyle.logicalContentWidth; - double? logicalContentHeight = renderStyle.logicalContentHeight; - - if (!isScrollingContentBox && (logicalContentWidth != null || logicalContentHeight != null)) { - double minWidth; - double maxWidth; - double minHeight; - double maxHeight; - - if (boxConstraints.hasTightWidth) { - minWidth = maxWidth = boxConstraints.maxWidth; - } else if (logicalContentWidth != null) { - minWidth = 0.0; - maxWidth = logicalContentWidth; - } else { - minWidth = boxConstraints.minWidth; - maxWidth = boxConstraints.maxWidth; - } - - if (boxConstraints.hasTightHeight) { - minHeight = maxHeight = boxConstraints.maxHeight; - } else if (logicalContentHeight != null) { - minHeight = 0.0; - maxHeight = logicalContentHeight; - } else { - minHeight = boxConstraints.minHeight; - maxHeight = boxConstraints.maxHeight; - } - - // max and min size of intrinsc element should respect intrinsc ratio of each other - if (intrinsicRatio != null) { - if (!renderStyle.minWidth.isAuto && renderStyle.minHeight.isAuto) { - minHeight = minWidth * intrinsicRatio!; - } - if (!renderStyle.maxWidth.isNone && renderStyle.maxHeight.isNone) { - maxHeight = maxWidth * intrinsicRatio!; - } - if (renderStyle.minWidth.isAuto && !renderStyle.minHeight.isAuto) { - minWidth = minHeight / intrinsicRatio!; - } - if (renderStyle.maxWidth.isNone && !renderStyle.maxHeight.isNone) { - maxWidth = maxHeight / intrinsicRatio!; - } - } - - _contentConstraints = BoxConstraints( - minWidth: minWidth, - maxWidth: maxWidth, - minHeight: minHeight, - maxHeight: maxHeight - ); + BoxConstraints contentConstraints; + // @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) { + contentConstraints = getConstraints(); } else { - _contentConstraints = boxConstraints; + // Constraints is already calculated in parent layout. + contentConstraints = constraints; } + + // Deflate border constraints. + contentConstraints = renderStyle.deflateBorderConstraints(contentConstraints); + // Deflate padding constraints. + contentConstraints = renderStyle.deflatePaddingConstraints(contentConstraints); + _contentConstraints = contentConstraints; } /// Find scroll container diff --git a/kraken/lib/src/rendering/flex.dart b/kraken/lib/src/rendering/flex.dart index 43eb35b577..d120eacd11 100644 --- a/kraken/lib/src/rendering/flex.dart +++ b/kraken/lib/src/rendering/flex.dart @@ -496,8 +496,8 @@ class RenderFlexLayout extends RenderLayoutBox { minMainSize = math.min(contentSize, transferredSize); } else if (child is RenderBoxModel) { double? specifiedMainSize = _isHorizontalFlexDirection - ? child.renderStyle.logicalContentWidth - : child.renderStyle.logicalContentHeight; + ? child.renderStyle.contentBoxLogicalWidth + : child.renderStyle.contentBoxLogicalHeight; minMainSize = specifiedMainSize != null ? math.min(contentSize, specifiedMainSize) : contentSize; @@ -753,14 +753,14 @@ class RenderFlexLayout extends RenderLayoutBox { containerSizeMap, ); - double? logicalContentWidth = renderStyle.logicalContentWidth; - double? logicalContentHeight = renderStyle.logicalContentHeight; + double? contentBoxLogicalWidth = renderStyle.contentBoxLogicalWidth; + double? contentBoxLogicalHeight = renderStyle.contentBoxLogicalHeight; /// If no non positioned child exists, stop layout if (runMetrics.isEmpty) { Size contentSize = Size( - logicalContentWidth ?? 0, - logicalContentHeight ?? 0, + contentBoxLogicalWidth ?? 0, + contentBoxLogicalHeight ?? 0, ); setMaxScrollableSize(contentSize); size = getBoxSize(contentSize); @@ -770,9 +770,9 @@ class RenderFlexLayout extends RenderLayoutBox { double containerCrossAxisExtent = 0.0; if (!_isHorizontalFlexDirection) { - containerCrossAxisExtent = logicalContentWidth ?? 0; + containerCrossAxisExtent = contentBoxLogicalWidth ?? 0; } else { - containerCrossAxisExtent = logicalContentHeight ?? 0; + containerCrossAxisExtent = contentBoxLogicalHeight ?? 0; } /// Calculate leading and between space between flex lines @@ -1233,21 +1233,21 @@ class RenderFlexLayout extends RenderLayoutBox { Map containerSizeMap, ) { RenderBox? child = placeholderChild ?? firstChild; - double? logicalContentWidth = renderStyle.logicalContentWidth; - double? logicalContentHeight = renderStyle.logicalContentHeight; + double? contentBoxLogicalWidth = renderStyle.contentBoxLogicalWidth; + double? contentBoxLogicalHeight = renderStyle.contentBoxLogicalHeight; // Container's width specified by style or inherited from parent double? containerWidth = 0; - if (logicalContentWidth != null) { - containerWidth = logicalContentWidth; + if (contentBoxLogicalWidth != null) { + containerWidth = contentBoxLogicalWidth; } else if (contentConstraints!.hasTightWidth) { containerWidth = contentConstraints!.maxWidth; } // Container's height specified by style or inherited from parent double? containerHeight = 0; - if (logicalContentHeight != null) { - containerHeight = logicalContentHeight; + if (contentBoxLogicalHeight != null) { + containerHeight = contentBoxLogicalHeight; } else if (contentConstraints!.hasTightHeight) { containerHeight = contentConstraints!.maxHeight; } @@ -1341,8 +1341,8 @@ class RenderFlexLayout extends RenderLayoutBox { if (child is RenderBoxModel && child.hasSize) { Size? childSize = _getChildSize(child); - double? childContentWidth = child.renderStyle.logicalContentWidth; - double? childContentHeight = child.renderStyle.logicalContentHeight; + double? childContentWidth = child.renderStyle.contentBoxLogicalWidth; + double? childContentHeight = child.renderStyle.contentBoxLogicalHeight; double paddingLeft = child.renderStyle.paddingLeft.computedValue; double paddingRight = child.renderStyle.paddingRight.computedValue; double paddingTop = child.renderStyle.paddingTop.computedValue; From 2ee3b2f2164889b5ff99d3b370d0718e5b21c65c Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 15:53:57 +0800 Subject: [PATCH 10/17] fix: logical content size before layout --- kraken/lib/src/css/render_style.dart | 16 ++++++++++++++-- kraken/lib/src/rendering/box_model.dart | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index b7e3170f42..adc0be8ca9 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -685,7 +685,8 @@ class RenderStyle // Content width calculated from renderStyle tree. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - double? _contentBoxLogicalWidth; + // Use double.infinity refers to the value is not computed yet. + double? _contentBoxLogicalWidth = double.infinity; double? get contentBoxLogicalWidth { // If renderBox has tight width, its logical size equals max size. // if (renderBoxModel != null && @@ -696,13 +697,19 @@ class RenderStyle // effectiveBorderLeftWidth.computedValue - effectiveBorderRightWidth.computedValue - // paddingLeft.computedValue - paddingRight.computedValue; // } + // Compute logical width directly if renderBoxModel is not layouted yet, + // eg compute percentage length before layout. + if (_contentBoxLogicalWidth == double.infinity) { + computeContentBoxLogicalWidth(); + } return _contentBoxLogicalWidth; // return getLogicalContentWidth(); } // Content height calculated from renderStyle tree. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - double? _contentBoxLogicalHeight; + // Use double.infinity refers to the value is not computed yet. + double? _contentBoxLogicalHeight = double.infinity; double? get contentBoxLogicalHeight { // If renderBox has tight height, its logical size equals max size. // if (renderBoxModel != null && @@ -713,6 +720,11 @@ class RenderStyle // effectiveBorderTopWidth.computedValue - effectiveBorderBottomWidth.computedValue - // paddingTop.computedValue - paddingBottom.computedValue; // } + // Compute logical height directly if renderBoxModel is not layouted yet, + // eg compute percentage length before layout. + if (_contentBoxLogicalHeight == double.infinity) { + computeContentBoxLogicalHeight(); + } return _contentBoxLogicalHeight; // return getLogicalContentHeight(); } diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index 79c4966916..cbf16090af 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -845,7 +845,8 @@ class RenderBoxModel extends RenderBox super.layout(newConstraints, parentUsesSize: parentUsesSize); } - // Calculate constraints of renderBoxModel on layout stage. + // Calculate constraints of renderBoxModel on layout stage and + // only needed to be excuted once on every layout. BoxConstraints getConstraints() { // Inner scrolling content box of overflow element inherits constraints from parent // but has indefinite max constraints to allow children overflow From adcbf2c3d0c1a3cc9e7ad0532c75681ac6405121 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 17:53:43 +0800 Subject: [PATCH 11/17] fix: percentage width/height resolve --- kraken/lib/src/css/render_style.dart | 262 +++++++------------------- kraken/lib/src/css/values/length.dart | 43 +++-- 2 files changed, 94 insertions(+), 211 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index adc0be8ca9..801bf48ca1 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -252,6 +252,7 @@ class RenderStyle return parentRenderStyle; } + // Compute the content box width from render style. void computeContentBoxLogicalWidth() { RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; @@ -337,107 +338,7 @@ class RenderStyle _contentBoxLogicalWidth = logicalContentWidth; } - // Content width of render box model calculated from style. - double? getLogicalContentWidth() { - RenderStyle renderStyle = this; - double? intrinsicRatio = renderBoxModel!.intrinsicRatio; - CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay; - double? width = renderStyle.width.isAuto ? null : renderStyle.width.computedValue; - double? minWidth = renderStyle.minWidth.isAuto ? null : renderStyle.minWidth.computedValue; - double? maxWidth = renderStyle.maxWidth.isNone ? null : renderStyle.maxWidth.computedValue; - double cropWidth = 0; - - switch (effectiveDisplay) { - case CSSDisplay.block: - case CSSDisplay.flex: - case CSSDisplay.sliver: - // Get own width if exists else get the width of nearest ancestor width width - if (!renderStyle.width.isAuto) { - cropWidth = _getCropWidthByPaddingBorder(renderStyle, cropWidth); - } else { - // @TODO: flexbox stretch alignment will stretch replaced element in the cross axis - // Block level element will spread to its parent's width except for replaced element - if (renderBoxModel is! RenderIntrinsic) { - RenderStyle currentRenderStyle = renderStyle; - - while (true) { - RenderStyle? parentRenderStyle = renderStyle.parent; - - if (parentRenderStyle != null) { - cropWidth += currentRenderStyle.margin.horizontal; - cropWidth = _getCropWidthByPaddingBorder(currentRenderStyle, cropWidth); - parentRenderStyle = currentRenderStyle.parent; - } else { - break; - } - - CSSDisplay? parentEffectiveDisplay = parentRenderStyle!.effectiveDisplay; - RenderBoxModel parentRenderBoxModel = parentRenderStyle.renderBoxModel!; - // Set width of element according to parent display - if (parentEffectiveDisplay != CSSDisplay.inline) { - // Skip to find upper parent - if (parentRenderStyle.width.isNotAuto) { - // Use style width - width = parentRenderStyle.width.computedValue; - cropWidth = _getCropWidthByPaddingBorder(parentRenderStyle, cropWidth); - break; - } else if (parentRenderBoxModel.hasSize && parentRenderBoxModel.constraints.hasTightWidth) { - // Cases like flex item with flex-grow and no width in flex row direction. - width = parentRenderBoxModel.constraints.maxWidth; - cropWidth = _getCropWidthByPaddingBorder(parentRenderStyle, cropWidth); - break; - } else if (parentEffectiveDisplay == CSSDisplay.inlineBlock || - parentEffectiveDisplay == CSSDisplay.inlineFlex || - parentEffectiveDisplay == CSSDisplay.sliver) { - // Collapse width to children - width = null; - break; - } - } - - currentRenderStyle = parentRenderStyle; - } - } - } - break; - case CSSDisplay.inlineBlock: - case CSSDisplay.inlineFlex: - if (renderStyle.width.isNotAuto) { - width = renderStyle.width.computedValue; - cropWidth = _getCropWidthByPaddingBorder(renderStyle, cropWidth); - } else { - width = null; - } - break; - case CSSDisplay.inline: - width = null; - break; - default: - break; - } - // Get height by intrinsic ratio for replaced element if height is not defined - if (width == null && intrinsicRatio != null) { - width = renderStyle.getWidthByIntrinsicRatio() + cropWidth; - } - - if (minWidth != null) { - if (width != null && width < minWidth) { - width = minWidth; - } - } - if (maxWidth != null) { - if (width != null && width > maxWidth) { - width = maxWidth; - } - } - - if (width != null) { - return math.max(0, width - cropWidth); - } else { - return null; - } - } - + // Compute the content box height from render style. void computeContentBoxLogicalHeight() { RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; @@ -505,78 +406,6 @@ class RenderStyle _contentBoxLogicalHeight = logicalContentHeight; } - // Content height of render box model calculated from style. - double? getLogicalContentHeight() { - RenderStyle renderStyle = this; - CSSDisplay? effectiveDisplay = renderStyle.effectiveDisplay; - double? height = renderStyle.height.isAuto ? null : renderStyle.height.computedValue; - double cropHeight = 0; - double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; - double? minHeight = renderStyle.minHeight.isAuto ? null : renderStyle.minHeight.computedValue; - double? intrinsicRatio = renderBoxModel!.intrinsicRatio; - - // Inline element has no height. - if (effectiveDisplay == CSSDisplay.inline) { - return null; - } else if (height != null) { - cropHeight = _getCropHeightByPaddingBorder(renderStyle, cropHeight); - } else { - RenderStyle currentRenderStyle = renderStyle; - - while (true) { - RenderStyle? parentRenderStyle = currentRenderStyle.parent; - - if (parentRenderStyle != null) { - cropHeight += currentRenderStyle.margin.vertical; - cropHeight = _getCropHeightByPaddingBorder(currentRenderStyle, cropHeight); - parentRenderStyle = currentRenderStyle.parent; - } else { - break; - } - - RenderBoxModel parentRenderBoxModel = parentRenderStyle!.renderBoxModel!; - if (currentRenderStyle.isHeightStretch) { - if (parentRenderStyle.height.isNotAuto) { - height = parentRenderStyle.height.computedValue; - cropHeight = _getCropHeightByPaddingBorder(parentRenderStyle, cropHeight); - break; - } else if (parentRenderBoxModel.hasSize && parentRenderBoxModel.constraints.hasTightHeight) { - // Cases like flex item with flex-grow and no height in flex column direction. - height = parentRenderBoxModel.constraints.maxHeight; - cropHeight = _getCropHeightByPaddingBorder(parentRenderStyle, cropHeight); - break; - } - } else { - break; - } - - currentRenderStyle = parentRenderStyle; - } - } - - // Get height by intrinsic ratio for replaced element if height is not defined. - if (height == null && intrinsicRatio != null) { - height = renderStyle.getHeightByIntrinsicRatio() + cropHeight; - } - - if (minHeight != null) { - if (height != null && height < minHeight) { - height = minHeight; - } - } - if (maxHeight != null) { - if (height != null && height > maxHeight) { - height = maxHeight; - } - } - - if (height != null) { - return math.max(0, height - cropHeight); - } else { - return null; - } - } - // Whether height is stretched to fill its parent's content height. bool get isHeightStretch { RenderStyle renderStyle = this; @@ -689,21 +518,12 @@ class RenderStyle double? _contentBoxLogicalWidth = double.infinity; double? get contentBoxLogicalWidth { // If renderBox has tight width, its logical size equals max size. -// if (renderBoxModel != null && -// renderBoxModel!.hasSize && -// renderBoxModel!.constraints.hasTightWidth -// ) { -// return renderBoxModel!.constraints.maxWidth - -// effectiveBorderLeftWidth.computedValue - effectiveBorderRightWidth.computedValue - -// paddingLeft.computedValue - paddingRight.computedValue; -// } - // Compute logical width directly if renderBoxModel is not layouted yet, - // eg compute percentage length before layout. + // Compute logical width directly in case as renderBoxModel is not layouted yet, + // eg. compute percentage length before layout. if (_contentBoxLogicalWidth == double.infinity) { computeContentBoxLogicalWidth(); } return _contentBoxLogicalWidth; -// return getLogicalContentWidth(); } // Content height calculated from renderStyle tree. @@ -711,22 +531,12 @@ class RenderStyle // Use double.infinity refers to the value is not computed yet. double? _contentBoxLogicalHeight = double.infinity; double? get contentBoxLogicalHeight { - // If renderBox has tight height, its logical size equals max size. -// if (renderBoxModel != null && -// renderBoxModel!.hasSize && -// renderBoxModel!.constraints.hasTightHeight -// ) { -// return renderBoxModel!.constraints.maxHeight - -// effectiveBorderTopWidth.computedValue - effectiveBorderBottomWidth.computedValue - -// paddingTop.computedValue - paddingBottom.computedValue; -// } - // Compute logical height directly if renderBoxModel is not layouted yet, - // eg compute percentage length before layout. + // Compute logical height directly in case as renderBoxModel is not layouted yet, + // eg. compute percentage length before layout. if (_contentBoxLogicalHeight == double.infinity) { computeContentBoxLogicalHeight(); } return _contentBoxLogicalHeight; -// return getLogicalContentHeight(); } // Padding box width calculated from renderStyle tree. @@ -819,6 +629,66 @@ class RenderStyle return null; } + // Content box width of renderBoxModel calculated from tight width constraints. + double? get contentBoxConstraintsWidth { + if (paddingBoxConstraintsWidth == null) { + return null; + } + return paddingBoxConstraintsWidth! + - paddingLeft.computedValue + - paddingRight.computedValue; + } + + // Content box height of renderBoxModel calculated from tight height constraints. + double? get contentBoxConstraintsHeight { + if (paddingBoxConstraintsHeight == null) { + return null; + } + return paddingBoxConstraintsHeight! + - paddingTop.computedValue + - paddingBottom.computedValue; + } + + // Padding box width of renderBoxModel calculated from tight width constraints. + double? get paddingBoxConstraintsWidth { + if (borderBoxConstraintsWidth == null) { + return null; + } + return borderBoxConstraintsWidth! + - effectiveBorderLeftWidth.computedValue + - effectiveBorderRightWidth.computedValue; + } + + // Padding box height of renderBoxModel calculated from tight height constraints. + double? get paddingBoxConstraintsHeight { + if (borderBoxConstraintsHeight == null) { + return null; + } + return borderBoxConstraintsHeight! + - effectiveBorderTopWidth.computedValue + - effectiveBorderBottomWidth.computedValue; + } + + // Border box width of renderBoxModel calculated from tight width constraints. + double? get borderBoxConstraintsWidth { + if (renderBoxModel!.hasSize && + renderBoxModel!.constraints.hasTightWidth + ) { + return renderBoxModel!.constraints.maxWidth; + } + return null; + } + + // Border box height of renderBoxModel calculated from tight height constraints. + double? get borderBoxConstraintsHeight { + if (renderBoxModel!.hasSize && + renderBoxModel!.constraints.hasTightHeight + ) { + return renderBoxModel!.constraints.maxHeight; + } + return null; + } + /// Get height of replaced element by intrinsic ratio if height is not defined double getHeightByIntrinsicRatio() { // @TODO: move intrinsic width/height to renderStyle diff --git a/kraken/lib/src/css/values/length.dart b/kraken/lib/src/css/values/length.dart index 91279d191b..c28cb4c846 100644 --- a/kraken/lib/src/css/values/length.dart +++ b/kraken/lib/src/css/values/length.dart @@ -122,14 +122,36 @@ class CSSLengthValue { positionType == CSSPositionType.fixed; RenderStyle? parentRenderStyle = renderStyle!.parent; - - // Percentage relative width priority: logical width > renderer width - double? relativeParentWidth = isPositioned ? - parentRenderStyle?.paddingBoxLogicalWidth ?? parentRenderStyle?.paddingBoxWidth : - parentRenderStyle?.contentBoxLogicalWidth ?? parentRenderStyle?.contentBoxWidth; - RenderBoxModel? renderBoxModel = renderStyle!.renderBoxModel; + // Constraints is calculated before layout, the layouted size is identical to the tight constraints + // if constraints is tight, so it's safe to use the tight constraints as the parent size to resolve + // the child percentage length to save one extra layout to wait for parent layout complete. + + // Percentage relative width priority: tight constraints width > renderer width > logical width + double? parentPaddingBoxWidth = parentRenderStyle?.paddingBoxConstraintsWidth + ?? parentRenderStyle?.paddingBoxWidth + ?? parentRenderStyle?.paddingBoxLogicalWidth; + double? parentContentBoxWidth = parentRenderStyle?.contentBoxConstraintsWidth + ?? parentRenderStyle?.contentBoxWidth + ?? parentRenderStyle?.contentBoxLogicalWidth; + // Percentage relative height priority: tight constraints height > renderer height > logical height + double? parentPaddingBoxHeight = parentRenderStyle?.paddingBoxConstraintsHeight + ?? parentRenderStyle?.paddingBoxHeight + ?? parentRenderStyle?.paddingBoxLogicalHeight; + double? parentContentBoxHeight = parentRenderStyle?.contentBoxConstraintsHeight + ?? parentRenderStyle?.contentBoxHeight + ?? parentRenderStyle?.contentBoxLogicalHeight; + + // Positioned element is positioned relative to the padding box of its containing block + // while the others relative to the content box. + double? relativeParentWidth = isPositioned + ? parentPaddingBoxWidth + : parentContentBoxWidth; + double? relativeParentHeight = isPositioned + ? parentPaddingBoxHeight + : parentContentBoxHeight; + switch (propertyName) { case FONT_SIZE: // Relative to the parent font size. @@ -173,11 +195,6 @@ class CSSLengthValue { // The percentage height of positioned element and flex item resolves against the rendered height // of parent, mark parent as needs relayout if rendered height is not ready yet. if (isPositioned || isGrandParentFlexLayout) { - // Percentage relative height priority: logical height > renderer height - double? relativeParentHeight = isPositioned ? - parentRenderStyle?.paddingBoxLogicalHeight ?? parentRenderStyle?.paddingBoxHeight : - parentRenderStyle?.contentBoxLogicalHeight ?? parentRenderStyle?.contentBoxHeight; - if (relativeParentHeight != null) { _computedValue = value! * relativeParentHeight; } else { @@ -240,8 +257,6 @@ class CSSLengthValue { case TOP: case BOTTOM: // Offset of positioned element starts from the edge of padding box of containing block. - double? parentPaddingBoxHeight = parentRenderStyle?.paddingBoxHeight ?? - parentRenderStyle?.paddingBoxLogicalHeight; if (parentPaddingBoxHeight != null) { _computedValue = value! * parentPaddingBoxHeight; } else { @@ -255,8 +270,6 @@ class CSSLengthValue { case LEFT: case RIGHT: // Offset of positioned element starts from the edge of padding box of containing block. - double? parentPaddingBoxWidth = parentRenderStyle?.paddingBoxWidth ?? - parentRenderStyle?.paddingBoxLogicalWidth; if (parentPaddingBoxWidth != null) { _computedValue = value! * parentPaddingBoxWidth; } else { From e937361d031b136fa9257ac38598b988f67d8bae Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 17:57:04 +0800 Subject: [PATCH 12/17] fix: lint --- kraken/lib/src/css/render_style.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 801bf48ca1..aa5ca7e580 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -735,8 +735,3 @@ double _getCropWidthByPaddingBorder(RenderStyle renderStyle, double cropWidth) { return cropWidth; } -double _getCropHeightByPaddingBorder(RenderStyle renderStyle, double cropHeight) { - cropHeight += renderStyle.border.vertical; - cropHeight += renderStyle.padding.vertical; - return cropHeight; -} From b567bb7163aec8ad0ccbe8796903f88919728019 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 19:04:36 +0800 Subject: [PATCH 13/17] test: add tests for sliver constraints calculation --- .../css/css-display/sliver.ts.68990a0e1.png | Bin 0 -> 2742 bytes .../css/css-display/sliver.ts.68990a0e2.png | Bin 0 -> 2752 bytes .../specs/css/css-display/sliver.ts | 47 ++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 integration_tests/snapshots/css/css-display/sliver.ts.68990a0e1.png create mode 100644 integration_tests/snapshots/css/css-display/sliver.ts.68990a0e2.png diff --git a/integration_tests/snapshots/css/css-display/sliver.ts.68990a0e1.png b/integration_tests/snapshots/css/css-display/sliver.ts.68990a0e1.png new file mode 100644 index 0000000000000000000000000000000000000000..8c6aac0480637234a77dc3925be79fd96c083b24 GIT binary patch literal 2742 zcmeAS@N?(olHy`uVBq!ia0y~yV9a1(U~1rC1Bz^vdbAu!F%}28J29*~C-V}>VJUX< z4B-HR8jh3>1_rJKPZ!6KiaBrZZ0w4C%GCBS|51djNOnJqPvL=6P8$SVgCZhsM9jU` zy}_*a`y<{A)y$TXC=MkdgVX~O9@8JOY;%<{^eH+OssF>q;AmWR*ZN5P?)v<1H}l?_ zJlN?Mzr)tz+}6eH3?FKkcm-51Fa!dr(tl@G|Ie-7@b=`k*Y0N+9~`>uaQ|*u_3gj* z>;Glne$KATlyLi~;PK4cy}9%Aet(}>%&_Cb7tUYy_5X5j``?z6HDzz$wo_s05XxxK zXk-Xnv&y%&~e=z@b>;2}s|9{_peEjzJ z`}I{qQ+~*q9It%X-qJ6hzkXlU)L@1myPvcDIyd)iyZpA<=Ig8Y7{v8t3;%q({p}$8 z?Zxi5_4ntj-&=OYM5Exy!NPO@|2=wm`0e8UZNI@pFS>S zo}ZV$r|^u0#XRGTzT$76&s*>Pdae8a!`b=U`tA4aa=f5)LFPFBx5NKI!BlsaZ!|gK z$x-LFU%n{KP{HR9$@0*gKT5&Mz|oKx4GDOKIGPwn6T@D}4^qRFR@r*GBVJUX< z4B-HR8jh3>1_rJyPZ!6KiaBrZ7FqDUVul?bOfHmfzk9Fj z|M}JH^L~GK>}I%8R(PcFR$21x=ePe=K9OP2v#D+RcYS{S?Qi#U`}<}wA7GUiVuBe5 zH5E$5@_o6vtv=?j0K>e}x|gTK+1D^U5OSAc2xQ_FP`yAWs!?teE-w%gF{hNgD zH$St`|1;sk$H#BKUSD6t#ZdqKj>G+(oB#fJT=w}{=y}Emhn6b$-LJcC_ba3NOUCb~ z)8F=*_swEs?X$2r_w# { await snapshot(); }); + it('should works with height of sliver child changes', async (done) => { + let div; + let div1; + let div2; + div = createElement( + 'div', + { + style: { + display: 'sliver', + width: '200px', + height: '200px', + backgroundColor: 'red' + }, + }, [ + (div1 = createElement('div', { + style: { + positive: 'relative', + width: '200px', + height: '100px', + backgroundColor: 'green' + } + }, [ + createText('1') + ])), + (div2 = createElement('div', { + style: { + positive: 'relative', + width: '200px', + height: '100px', + backgroundColor: 'yellow' + } + }, [ + createText('2') + ])) + ] + ); + BODY.appendChild(div); + + await snapshot(); + + requestAnimationFrame(async () => { + div1.style.height = '50px'; + div2.style.height = '50px'; + await snapshot(); + done(); + }); + }); }); From b3a4735bbe092794068c2342afa4978bc977be3c Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 19:19:11 +0800 Subject: [PATCH 14/17] refactor: move intrinsic width/height/ratio to renderStyle --- kraken/lib/src/css/render_style.dart | 46 +++++++++------- kraken/lib/src/css/sizing.dart | 33 ++++++++++++ kraken/lib/src/dom/elements/img.dart | 8 +-- kraken/lib/src/rendering/box_model.dart | 71 +++---------------------- kraken/lib/src/rendering/flex.dart | 20 +++---- kraken/lib/src/rendering/intrinsic.dart | 9 ++-- 6 files changed, 84 insertions(+), 103 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index aa5ca7e580..3c119abbde 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -303,8 +303,6 @@ class RenderStyle break; } - double? intrinsicRatio = current.intrinsicRatio; - // Get width by intrinsic ratio for replaced element if width is auto. if (logicalWidth == null && intrinsicRatio != null) { logicalWidth = renderStyle.getWidthByIntrinsicRatio(); @@ -371,7 +369,6 @@ class RenderStyle } } } - double? intrinsicRatio = current.intrinsicRatio; // Get height by intrinsic ratio for replaced element if height is auto. if (logicalHeight == null && intrinsicRatio != null) { @@ -545,7 +542,9 @@ class RenderStyle if (contentBoxLogicalWidth == null) { return null; } - return contentBoxLogicalWidth! + paddingLeft.computedValue + paddingRight.computedValue; + return contentBoxLogicalWidth! + + paddingLeft.computedValue + + paddingRight.computedValue; } // Padding box height calculated from renderStyle tree. @@ -554,7 +553,9 @@ class RenderStyle if (contentBoxLogicalHeight == null) { return null; } - return contentBoxLogicalHeight! + paddingTop.computedValue + paddingBottom.computedValue; + return contentBoxLogicalHeight! + + paddingTop.computedValue + + paddingBottom.computedValue; } // Border box width calculated from renderStyle tree. @@ -563,7 +564,9 @@ class RenderStyle if (paddingBoxLogicalWidth == null) { return null; } - return paddingBoxLogicalWidth! + effectiveBorderLeftWidth.computedValue + effectiveBorderRightWidth.computedValue; + return paddingBoxLogicalWidth! + + effectiveBorderLeftWidth.computedValue + + effectiveBorderRightWidth.computedValue; } // Border box height calculated from renderStyle tree. @@ -572,7 +575,9 @@ class RenderStyle if (paddingBoxLogicalHeight == null) { return null; } - return paddingBoxLogicalHeight! + effectiveBorderTopWidth.computedValue + effectiveBorderBottomWidth.computedValue; + return paddingBoxLogicalHeight! + + effectiveBorderTopWidth.computedValue + + effectiveBorderBottomWidth.computedValue; } // Content box width of renderBoxModel after it was rendered. @@ -581,7 +586,9 @@ class RenderStyle if (paddingBoxWidth == null) { return null; } - return paddingBoxWidth! - paddingLeft.computedValue - paddingRight.computedValue; + return paddingBoxWidth! + - paddingLeft.computedValue + - paddingRight.computedValue; } // Content box height of renderBoxModel after it was rendered. @@ -590,7 +597,9 @@ class RenderStyle if (paddingBoxHeight == null) { return null; } - return paddingBoxHeight! - paddingTop.computedValue - paddingBottom.computedValue; + return paddingBoxHeight! + - paddingTop.computedValue + - paddingBottom.computedValue; } // Padding box width of renderBoxModel after it was rendered. @@ -599,7 +608,9 @@ class RenderStyle if (borderBoxWidth == null) { return null; } - return borderBoxWidth! - effectiveBorderLeftWidth.computedValue - effectiveBorderRightWidth.computedValue; + return borderBoxWidth! + - effectiveBorderLeftWidth.computedValue + - effectiveBorderRightWidth.computedValue; } // Padding box height of renderBoxModel after it was rendered. @@ -608,7 +619,9 @@ class RenderStyle if (borderBoxHeight == null) { return null; } - return borderBoxHeight! - effectiveBorderTopWidth.computedValue - effectiveBorderBottomWidth.computedValue; + return borderBoxHeight! + - effectiveBorderTopWidth.computedValue + - effectiveBorderBottomWidth.computedValue; } // Border box width of renderBoxModel after it was rendered. @@ -691,9 +704,6 @@ class RenderStyle /// Get height of replaced element by intrinsic ratio if height is not defined double getHeightByIntrinsicRatio() { - // @TODO: move intrinsic width/height to renderStyle - double? intrinsicWidth = renderBoxModel!.intrinsicWidth; - double intrinsicRatio = renderBoxModel!.intrinsicRatio!; double? realWidth = width.isAuto ? intrinsicWidth : width.computedValue; if (minWidth.isNotAuto && realWidth! < minWidth.computedValue) { realWidth = minWidth.computedValue; @@ -701,16 +711,12 @@ class RenderStyle if (maxWidth.isNotNone && realWidth! > maxWidth.computedValue) { realWidth = maxWidth.computedValue; } - double realHeight = realWidth! * intrinsicRatio; + double realHeight = realWidth! * intrinsicRatio!; return realHeight; } /// Get width of replaced element by intrinsic ratio if width is not defined double getWidthByIntrinsicRatio() { - // @TODO: move intrinsic width/height to renderStyle - double? intrinsicHeight = renderBoxModel!.intrinsicHeight; - double intrinsicRatio = renderBoxModel!.intrinsicRatio!; - double? realHeight = height.isAuto ? intrinsicHeight : height.computedValue; if (!minHeight.isAuto && realHeight! < minHeight.computedValue) { realHeight = minHeight.computedValue; @@ -718,7 +724,7 @@ class RenderStyle if (!maxHeight.isNone && realHeight! > maxHeight.computedValue) { realHeight = maxHeight.computedValue; } - double realWidth = realHeight! / intrinsicRatio; + double realWidth = realHeight! / intrinsicRatio!; return realWidth; } diff --git a/kraken/lib/src/css/sizing.dart b/kraken/lib/src/css/sizing.dart index 0ecd8f2b08..0c6441ec8c 100644 --- a/kraken/lib/src/css/sizing.dart +++ b/kraken/lib/src/css/sizing.dart @@ -125,6 +125,39 @@ mixin CSSSizingMixin on RenderStyleBase { _markSelfAndParentNeedsLayout(); } + // Intrinsic width of replaced element. + double? _intrinsicWidth; + double? get intrinsicWidth { + return _intrinsicWidth; + } + set intrinsicWidth(double? value) { + if (_intrinsicWidth == value) return; + _intrinsicWidth = value; + _markSelfAndParentNeedsLayout(); + } + + // Intrinsic height of replaced element. + double? _intrinsicHeight; + double? get intrinsicHeight { + return _intrinsicHeight; + } + set intrinsicHeight(double? value) { + if (_intrinsicHeight == value) return; + _intrinsicHeight = value; + _markSelfAndParentNeedsLayout(); + } + + // Aspect ratio of replaced element. + double? _intrinsicRatio; + double? get intrinsicRatio { + return _intrinsicRatio; + } + set intrinsicRatio(double? value) { + if (_intrinsicRatio == value) return; + _intrinsicRatio = value; + _markSelfAndParentNeedsLayout(); + } + void _markSelfAndParentNeedsLayout() { if (renderBoxModel == null) return; RenderBoxModel boxModel = renderBoxModel!; diff --git a/kraken/lib/src/dom/elements/img.dart b/kraken/lib/src/dom/elements/img.dart index 55b8ba4010..b936d54ade 100644 --- a/kraken/lib/src/dom/elements/img.dart +++ b/kraken/lib/src/dom/elements/img.dart @@ -259,13 +259,13 @@ class ImageElement extends Element { _renderImage?.width = width; _renderImage?.height = height; - renderBoxModel!.intrinsicWidth = naturalWidth; - renderBoxModel!.intrinsicHeight = naturalHeight; + renderStyle.intrinsicWidth = naturalWidth; + renderStyle.intrinsicHeight = naturalHeight; if (naturalWidth == 0.0 || naturalHeight == 0.0) { - renderBoxModel!.intrinsicRatio = null; + renderStyle.intrinsicRatio = null; } else { - renderBoxModel!.intrinsicRatio = naturalHeight / naturalWidth; + renderStyle.intrinsicRatio = naturalHeight / naturalWidth; } } diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index 06251ab77a..4c82724773 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -626,18 +626,6 @@ class RenderBoxModel extends RenderBox return _contentConstraints; } - /// Used when setting percentage line-height style, it needs to be calculated when node attached - /// where it needs to know the font-size of its own element - bool _shouldLazyCalLineHeight = false; - - bool get shouldLazyCalLineHeight => _shouldLazyCalLineHeight; - - set shouldLazyCalLineHeight(bool value) { - if (_shouldLazyCalLineHeight != value) { - _shouldLazyCalLineHeight = value; - } - } - // When RenderBoxModel is scrolling box, contentConstraints are always equal to BoxConstraints(); bool isScrollingContentBox = false; @@ -733,53 +721,6 @@ class RenderBoxModel extends RenderBox ..parentData = parentData; } - // Boxes which have intrinsic ratio - double? _intrinsicWidth; - - double? get intrinsicWidth { - return _intrinsicWidth; - } - - set intrinsicWidth(double? value) { - if (_intrinsicWidth == value) return; - _intrinsicWidth = value; - _markSelfAndParentNeedsLayout(); - } - - // Boxes which have intrinsic ratio - double? _intrinsicHeight; - - double? get intrinsicHeight { - return _intrinsicHeight; - } - - set intrinsicHeight(double? value) { - if (_intrinsicHeight == value) return; - _intrinsicHeight = value; - _markSelfAndParentNeedsLayout(); - } - - double? _intrinsicRatio; - - double? get intrinsicRatio { - return _intrinsicRatio; - } - - set intrinsicRatio(double? value) { - if (_intrinsicRatio == value) return; - _intrinsicRatio = value; - _markSelfAndParentNeedsLayout(); - } - - // Sizing may affect parent size, mark parent as needsLayout in case - // renderBoxModel has tight constraints which will prevent parent from marking. - void _markSelfAndParentNeedsLayout() { - markNeedsLayout(); - if (parent is RenderBoxModel) { - (parent as RenderBoxModel).markNeedsLayout(); - } - } - /// Whether current box is the root of the document which corresponds to HTML element in dom tree. bool get isDocumentRootBox { // Get the outer box of overflow scroll box @@ -1423,12 +1364,12 @@ class RenderBoxModel extends RenderBox if (renderPositionPlaceholder != null) properties.add( DiagnosticsProperty('renderPositionHolder', renderPositionPlaceholder)); - if (intrinsicWidth != null) - properties.add(DiagnosticsProperty('intrinsicWidth', intrinsicWidth)); - if (intrinsicHeight != null) - properties.add(DiagnosticsProperty('intrinsicHeight', intrinsicHeight)); - if (intrinsicRatio != null) - properties.add(DiagnosticsProperty('intrinsicRatio', intrinsicRatio)); + if (renderStyle.intrinsicWidth != null) + properties.add(DiagnosticsProperty('intrinsicWidth', renderStyle.intrinsicWidth)); + if (renderStyle.intrinsicHeight != null) + properties.add(DiagnosticsProperty('intrinsicHeight', renderStyle.intrinsicHeight)); + if (renderStyle.intrinsicRatio != null) + properties.add(DiagnosticsProperty('intrinsicRatio', renderStyle.intrinsicRatio)); debugBoxDecorationProperties(properties); debugVisibilityProperties(properties); diff --git a/kraken/lib/src/rendering/flex.dart b/kraken/lib/src/rendering/flex.dart index 7d8b8bb348..031bced03d 100644 --- a/kraken/lib/src/rendering/flex.dart +++ b/kraken/lib/src/rendering/flex.dart @@ -493,20 +493,20 @@ class RenderFlexLayout extends RenderLayoutBox { : minHeight; if (child is RenderIntrinsic && - child.intrinsicRatio != null && + childRenderStyle.intrinsicRatio != null && _isHorizontalFlexDirection && childRenderStyle.width.isAuto) { double transferredSize = childRenderStyle.height.isNotAuto - ? childRenderStyle.height.computedValue * child.intrinsicRatio! - : child.intrinsicWidth!; + ? childRenderStyle.height.computedValue * childRenderStyle.intrinsicRatio! + : childRenderStyle.intrinsicWidth!; minMainSize = math.min(contentSize, transferredSize); } else if (child is RenderIntrinsic && - child.intrinsicRatio != null && + childRenderStyle.intrinsicRatio != null && !_isHorizontalFlexDirection && childRenderStyle.height.isAuto) { double transferredSize = childRenderStyle.width.isNotAuto - ? childRenderStyle.width.computedValue / child.intrinsicRatio! - : child.intrinsicHeight!; + ? childRenderStyle.width.computedValue / childRenderStyle.intrinsicRatio! + : childRenderStyle.intrinsicHeight!; minMainSize = math.min(contentSize, transferredSize); } else if (child is RenderBoxModel) { double? specifiedMainSize = _isHorizontalFlexDirection @@ -1528,9 +1528,9 @@ class RenderFlexLayout extends RenderLayoutBox { if (child is RenderIntrinsic && child.renderStyle.width.isAuto && child.renderStyle.minWidth.isAuto && - child.intrinsicRatio != null + child.renderStyle.intrinsicRatio != null ) { - minConstraintWidth = maxConstraintWidth = minConstraintHeight / child.intrinsicRatio!; + minConstraintWidth = maxConstraintWidth = minConstraintHeight / child.renderStyle.intrinsicRatio!; } } else { CSSLengthValue marginLeft = childRenderStyle.marginLeft; @@ -1566,9 +1566,9 @@ class RenderFlexLayout extends RenderLayoutBox { if (child is RenderIntrinsic && child.renderStyle.height.isAuto && child.renderStyle.minHeight.isAuto && - child.intrinsicRatio != null + child.renderStyle.intrinsicRatio != null ) { - minConstraintHeight = maxConstraintHeight = minConstraintWidth * child.intrinsicRatio!; + minConstraintHeight = maxConstraintHeight = minConstraintWidth * child.renderStyle.intrinsicRatio!; } } } diff --git a/kraken/lib/src/rendering/intrinsic.dart b/kraken/lib/src/rendering/intrinsic.dart index 55296f16f6..99d219e32f 100644 --- a/kraken/lib/src/rendering/intrinsic.dart +++ b/kraken/lib/src/rendering/intrinsic.dart @@ -66,6 +66,7 @@ class RenderIntrinsic extends RenderBoxModel double? maxWidth = renderStyle.maxWidth.isNone ? null : renderStyle.maxWidth.computedValue; double? minHeight = renderStyle.minHeight.isAuto ? null : renderStyle.minHeight.computedValue; double? maxHeight = renderStyle.maxHeight.isNone ? null : renderStyle.maxHeight.computedValue; + double? intrinsicRatio = renderStyle.intrinsicRatio; if (child != null) { late DateTime childLayoutStart; @@ -97,7 +98,7 @@ class RenderIntrinsic extends RenderBoxModel // max-height should respect intrinsic ratio with max-width if (intrinsicRatio != null && maxHeight == null) { - constraintHeight = constraintWidth * intrinsicRatio!; + constraintHeight = constraintWidth * intrinsicRatio; } } else if (isInlineLevel && minWidth != null && width == null) { constraintWidth = @@ -105,7 +106,7 @@ class RenderIntrinsic extends RenderBoxModel // max-height should respect intrinsic ratio with max-width if (intrinsicRatio != null && minHeight == null) { - constraintHeight = constraintWidth * intrinsicRatio!; + constraintHeight = constraintWidth * intrinsicRatio; } } @@ -116,7 +117,7 @@ class RenderIntrinsic extends RenderBoxModel // max-width should respect intrinsic ratio with max-height if (intrinsicRatio != null && maxWidth == null) { - constraintWidth = constraintHeight / intrinsicRatio!; + constraintWidth = constraintHeight / intrinsicRatio; } } else if (isInlineLevel && minHeight != null && height == null) { constraintHeight = @@ -124,7 +125,7 @@ class RenderIntrinsic extends RenderBoxModel // max-width should respect intrinsic ratio with max-height if (intrinsicRatio != null && minWidth == null) { - constraintWidth = constraintHeight / intrinsicRatio!; + constraintWidth = constraintHeight / intrinsicRatio; } } From dd36f25a5edca756fa0b420bcd3111845e109c26 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 19:21:34 +0800 Subject: [PATCH 15/17] fix: lint --- kraken/lib/src/css/render_style.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 3c119abbde..04e152cba8 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -338,7 +338,6 @@ class RenderStyle // Compute the content box height from render style. void computeContentBoxLogicalHeight() { - RenderBoxModel current = renderBoxModel!; RenderStyle renderStyle = this; double? logicalHeight; @@ -702,7 +701,7 @@ class RenderStyle return null; } - /// Get height of replaced element by intrinsic ratio if height is not defined + // Get height of replaced element by intrinsic ratio if height is not defined double getHeightByIntrinsicRatio() { double? realWidth = width.isAuto ? intrinsicWidth : width.computedValue; if (minWidth.isNotAuto && realWidth! < minWidth.computedValue) { @@ -715,7 +714,7 @@ class RenderStyle return realHeight; } - /// Get width of replaced element by intrinsic ratio if width is not defined + // Get width of replaced element by intrinsic ratio if width is not defined double getWidthByIntrinsicRatio() { double? realHeight = height.isAuto ? intrinsicHeight : height.computedValue; if (!minHeight.isAuto && realHeight! < minHeight.computedValue) { From 0940c4120b724c3c0152b272a69740d669101ca2 Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Wed, 24 Nov 2021 21:38:14 +0800 Subject: [PATCH 16/17] refactor: content max constraint width calculation logic --- kraken/lib/src/css/render_style.dart | 249 +++++++++++------------- kraken/lib/src/rendering/box_model.dart | 12 +- 2 files changed, 125 insertions(+), 136 deletions(-) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index 04e152cba8..14a1d2e334 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -239,19 +239,6 @@ class RenderStyle } } - // Find ancestor render style with display of not inline. - RenderStyle? _findAncestoreWithNoDisplayInline() { - RenderStyle renderStyle = this; - RenderStyle? parentRenderStyle = renderStyle.parent; - while(parentRenderStyle != null) { - if (parentRenderStyle.effectiveDisplay != CSSDisplay.inline) { - break; - } - parentRenderStyle = parentRenderStyle.parent; - } - return parentRenderStyle; - } - // Compute the content box width from render style. void computeContentBoxLogicalWidth() { RenderBoxModel current = renderBoxModel!; @@ -277,10 +264,10 @@ class RenderStyle // Block element (except replaced element) will stretch to the content width of its parent in flow layout. // Replaced element also stretch in flex layout if align-items is stretch. } else if (current is! RenderIntrinsic || parent is RenderFlexLayout) { - RenderStyle? targetParentRenderStyle = _findAncestoreWithNoDisplayInline(); + RenderStyle? ancestorRenderStyle = _findAncestorWithNoDisplayInline(); // Should ignore renderStyle of display inline when searching for ancestors to stretch width. - if (targetParentRenderStyle != null) { - logicalWidth = targetParentRenderStyle.contentBoxLogicalWidth; + if (ancestorRenderStyle != null) { + logicalWidth = ancestorRenderStyle.contentBoxLogicalWidth; // Should subtract horizontal margin of own from its parent content width. if (logicalWidth != null) { logicalWidth -= renderStyle.margin.horizontal; @@ -437,8 +424,8 @@ class RenderStyle return isStretch; } - // Max constraints width of content, used in calculating the remaining space for line wrapping - // in the stage of layout. + + // Max width to constrain its children, used in deciding the line wrapping timing of layout. double get contentMaxConstraintsWidth { // If renderBoxModel definite content constraints, use it as max constrains width of content. BoxConstraints? contentConstraints = renderBoxModel!.contentConstraints; @@ -446,63 +433,28 @@ class RenderStyle return contentConstraints.maxWidth; } - // If renderBoxModel has no logical content width (eg display is inline-block/inline-flex and - // has no width), find its ancestors with logical width set to calculate the remaining space. double contentMaxConstraintsWidth = double.infinity; - double cropWidth = 0; - - RenderStyle currentRenderStyle = this; - - // Get the nearest width of ancestor with width - while (true) { - RenderStyle? parentRenderStyle = currentRenderStyle.parent; - CSSDisplay? effectiveDisplay = currentRenderStyle.effectiveDisplay; - - // Flex item with flex-shrink 0 and no width/max-width will have infinity constraints - // even if parents have width - if (parentRenderStyle != null && (parentRenderStyle.display == CSSDisplay.flex || - parentRenderStyle.display == CSSDisplay.inlineFlex) - ) { - if (currentRenderStyle.flexShrink == 0 && - currentRenderStyle.width.isAuto && - currentRenderStyle.maxWidth.isNone) { - break; - } - } - - // Get width if width exists and element is not inline - if (effectiveDisplay != CSSDisplay.inline && - (currentRenderStyle.width.isNotAuto || currentRenderStyle.maxWidth.isNotNone)) { - // Get the min width between width and max-width - contentMaxConstraintsWidth = math.min( - (currentRenderStyle.width.isAuto ? null : currentRenderStyle.width.computedValue) ?? double.infinity, - (currentRenderStyle.maxWidth.isNone ? null : currentRenderStyle.maxWidth.computedValue) ?? double.infinity - ); - cropWidth = _getCropWidthByPaddingBorder(currentRenderStyle, cropWidth); - break; - } - - if (parentRenderStyle != null) { - cropWidth += currentRenderStyle.margin.horizontal; - cropWidth = _getCropWidthByPaddingBorder(currentRenderStyle, cropWidth); - currentRenderStyle = parentRenderStyle; - } else { - break; - } - } + RenderStyle renderStyle = this; + double? borderBoxLogicalWidth; + RenderStyle? ancestorRenderStyle = _findAncestorWithContentBoxLogicalWidth(); - if (contentMaxConstraintsWidth != double.infinity) { - contentMaxConstraintsWidth = contentMaxConstraintsWidth - cropWidth; + // If renderBoxModel has no logical width (eg. display is inline-block/inline-flex and + // has no width), the child width is constrained by its closest ancestor who has definite logical content box width. + if (ancestorRenderStyle != null) { + borderBoxLogicalWidth = ancestorRenderStyle.contentBoxLogicalWidth; } - // Set contentMaxConstraintsWidth to 0 when it is negative in the case of - // renderBoxModel's width exceeds its ancestors. - //
- //
- //
- //
- if (contentMaxConstraintsWidth < 0) { - contentMaxConstraintsWidth = 0; + if (borderBoxLogicalWidth != null) { + contentMaxConstraintsWidth = borderBoxLogicalWidth - + renderStyle.border.horizontal - + renderStyle.padding.horizontal; + // Logical width may be smaller than its border and padding width, + // in this case, content width will be negative which is illegal. + //
+ //
+ //
+ //
+ contentMaxConstraintsWidth = math.max(0, contentMaxConstraintsWidth); } return contentMaxConstraintsWidth; @@ -579,26 +531,22 @@ class RenderStyle + effectiveBorderBottomWidth.computedValue; } - // Content box width of renderBoxModel after it was rendered. - // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - double? get contentBoxWidth { - if (paddingBoxWidth == null) { - return null; + // Border box width of renderBoxModel after it was rendered. + // https://www.w3.org/TR/css-box-3/#valdef-box-border-box + double? get borderBoxWidth { + if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { + return renderBoxModel!.boxSize!.width; } - return paddingBoxWidth! - - paddingLeft.computedValue - - paddingRight.computedValue; + return null; } - // Content box height of renderBoxModel after it was rendered. - // https://www.w3.org/TR/css-box-3/#valdef-box-content-box - double? get contentBoxHeight { - if (paddingBoxHeight == null) { - return null; + // Border box height of renderBoxModel after it was rendered. + // https://www.w3.org/TR/css-box-3/#valdef-box-border-box + double? get borderBoxHeight { + if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { + return renderBoxModel!.boxSize!.height; } - return paddingBoxHeight! - - paddingTop.computedValue - - paddingBottom.computedValue; + return null; } // Padding box width of renderBoxModel after it was rendered. @@ -623,44 +571,48 @@ class RenderStyle - effectiveBorderBottomWidth.computedValue; } - // Border box width of renderBoxModel after it was rendered. - // https://www.w3.org/TR/css-box-3/#valdef-box-border-box - double? get borderBoxWidth { - if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { - return renderBoxModel!.boxSize!.width; - } - return null; - } - - // Border box height of renderBoxModel after it was rendered. - // https://www.w3.org/TR/css-box-3/#valdef-box-border-box - double? get borderBoxHeight { - if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { - return renderBoxModel!.boxSize!.height; - } - return null; - } - - // Content box width of renderBoxModel calculated from tight width constraints. - double? get contentBoxConstraintsWidth { - if (paddingBoxConstraintsWidth == null) { + // Content box width of renderBoxModel after it was rendered. + // https://www.w3.org/TR/css-box-3/#valdef-box-content-box + double? get contentBoxWidth { + if (paddingBoxWidth == null) { return null; } - return paddingBoxConstraintsWidth! + return paddingBoxWidth! - paddingLeft.computedValue - paddingRight.computedValue; } - // Content box height of renderBoxModel calculated from tight height constraints. - double? get contentBoxConstraintsHeight { - if (paddingBoxConstraintsHeight == null) { + // Content box height of renderBoxModel after it was rendered. + // https://www.w3.org/TR/css-box-3/#valdef-box-content-box + double? get contentBoxHeight { + if (paddingBoxHeight == null) { return null; } - return paddingBoxConstraintsHeight! + return paddingBoxHeight! - paddingTop.computedValue - paddingBottom.computedValue; } + // Border box width of renderBoxModel calculated from tight width constraints. + double? get borderBoxConstraintsWidth { + if (renderBoxModel!.hasSize && + renderBoxModel!.constraints.hasTightWidth + ) { + return renderBoxModel!.constraints.maxWidth; + } + return null; + } + + // Border box height of renderBoxModel calculated from tight height constraints. + double? get borderBoxConstraintsHeight { + if (renderBoxModel!.hasSize && + renderBoxModel!.constraints.hasTightHeight + ) { + return renderBoxModel!.constraints.maxHeight; + } + return null; + } + // Padding box width of renderBoxModel calculated from tight width constraints. double? get paddingBoxConstraintsWidth { if (borderBoxConstraintsWidth == null) { @@ -681,24 +633,24 @@ class RenderStyle - effectiveBorderBottomWidth.computedValue; } - // Border box width of renderBoxModel calculated from tight width constraints. - double? get borderBoxConstraintsWidth { - if (renderBoxModel!.hasSize && - renderBoxModel!.constraints.hasTightWidth - ) { - return renderBoxModel!.constraints.maxWidth; + // Content box width of renderBoxModel calculated from tight width constraints. + double? get contentBoxConstraintsWidth { + if (paddingBoxConstraintsWidth == null) { + return null; } - return null; + return paddingBoxConstraintsWidth! + - paddingLeft.computedValue + - paddingRight.computedValue; } - // Border box height of renderBoxModel calculated from tight height constraints. - double? get borderBoxConstraintsHeight { - if (renderBoxModel!.hasSize && - renderBoxModel!.constraints.hasTightHeight - ) { - return renderBoxModel!.constraints.maxHeight; + // Content box height of renderBoxModel calculated from tight height constraints. + double? get contentBoxConstraintsHeight { + if (paddingBoxConstraintsHeight == null) { + return null; } - return null; + return paddingBoxConstraintsHeight! + - paddingTop.computedValue + - paddingBottom.computedValue; } // Get height of replaced element by intrinsic ratio if height is not defined @@ -732,11 +684,44 @@ class RenderStyle // Clear reference to it's parent. parent = null; } -} -double _getCropWidthByPaddingBorder(RenderStyle renderStyle, double cropWidth) { - cropWidth += renderStyle.border.horizontal; - cropWidth += renderStyle.padding.horizontal; - return cropWidth; + // Find ancestor render style with display of not inline. + RenderStyle? _findAncestorWithNoDisplayInline() { + RenderStyle renderStyle = this; + RenderStyle? parentRenderStyle = renderStyle.parent; + while(parentRenderStyle != null) { + if (parentRenderStyle.effectiveDisplay != CSSDisplay.inline) { + break; + } + parentRenderStyle = parentRenderStyle.parent; + } + return parentRenderStyle; + } + + // Find ancestor render style with definite content box logical width. + RenderStyle? _findAncestorWithContentBoxLogicalWidth() { + RenderStyle renderStyle = this; + RenderStyle? parentRenderStyle = renderStyle.parent; + + while(parentRenderStyle != null) { + RenderStyle? grandParentRenderStyle = parentRenderStyle.parent; + // Flex item with flex-shrink 0 and no width/max-width will have infinity constraints + // even if parents have width. + if (grandParentRenderStyle != null) { + bool isGrandParentFlex = grandParentRenderStyle.display == CSSDisplay.flex || + grandParentRenderStyle.display == CSSDisplay.inlineFlex; + if (isGrandParentFlex && parentRenderStyle.flexShrink == 0) { + return null; + } + } + + if (parentRenderStyle.contentBoxLogicalWidth != null) { + break; + } + + parentRenderStyle = grandParentRenderStyle; + } + return parentRenderStyle; + } } diff --git a/kraken/lib/src/rendering/box_model.dart b/kraken/lib/src/rendering/box_model.dart index 4c82724773..35c91f639b 100644 --- a/kraken/lib/src/rendering/box_model.dart +++ b/kraken/lib/src/rendering/box_model.dart @@ -834,13 +834,17 @@ class RenderBoxModel extends RenderBox // Width should be not smaller than border and padding in horizontal direction // when box-sizing is border-box which is only supported. - double minConstraintWidth = renderStyle.effectiveBorderLeftWidth.computedValue + renderStyle.effectiveBorderRightWidth.computedValue + - renderStyle.paddingLeft.computedValue + renderStyle.paddingRight.computedValue; + double minConstraintWidth = renderStyle.effectiveBorderLeftWidth.computedValue + + renderStyle.effectiveBorderRightWidth.computedValue + + renderStyle.paddingLeft.computedValue + + renderStyle.paddingRight.computedValue; double maxConstraintWidth = renderStyle.borderBoxLogicalWidth ?? double.infinity; // Height should be not smaller than border and padding in vertical direction // when box-sizing is border-box which is only supported. - double minConstraintHeight = renderStyle.effectiveBorderTopWidth.computedValue + renderStyle.effectiveBorderBottomWidth.computedValue + - renderStyle.paddingTop.computedValue + renderStyle.paddingBottom.computedValue; + double minConstraintHeight = renderStyle.effectiveBorderTopWidth.computedValue + + renderStyle.effectiveBorderBottomWidth.computedValue + + renderStyle.paddingTop.computedValue + + renderStyle.paddingBottom.computedValue; double maxConstraintHeight = renderStyle.borderBoxLogicalHeight ?? double.infinity; if (parent is RenderFlexLayout) { From 6204efc78d20abe4fd588469c59c80d2c650b37f Mon Sep 17 00:00:00 2001 From: "zhanwen.zw" Date: Thu, 2 Dec 2021 16:52:49 +0800 Subject: [PATCH 17/17] fix: lint --- kraken/lib/src/css/render_style.dart | 18 ++++++++++++++++++ kraken/lib/src/css/sizing.dart | 3 +++ 2 files changed, 21 insertions(+) diff --git a/kraken/lib/src/css/render_style.dart b/kraken/lib/src/css/render_style.dart index c2a1c6f259..1a90baffb0 100644 --- a/kraken/lib/src/css/render_style.dart +++ b/kraken/lib/src/css/render_style.dart @@ -93,6 +93,8 @@ abstract class RenderStyle { // BoxModel double? get borderBoxLogicalWidth; double? get borderBoxLogicalHeight; + double? get borderBoxConstraintsWidth; + double? get borderBoxConstraintsHeight; double? get borderBoxWidth; double? get borderBoxHeight; double? get paddingBoxLogicalWidth; @@ -540,6 +542,7 @@ class CSSRenderStyle } // Whether height is stretched to fill its parent's content height. + @override bool get isHeightStretch { RenderStyle renderStyle = this; if (renderStyle.parent == null) { @@ -576,6 +579,7 @@ class CSSRenderStyle // Max width to constrain its children, used in deciding the line wrapping timing of layout. + @override double get contentMaxConstraintsWidth { // If renderBoxModel definite content constraints, use it as max constrains width of content. BoxConstraints? contentConstraints = renderBoxModel!.contentConstraints; @@ -614,6 +618,7 @@ class CSSRenderStyle // https://www.w3.org/TR/css-box-3/#valdef-box-content-box // Use double.infinity refers to the value is not computed yet. double? _contentBoxLogicalWidth = double.infinity; + @override double? get contentBoxLogicalWidth { // If renderBox has tight width, its logical size equals max size. // Compute logical width directly in case as renderBoxModel is not layouted yet, @@ -628,6 +633,7 @@ class CSSRenderStyle // https://www.w3.org/TR/css-box-3/#valdef-box-content-box // Use double.infinity refers to the value is not computed yet. double? _contentBoxLogicalHeight = double.infinity; + @override double? get contentBoxLogicalHeight { // Compute logical height directly in case as renderBoxModel is not layouted yet, // eg. compute percentage length before layout. @@ -687,6 +693,7 @@ class CSSRenderStyle // Border box width of renderBoxModel after it was rendered. // https://www.w3.org/TR/css-box-3/#valdef-box-border-box + @override double? get borderBoxWidth { if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { return renderBoxModel!.boxSize!.width; @@ -696,6 +703,7 @@ class CSSRenderStyle // Border box height of renderBoxModel after it was rendered. // https://www.w3.org/TR/css-box-3/#valdef-box-border-box + @override double? get borderBoxHeight { if (renderBoxModel!.hasSize && renderBoxModel!.boxSize != null) { return renderBoxModel!.boxSize!.height; @@ -729,6 +737,7 @@ class CSSRenderStyle // Content box width of renderBoxModel after it was rendered. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box + @override double? get contentBoxWidth { if (paddingBoxWidth == null) { return null; @@ -740,6 +749,7 @@ class CSSRenderStyle // Content box height of renderBoxModel after it was rendered. // https://www.w3.org/TR/css-box-3/#valdef-box-content-box + @override double? get contentBoxHeight { if (paddingBoxHeight == null) { return null; @@ -750,6 +760,7 @@ class CSSRenderStyle } // Border box width of renderBoxModel calculated from tight width constraints. + @override double? get borderBoxConstraintsWidth { if (renderBoxModel!.hasSize && renderBoxModel!.constraints.hasTightWidth @@ -760,6 +771,7 @@ class CSSRenderStyle } // Border box height of renderBoxModel calculated from tight height constraints. + @override double? get borderBoxConstraintsHeight { if (renderBoxModel!.hasSize && renderBoxModel!.constraints.hasTightHeight @@ -770,6 +782,7 @@ class CSSRenderStyle } // Padding box width of renderBoxModel calculated from tight width constraints. + @override double? get paddingBoxConstraintsWidth { if (borderBoxConstraintsWidth == null) { return null; @@ -780,6 +793,7 @@ class CSSRenderStyle } // Padding box height of renderBoxModel calculated from tight height constraints. + @override double? get paddingBoxConstraintsHeight { if (borderBoxConstraintsHeight == null) { return null; @@ -790,6 +804,7 @@ class CSSRenderStyle } // Content box width of renderBoxModel calculated from tight width constraints. + @override double? get contentBoxConstraintsWidth { if (paddingBoxConstraintsWidth == null) { return null; @@ -800,6 +815,7 @@ class CSSRenderStyle } // Content box height of renderBoxModel calculated from tight height constraints. + @override double? get contentBoxConstraintsHeight { if (paddingBoxConstraintsHeight == null) { return null; @@ -810,6 +826,7 @@ class CSSRenderStyle } // Get height of replaced element by intrinsic ratio if height is not defined + @override double getHeightByIntrinsicRatio() { double? realWidth = width.isAuto ? intrinsicWidth : width.computedValue; if (minWidth.isNotAuto && realWidth! < minWidth.computedValue) { @@ -823,6 +840,7 @@ class CSSRenderStyle } // Get width of replaced element by intrinsic ratio if width is not defined + @override double getWidthByIntrinsicRatio() { double? realHeight = height.isAuto ? intrinsicHeight : height.computedValue; if (!minHeight.isAuto && realHeight! < minHeight.computedValue) { diff --git a/kraken/lib/src/css/sizing.dart b/kraken/lib/src/css/sizing.dart index 036fa7d81d..3b31e048c8 100644 --- a/kraken/lib/src/css/sizing.dart +++ b/kraken/lib/src/css/sizing.dart @@ -135,6 +135,7 @@ mixin CSSSizingMixin on RenderStyle { // Intrinsic width of replaced element. double? _intrinsicWidth; + @override double? get intrinsicWidth { return _intrinsicWidth; } @@ -146,6 +147,7 @@ mixin CSSSizingMixin on RenderStyle { // Intrinsic height of replaced element. double? _intrinsicHeight; + @override double? get intrinsicHeight { return _intrinsicHeight; } @@ -157,6 +159,7 @@ mixin CSSSizingMixin on RenderStyle { // Aspect ratio of replaced element. double? _intrinsicRatio; + @override double? get intrinsicRatio { return _intrinsicRatio; }