Skip to content

Commit

Permalink
Add fixes for some table and intrinsic sizing issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Sub6Resources committed Jun 7, 2023
1 parent 38d4638 commit 88079a2
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 131 deletions.
3 changes: 2 additions & 1 deletion lib/src/builtins/image_builtin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ class ImageBuiltIn extends HtmlExtension {
}

return WidgetSpan(
alignment: context.style!.verticalAlign.toPlaceholderAlignment(context.style!.display),
alignment: context.style!.verticalAlign
.toPlaceholderAlignment(context.style!.display),
baseline: TextBaseline.alphabetic,
child: CssBoxWidget(
style: imageStyle,
Expand Down
10 changes: 8 additions & 2 deletions lib/src/builtins/interactive_element_builtin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,19 @@ class InteractiveElementBuiltIn extends HtmlExtension {
children: childSpan.children
?.map((e) => _processInteractableChild(context, e))
.toList(),
recognizer: TapGestureRecognizer()..onTap = onTap,
style: childSpan.style,
semanticsLabel: childSpan.semanticsLabel,
recognizer: TapGestureRecognizer()..onTap = onTap,
locale: childSpan.locale,
mouseCursor: childSpan.mouseCursor,
onEnter: childSpan.onEnter,
onExit: childSpan.onExit,
spellOut: childSpan.spellOut,
);
} else {
return WidgetSpan(
alignment: context.style!.verticalAlign.toPlaceholderAlignment(context.style!.display),
alignment: context.style!.verticalAlign
.toPlaceholderAlignment(context.style!.display),
baseline: TextBaseline.alphabetic,
child: MultipleTapGestureDetector(
onTap: onTap,
Expand Down
17 changes: 8 additions & 9 deletions lib/src/builtins/styled_element_builtin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -428,27 +428,26 @@ class StyledElementBuiltIn extends HtmlExtension {
@override
InlineSpan build(ExtensionContext context) {
final style = context.styledElement!.style;
final display = style.display;
if (display == Display.listItem ||
((display == Display.block || display == Display.inlineBlock) &&
final display = style.display ?? Display.inline;
if (display.displayListItem ||
((display.isBlock || display == Display.inlineBlock) &&
(context.styledElement!.children.isNotEmpty ||
context.elementName == "hr"))) {
return WidgetSpan(
alignment: style.verticalAlign.toPlaceholderAlignment(display),
baseline: TextBaseline.alphabetic,
child: CssBoxWidget.withInlineSpanChildren(
key: AnchorKey.of(context.parser.key, context.styledElement),
style: context.styledElement!.style,
style: context.style!,
shrinkWrap: context.parser.shrinkWrap,
childIsReplaced: ["iframe", "img", "video", "audio"]
.contains(context.styledElement!.name),
childIsReplaced:
["iframe", "img", "video", "audio"].contains(context.elementName),
children: context.builtChildrenMap!.entries
.expandIndexed((i, child) => [
child.value,
if (context.parser.shrinkWrap &&
i != context.styledElement!.children.length - 1 &&
(child.key.style.display == Display.block ||
child.key.style.display == Display.listItem) &&
(child.key.style.display?.isBlock ?? false) &&
child.key.element?.localName != "html" &&
child.key.element?.localName != "body")
const TextSpan(text: "\n", style: TextStyle(fontSize: 0)),
Expand All @@ -464,7 +463,7 @@ class StyledElementBuiltIn extends HtmlExtension {
.expandIndexed((index, child) => [
child.value,
if (context.parser.shrinkWrap &&
child.key.style.display == Display.block &&
(child.key.style.display?.isBlock ?? false) &&
index != context.styledElement!.children.length - 1 &&
child.key.element?.parent?.localName != "th" &&
child.key.element?.parent?.localName != "td" &&
Expand Down
142 changes: 85 additions & 57 deletions lib/src/css_box_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,7 @@ class CssBoxWidget extends StatelessWidget {
/// width available to it or if it should just let its inner content
/// determine the content-box's width.
bool _shouldExpandToFillBlock() {
return (style.display == Display.block ||
style.display == Display.listItem) &&
!childIsReplaced &&
!shrinkWrap;
return (style.display?.isBlock ?? false) && !childIsReplaced && !shrinkWrap;
}

TextDirection _checkTextDirection(
Expand Down Expand Up @@ -424,42 +421,62 @@ class RenderCSSBox extends RenderBox
}
}

static double getIntrinsicDimension(RenderBox? firstChild,
double Function(RenderBox child) mainChildSizeGetter) {
static double getIntrinsicDimension(
RenderBox? firstChild,
double Function(RenderBox child) mainChildSizeGetter,
double marginSpaceNeeded) {
double extent = 0.0;
RenderBox? child = firstChild;
while (child != null) {
final CSSBoxParentData childParentData =
child.parentData! as CSSBoxParentData;
extent = math.max(extent, mainChildSizeGetter(child));
try {
extent = math.max(extent, mainChildSizeGetter(child));
} catch (_) {
// See https://github.com/flutter/flutter/issues/65895
debugPrint(
"Due to Flutter layout restrictions (see https://github.com/flutter/flutter/issues/65895), contents set to `vertical-align: baseline` within an intrinsically-sized layout may not display as expected. If content is cut off or displaying incorrectly, please try setting vertical-align to 'bottom' on the problematic elements");
}
assert(child.parentData == childParentData);
child = childParentData.nextSibling;
}
return extent;
return extent + marginSpaceNeeded;
}

@override
double computeMinIntrinsicWidth(double height) {
return getIntrinsicDimension(
firstChild, (RenderBox child) => child.getMinIntrinsicWidth(height));
firstChild,
(RenderBox child) => child.getMinIntrinsicWidth(height),
_calculateIntrinsicMargins().horizontal,
);
}

@override
double computeMaxIntrinsicWidth(double height) {
return getIntrinsicDimension(
firstChild, (RenderBox child) => child.getMaxIntrinsicWidth(height));
firstChild,
(RenderBox child) => child.getMaxIntrinsicWidth(height),
_calculateIntrinsicMargins().horizontal,
);
}

@override
double computeMinIntrinsicHeight(double width) {
return getIntrinsicDimension(
firstChild, (RenderBox child) => child.getMinIntrinsicHeight(width));
firstChild,
(RenderBox child) => child.getMinIntrinsicHeight(width),
_calculateIntrinsicMargins().vertical,
);
}

@override
double computeMaxIntrinsicHeight(double width) {
return getIntrinsicDimension(
firstChild, (RenderBox child) => child.getMaxIntrinsicHeight(width));
firstChild,
(RenderBox child) => child.getMaxIntrinsicHeight(width),
_calculateIntrinsicMargins().vertical,
);
}

@override
Expand Down Expand Up @@ -521,31 +538,20 @@ class RenderCSSBox extends RenderBox

//Calculate Width and Height of CSS Box
height = childSize.height;
switch (display) {
case Display.block:
width = (shrinkWrap || childIsReplaced)
? childSize.width + horizontalMargins
: containingBlockSize.width;
height = childSize.height + verticalMargins;
break;
case Display.inline:
width = childSize.width + horizontalMargins;
height = childSize.height;
break;
case Display.inlineBlock:
width = childSize.width + horizontalMargins;
height = childSize.height + verticalMargins;
break;
case Display.listItem:
width = shrinkWrap
? childSize.width + horizontalMargins
: containingBlockSize.width;
height = childSize.height + verticalMargins;
break;
case Display.none:
width = 0;
height = 0;
break;
if (display.displayBox == DisplayBox.none) {
width = 0;
height = 0;
} else if (display == Display.inlineBlock) {
width = childSize.width + horizontalMargins;
height = childSize.height + verticalMargins;
} else if (display.isBlock) {
width = (shrinkWrap || childIsReplaced)
? childSize.width + horizontalMargins
: containingBlockSize.width;
height = childSize.height + verticalMargins;
} else {
width = childSize.width + horizontalMargins;
height = childSize.height;
}

return _Sizes(constraints.constrain(Size(width, height)), childSize);
Expand Down Expand Up @@ -575,26 +581,14 @@ class RenderCSSBox extends RenderBox

double leftOffset = 0;
double topOffset = 0;
switch (display) {
case Display.block:
leftOffset = leftMargin;
topOffset = topMargin;
break;
case Display.inline:
leftOffset = leftMargin;
break;
case Display.inlineBlock:
leftOffset = leftMargin;
topOffset = topMargin;
break;
case Display.listItem:
leftOffset = leftMargin;
topOffset = topMargin;
break;
case Display.none:
//No offset
break;

if (display.isBlock || display == Display.inlineBlock) {
leftOffset = leftMargin;
topOffset = topMargin;
} else if (display.displayOutside == DisplayOutside.inline) {
leftOffset = leftMargin;
}

childParentData.offset = Offset(leftOffset, topOffset);
assert(child.parentData == childParentData);

Expand Down Expand Up @@ -628,7 +622,7 @@ class RenderCSSBox extends RenderBox

Margins _calculateUsedMargins(Size childSize, Size containingBlockSize) {
//We assume that margins have already been preprocessed
// (i.e. they are non-null and either px units or auto.
// (i.e. they are non-null and either px units or auto).
assert(margins.left != null && margins.right != null);
assert(margins.left!.unit == Unit.px || margins.left!.unit == Unit.auto);
assert(margins.right!.unit == Unit.px || margins.right!.unit == Unit.auto);
Expand Down Expand Up @@ -737,6 +731,40 @@ class RenderCSSBox extends RenderBox
);
}

Margins _calculateIntrinsicMargins() {
//We assume that margins have already been preprocessed
// (i.e. they are non-null and either px units or auto).
assert(margins.left != null && margins.right != null);
assert(margins.left!.unit == Unit.px || margins.left!.unit == Unit.auto);
assert(margins.right!.unit == Unit.px || margins.right!.unit == Unit.auto);

Margin marginLeft = margins.left!;
Margin marginRight = margins.right!;

bool marginLeftIsAuto = marginLeft.unit == Unit.auto;
bool marginRightIsAuto = marginRight.unit == Unit.auto;

if (display.isBlock) {
if (marginLeftIsAuto) {
marginLeft = Margin(0);
}

if (marginRightIsAuto) {
marginRight = Margin(0);
}
} else {
marginLeft = Margin(0);
marginRight = Margin(0);
}

return Margins(
left: marginLeft,
right: marginRight,
top: margins.top,
bottom: margins.bottom,
);
}

@override
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
return defaultHitTestChildren(result, position: position);
Expand Down
9 changes: 6 additions & 3 deletions lib/src/processing/margins.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ class MarginProcessing {
//Collapsing should be depth-first.
tree.children.forEach(_collapseMargins);

//The root boxes do not collapse.
if (tree.name == '[Tree Root]' || tree.name == 'html') {
//The root boxes and table/ruby elements do not collapse.
if (tree.name == '[Tree Root]' ||
tree.name == 'html' ||
tree.style.display?.displayInternal != null) {
return tree;
}

Expand Down Expand Up @@ -67,7 +69,8 @@ class MarginProcessing {

// Handle case (3) from above.
// Bottom margins cannot collapse if the element has padding
if ((tree.style.padding?.bottom ?? tree.style.padding?.blockEnd ?? 0) ==
if ((tree.style.padding?.bottom?.value ??
tree.style.padding?.blockEnd?.value) ==
0) {
final parentBottom = tree.style.margin?.bottom?.value ??
tree.style.margin?.blockEnd?.value ??
Expand Down
10 changes: 6 additions & 4 deletions lib/src/style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -689,14 +689,17 @@ enum VerticalAlign {
/// Converts this [VerticalAlign] to a [PlaceholderAlignment] given the
/// [Display] type of the current context
PlaceholderAlignment toPlaceholderAlignment(Display? display) {

// vertical-align only applies to inline context elements.
// If we aren't in such a context, use the default 'bottom' alignment.
if(display != Display.inline && display != Display.inlineBlock) {
// Also note that the default display, if it is not set, is inline, so we
// treat null `display` values as if they were inline by default.
if (display != Display.inline &&
display != Display.inlineBlock &&
display != null) {
return PlaceholderAlignment.bottom;
}

switch(this) {
switch (this) {
case VerticalAlign.baseline:
case VerticalAlign.sub:
case VerticalAlign.sup:
Expand All @@ -708,7 +711,6 @@ enum VerticalAlign {
case VerticalAlign.middle:
return PlaceholderAlignment.middle;
}

}
}

Expand Down
Loading

0 comments on commit 88079a2

Please sign in to comment.