extendMaxScrollableSize method
Extend max scrollable size of renderBoxModel by offset of positioned child, get the max scrollable size of children of normal flow and single positioned child.
Implementation
void extendMaxScrollableSize(RenderBoxModel child) {
Size? childScrollableSize;
RenderStyle childRenderStyle = child.renderStyle;
CSSOverflowType overflowX = childRenderStyle.effectiveOverflowX;
CSSOverflowType overflowY = childRenderStyle.effectiveOverflowY;
// Only non scroll container need to use scrollable size, otherwise use its own size
if (overflowX == CSSOverflowType.visible && overflowY == CSSOverflowType.visible) {
childScrollableSize = child.scrollableSize;
} else {
childScrollableSize = child.boxSize;
}
Matrix4? transform = (childRenderStyle as CSSRenderStyle).transformMatrix;
// Determine container content box size for positioned computations.
double containerContentWidth = _contentSize!.width;
double containerContentHeight = _contentSize!.height;
if (parent is RenderBoxModel) {
final RenderBoxModel p = parent as RenderBoxModel;
if (p.widthSizeType == BoxSizeType.specified) {
containerContentWidth = p.renderStyle.width.computedValue -
p.renderStyle.effectiveBorderLeftWidth.computedValue -
p.renderStyle.effectiveBorderRightWidth.computedValue;
}
if (p.heightSizeType == BoxSizeType.specified) {
containerContentHeight = p.renderStyle.height.computedValue -
p.renderStyle.effectiveBorderTopWidth.computedValue -
p.renderStyle.effectiveBorderBottomWidth.computedValue;
}
}
// Compute positioned box edges relative to the content (padding) box origin.
final Size childSize = childScrollableSize!;
double childLeft;
if (childRenderStyle.left.isNotAuto) {
childLeft = childRenderStyle.left.computedValue;
} else if (childRenderStyle.right.isNotAuto) {
childLeft = containerContentWidth - childSize.width - childRenderStyle.right.computedValue;
} else {
childLeft = 0;
}
double childTop;
if (childRenderStyle.top.isNotAuto) {
childTop = childRenderStyle.top.computedValue;
} else if (childRenderStyle.bottom.isNotAuto) {
childTop = containerContentHeight - childSize.height - childRenderStyle.bottom.computedValue;
} else {
childTop = 0;
}
if (transform != null) {
childLeft += transform.getTranslation()[0];
childTop += transform.getTranslation()[1];
}
final double childRight = childLeft + childSize.width;
final double childBottom = childTop + childSize.height;
// Extend scroll area when the positioned box reaches or crosses the
// scrollport (padding box) boundary.
// For LTR, treat boxes that start exactly at the trailing edge as contributing
// (<=) so users can scroll to reveal them. For RTL, keep strict (<) to avoid
// shifting initial visual alignment for cases like right:-N content.
final bool parentIsRTL = renderStyle.direction == TextDirection.rtl;
final bool intersectsH =
childRight > 0 && (parentIsRTL ? (childLeft < containerContentWidth) : (childLeft <= containerContentWidth));
final bool intersectsV = childBottom > 0 && childTop <= containerContentHeight;
double maxScrollableX = scrollableSize.width;
double maxScrollableY = scrollableSize.height;
if (intersectsH) {
maxScrollableX = math.max(maxScrollableX, math.max(containerContentWidth, childRight));
}
// Only extend vertical scroll when the positioned box also intersects (or
// reaches) the scrollport horizontally. Purely off-axis content should not
// create scroll in the other axis.
if (intersectsV && intersectsH) {
maxScrollableY = math.max(maxScrollableY, math.max(containerContentHeight, childBottom));
}
scrollableSize = Size(maxScrollableX, maxScrollableY);
}