Skip to content

Commit 90550dd

Browse files
committed
Add fixes for some table and intrinsic sizing issues
1 parent f74c2a5 commit 90550dd

File tree

10 files changed

+204
-131
lines changed

10 files changed

+204
-131
lines changed

lib/src/builtins/image_builtin.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ class ImageBuiltIn extends HtmlExtension {
9393
}
9494

9595
return WidgetSpan(
96-
alignment: context.style!.verticalAlign.toPlaceholderAlignment(context.style!.display),
96+
alignment: context.style!.verticalAlign
97+
.toPlaceholderAlignment(context.style!.display),
9798
baseline: TextBaseline.alphabetic,
9899
child: CssBoxWidget(
99100
style: imageStyle,

lib/src/builtins/interactive_element_builtin.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,19 @@ class InteractiveElementBuiltIn extends HtmlExtension {
6161
children: childSpan.children
6262
?.map((e) => _processInteractableChild(context, e))
6363
.toList(),
64+
recognizer: TapGestureRecognizer()..onTap = onTap,
6465
style: childSpan.style,
6566
semanticsLabel: childSpan.semanticsLabel,
66-
recognizer: TapGestureRecognizer()..onTap = onTap,
67+
locale: childSpan.locale,
68+
mouseCursor: childSpan.mouseCursor,
69+
onEnter: childSpan.onEnter,
70+
onExit: childSpan.onExit,
71+
spellOut: childSpan.spellOut,
6772
);
6873
} else {
6974
return WidgetSpan(
70-
alignment: context.style!.verticalAlign.toPlaceholderAlignment(context.style!.display),
75+
alignment: context.style!.verticalAlign
76+
.toPlaceholderAlignment(context.style!.display),
7177
baseline: TextBaseline.alphabetic,
7278
child: MultipleTapGestureDetector(
7379
onTap: onTap,

lib/src/builtins/styled_element_builtin.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -428,27 +428,26 @@ class StyledElementBuiltIn extends HtmlExtension {
428428
@override
429429
InlineSpan build(ExtensionContext context) {
430430
final style = context.styledElement!.style;
431-
final display = style.display;
432-
if (display == Display.listItem ||
433-
((display == Display.block || display == Display.inlineBlock) &&
431+
final display = style.display ?? Display.inline;
432+
if (display.displayListItem ||
433+
((display.isBlock || display == Display.inlineBlock) &&
434434
(context.styledElement!.children.isNotEmpty ||
435435
context.elementName == "hr"))) {
436436
return WidgetSpan(
437437
alignment: style.verticalAlign.toPlaceholderAlignment(display),
438438
baseline: TextBaseline.alphabetic,
439439
child: CssBoxWidget.withInlineSpanChildren(
440440
key: AnchorKey.of(context.parser.key, context.styledElement),
441-
style: context.styledElement!.style,
441+
style: context.style!,
442442
shrinkWrap: context.parser.shrinkWrap,
443-
childIsReplaced: ["iframe", "img", "video", "audio"]
444-
.contains(context.styledElement!.name),
443+
childIsReplaced:
444+
["iframe", "img", "video", "audio"].contains(context.elementName),
445445
children: context.builtChildrenMap!.entries
446446
.expandIndexed((i, child) => [
447447
child.value,
448448
if (context.parser.shrinkWrap &&
449449
i != context.styledElement!.children.length - 1 &&
450-
(child.key.style.display == Display.block ||
451-
child.key.style.display == Display.listItem) &&
450+
(child.key.style.display?.isBlock ?? false) &&
452451
child.key.element?.localName != "html" &&
453452
child.key.element?.localName != "body")
454453
const TextSpan(text: "\n", style: TextStyle(fontSize: 0)),
@@ -464,7 +463,7 @@ class StyledElementBuiltIn extends HtmlExtension {
464463
.expandIndexed((index, child) => [
465464
child.value,
466465
if (context.parser.shrinkWrap &&
467-
child.key.style.display == Display.block &&
466+
(child.key.style.display?.isBlock ?? false) &&
468467
index != context.styledElement!.children.length - 1 &&
469468
child.key.element?.parent?.localName != "th" &&
470469
child.key.element?.parent?.localName != "td" &&

lib/src/css_box_widget.dart

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,7 @@ class CssBoxWidget extends StatelessWidget {
159159
/// width available to it or if it should just let its inner content
160160
/// determine the content-box's width.
161161
bool _shouldExpandToFillBlock() {
162-
return (style.display == Display.block ||
163-
style.display == Display.listItem) &&
164-
!childIsReplaced &&
165-
!shrinkWrap;
162+
return (style.display?.isBlock ?? false) && !childIsReplaced && !shrinkWrap;
166163
}
167164

168165
TextDirection _checkTextDirection(
@@ -424,42 +421,62 @@ class RenderCSSBox extends RenderBox
424421
}
425422
}
426423

427-
static double getIntrinsicDimension(RenderBox? firstChild,
428-
double Function(RenderBox child) mainChildSizeGetter) {
424+
static double getIntrinsicDimension(
425+
RenderBox? firstChild,
426+
double Function(RenderBox child) mainChildSizeGetter,
427+
double marginSpaceNeeded) {
429428
double extent = 0.0;
430429
RenderBox? child = firstChild;
431430
while (child != null) {
432431
final CSSBoxParentData childParentData =
433432
child.parentData! as CSSBoxParentData;
434-
extent = math.max(extent, mainChildSizeGetter(child));
433+
try {
434+
extent = math.max(extent, mainChildSizeGetter(child));
435+
} catch (_) {
436+
// See https://github.com/flutter/flutter/issues/65895
437+
debugPrint(
438+
"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");
439+
}
435440
assert(child.parentData == childParentData);
436441
child = childParentData.nextSibling;
437442
}
438-
return extent;
443+
return extent + marginSpaceNeeded;
439444
}
440445

441446
@override
442447
double computeMinIntrinsicWidth(double height) {
443448
return getIntrinsicDimension(
444-
firstChild, (RenderBox child) => child.getMinIntrinsicWidth(height));
449+
firstChild,
450+
(RenderBox child) => child.getMinIntrinsicWidth(height),
451+
_calculateIntrinsicMargins().horizontal,
452+
);
445453
}
446454

447455
@override
448456
double computeMaxIntrinsicWidth(double height) {
449457
return getIntrinsicDimension(
450-
firstChild, (RenderBox child) => child.getMaxIntrinsicWidth(height));
458+
firstChild,
459+
(RenderBox child) => child.getMaxIntrinsicWidth(height),
460+
_calculateIntrinsicMargins().horizontal,
461+
);
451462
}
452463

453464
@override
454465
double computeMinIntrinsicHeight(double width) {
455466
return getIntrinsicDimension(
456-
firstChild, (RenderBox child) => child.getMinIntrinsicHeight(width));
467+
firstChild,
468+
(RenderBox child) => child.getMinIntrinsicHeight(width),
469+
_calculateIntrinsicMargins().vertical,
470+
);
457471
}
458472

459473
@override
460474
double computeMaxIntrinsicHeight(double width) {
461475
return getIntrinsicDimension(
462-
firstChild, (RenderBox child) => child.getMaxIntrinsicHeight(width));
476+
firstChild,
477+
(RenderBox child) => child.getMaxIntrinsicHeight(width),
478+
_calculateIntrinsicMargins().vertical,
479+
);
463480
}
464481

465482
@override
@@ -521,31 +538,20 @@ class RenderCSSBox extends RenderBox
521538

522539
//Calculate Width and Height of CSS Box
523540
height = childSize.height;
524-
switch (display) {
525-
case Display.block:
526-
width = (shrinkWrap || childIsReplaced)
527-
? childSize.width + horizontalMargins
528-
: containingBlockSize.width;
529-
height = childSize.height + verticalMargins;
530-
break;
531-
case Display.inline:
532-
width = childSize.width + horizontalMargins;
533-
height = childSize.height;
534-
break;
535-
case Display.inlineBlock:
536-
width = childSize.width + horizontalMargins;
537-
height = childSize.height + verticalMargins;
538-
break;
539-
case Display.listItem:
540-
width = shrinkWrap
541-
? childSize.width + horizontalMargins
542-
: containingBlockSize.width;
543-
height = childSize.height + verticalMargins;
544-
break;
545-
case Display.none:
546-
width = 0;
547-
height = 0;
548-
break;
541+
if (display.displayBox == DisplayBox.none) {
542+
width = 0;
543+
height = 0;
544+
} else if (display == Display.inlineBlock) {
545+
width = childSize.width + horizontalMargins;
546+
height = childSize.height + verticalMargins;
547+
} else if (display.isBlock) {
548+
width = (shrinkWrap || childIsReplaced)
549+
? childSize.width + horizontalMargins
550+
: containingBlockSize.width;
551+
height = childSize.height + verticalMargins;
552+
} else {
553+
width = childSize.width + horizontalMargins;
554+
height = childSize.height;
549555
}
550556

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

576582
double leftOffset = 0;
577583
double topOffset = 0;
578-
switch (display) {
579-
case Display.block:
580-
leftOffset = leftMargin;
581-
topOffset = topMargin;
582-
break;
583-
case Display.inline:
584-
leftOffset = leftMargin;
585-
break;
586-
case Display.inlineBlock:
587-
leftOffset = leftMargin;
588-
topOffset = topMargin;
589-
break;
590-
case Display.listItem:
591-
leftOffset = leftMargin;
592-
topOffset = topMargin;
593-
break;
594-
case Display.none:
595-
//No offset
596-
break;
584+
585+
if (display.isBlock || display == Display.inlineBlock) {
586+
leftOffset = leftMargin;
587+
topOffset = topMargin;
588+
} else if (display.displayOutside == DisplayOutside.inline) {
589+
leftOffset = leftMargin;
597590
}
591+
598592
childParentData.offset = Offset(leftOffset, topOffset);
599593
assert(child.parentData == childParentData);
600594

@@ -628,7 +622,7 @@ class RenderCSSBox extends RenderBox
628622

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

734+
Margins _calculateIntrinsicMargins() {
735+
//We assume that margins have already been preprocessed
736+
// (i.e. they are non-null and either px units or auto).
737+
assert(margins.left != null && margins.right != null);
738+
assert(margins.left!.unit == Unit.px || margins.left!.unit == Unit.auto);
739+
assert(margins.right!.unit == Unit.px || margins.right!.unit == Unit.auto);
740+
741+
Margin marginLeft = margins.left!;
742+
Margin marginRight = margins.right!;
743+
744+
bool marginLeftIsAuto = marginLeft.unit == Unit.auto;
745+
bool marginRightIsAuto = marginRight.unit == Unit.auto;
746+
747+
if (display.isBlock) {
748+
if (marginLeftIsAuto) {
749+
marginLeft = Margin(0);
750+
}
751+
752+
if (marginRightIsAuto) {
753+
marginRight = Margin(0);
754+
}
755+
} else {
756+
marginLeft = Margin(0);
757+
marginRight = Margin(0);
758+
}
759+
760+
return Margins(
761+
left: marginLeft,
762+
right: marginRight,
763+
top: margins.top,
764+
bottom: margins.bottom,
765+
);
766+
}
767+
740768
@override
741769
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
742770
return defaultHitTestChildren(result, position: position);

lib/src/processing/margins.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ class MarginProcessing {
3232
//Collapsing should be depth-first.
3333
tree.children.forEach(_collapseMargins);
3434

35-
//The root boxes do not collapse.
36-
if (tree.name == '[Tree Root]' || tree.name == 'html') {
35+
//The root boxes and table/ruby elements do not collapse.
36+
if (tree.name == '[Tree Root]' ||
37+
tree.name == 'html' ||
38+
tree.style.display?.displayInternal != null) {
3739
return tree;
3840
}
3941

@@ -67,7 +69,8 @@ class MarginProcessing {
6769

6870
// Handle case (3) from above.
6971
// Bottom margins cannot collapse if the element has padding
70-
if ((tree.style.padding?.bottom ?? tree.style.padding?.blockEnd ?? 0) ==
72+
if ((tree.style.padding?.bottom?.value ??
73+
tree.style.padding?.blockEnd?.value) ==
7174
0) {
7275
final parentBottom = tree.style.margin?.bottom?.value ??
7376
tree.style.margin?.blockEnd?.value ??

lib/src/style.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -689,14 +689,17 @@ enum VerticalAlign {
689689
/// Converts this [VerticalAlign] to a [PlaceholderAlignment] given the
690690
/// [Display] type of the current context
691691
PlaceholderAlignment toPlaceholderAlignment(Display? display) {
692-
693692
// vertical-align only applies to inline context elements.
694693
// If we aren't in such a context, use the default 'bottom' alignment.
695-
if(display != Display.inline && display != Display.inlineBlock) {
694+
// Also note that the default display, if it is not set, is inline, so we
695+
// treat null `display` values as if they were inline by default.
696+
if (display != Display.inline &&
697+
display != Display.inlineBlock &&
698+
display != null) {
696699
return PlaceholderAlignment.bottom;
697700
}
698701

699-
switch(this) {
702+
switch (this) {
700703
case VerticalAlign.baseline:
701704
case VerticalAlign.sub:
702705
case VerticalAlign.sup:
@@ -708,7 +711,6 @@ enum VerticalAlign {
708711
case VerticalAlign.middle:
709712
return PlaceholderAlignment.middle;
710713
}
711-
712714
}
713715
}
714716

0 commit comments

Comments
 (0)