Bug 69808

Summary: Implement -webkit-flex-align for cross axis alignment in flex-flow: row
Product: WebKit Reporter: Tony Chang <tony>
Component: New BugsAssignee: Tony Chang <tony>
Status: RESOLVED FIXED    
Severity: Normal CC: hyatt, ojan, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 62048    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch for landing none

Description Tony Chang 2011-10-10 18:17:53 PDT
Implement -webkit-flex-align for cross axis alignment
Comment 1 Tony Chang 2011-10-10 18:18:25 PDT
Created attachment 110454 [details]
Patch
Comment 2 Ojan Vafai 2011-10-10 19:15:28 PDT
Comment on attachment 110454 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110454&action=review

A first pass review. I'd like hyatt to do the final r+ here since I'm unsure about the baseline related stuff.

> LayoutTests/css3/flexbox/flex-align.html:105
> +  <div data-expected-height="100" data-offset-y="0" style="width: -webkit-flex(1 0 0); height: 100px;"></div>

Would be good to have a test-case for items with different top/bottom margins. Specifically, I'd like to see flex-align:stretch and flex-align:baseline with something like the following:

<div class=flexbox>
  <div style="width: -webkit-flex(1); -webkit-flex-align: stretch; height: 50px; margin: 10px 20px 30px 40px"></div>
  <div style="width: -webkit-flex(1); -webkit-flex-align: stretch; height: 50px; margin: 2px 4px 6px 8px"></div>
</div>

> Source/WebCore/rendering/RenderFlexibleBox.cpp:512
> +            if (isFlowAwareLogicalHeightAuto())
> +                setFlowAwareLogicalHeight(std::max(flowAwareLogicalHeight(), flowAwareBorderBefore() + flowAwarePaddingBefore() + flowAwareMarginBeforeForChild(child) + maxAscent + maxDescent + flowAwareMarginAfterForChild(child) + flowAwarePaddingAfter() + flowAwareBorderAfter() + scrollbarLogicalHeight()));
> +        } else if (isFlowAwareLogicalHeightAuto())
> +            setFlowAwareLogicalHeight(std::max(flowAwareLogicalHeight(), flowAwareBorderBefore() + flowAwarePaddingBefore() + flowAwareMarginBeforeForChild(child) + flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child) + flowAwarePaddingAfter() + flowAwareBorderAfter() + scrollbarLogicalHeight()));

Can you instead move flowAwareBorderAndPaddingHeight and flowAwareMarginHeightForChild into helper functions? That would make this a lot easier to read and avoid code duplication here and above.

> Source/WebCore/rendering/RenderFlexibleBox.cpp:540
> +void RenderFlexibleBox::alignChildrenBlockDirection(FlexOrderIterator& iterator, LayoutUnit maxAscent, LayoutUnit maxDescent)

You don't use maxDescent. Did you not get a compiler warning?

> Source/WebCore/rendering/RenderFlexibleBox.cpp:544
> +        LayoutUnit currentChildHeight = flowAwareMarginBeforeForChild(child) + flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child);

You compute this on line 503 as well. Move into a helper function? flowAwareLogicalMarginBoxHeightForChild? lol.

> Source/WebCore/rendering/RenderFlexibleBox.cpp:555
> +        case AlignStart:
> +            break;

Could you check the flexAlign as the beginning of the function and early return? Then here you could ASSERT_NOT_REACHED? I guess that's a premature optimization, but a FIXME at least would be good.

> Source/WebCore/rendering/RenderFlexibleBox.cpp:566
> +            LayoutUnit ascent = child->firstLineBoxBaseline();
> +            if (ascent == -1)
> +                ascent = flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child);
> +            ascent += flowAwareMarginBeforeForChild(child);

This chunk of code is exactly the same as in layoutAndPlaceChildrenInlineDirection. Pull it out into a helper function?
Comment 3 Tony Chang 2011-10-11 14:21:02 PDT
Created attachment 110574 [details]
Patch
Comment 4 Tony Chang 2011-10-11 14:25:14 PDT
Created attachment 110575 [details]
Patch
Comment 5 Tony Chang 2011-10-11 14:27:13 PDT
(In reply to comment #2)
> (From update of attachment 110454 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=110454&action=review
> 
> > LayoutTests/css3/flexbox/flex-align.html:105
> > +  <div data-expected-height="100" data-offset-y="0" style="width: -webkit-flex(1 0 0); height: 100px;"></div>
> 
> Would be good to have a test-case for items with different top/bottom margins.

Done.

> > Source/WebCore/rendering/RenderFlexibleBox.cpp:512
> > +            if (isFlowAwareLogicalHeightAuto())
> > +                setFlowAwareLogicalHeight(std::max(flowAwareLogicalHeight(), flowAwareBorderBefore() + flowAwarePaddingBefore() + flowAwareMarginBeforeForChild(child) + maxAscent + maxDescent + flowAwareMarginAfterForChild(child) + flowAwarePaddingAfter() + flowAwareBorderAfter() + scrollbarLogicalHeight()));
> > +        } else if (isFlowAwareLogicalHeightAuto())
> > +            setFlowAwareLogicalHeight(std::max(flowAwareLogicalHeight(), flowAwareBorderBefore() + flowAwarePaddingBefore() + flowAwareMarginBeforeForChild(child) + flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child) + flowAwarePaddingAfter() + flowAwareBorderAfter() + scrollbarLogicalHeight()));
> 
> Can you instead move flowAwareBorderAndPaddingHeight and flowAwareMarginHeightForChild into helper functions? That would make this a lot easier to read and avoid code duplication here and above.

Done.

> > Source/WebCore/rendering/RenderFlexibleBox.cpp:540
> > +void RenderFlexibleBox::alignChildrenBlockDirection(FlexOrderIterator& iterator, LayoutUnit maxAscent, LayoutUnit maxDescent)
> 
> You don't use maxDescent. Did you not get a compiler warning?

Removed.

> > Source/WebCore/rendering/RenderFlexibleBox.cpp:544
> > +        LayoutUnit currentChildHeight = flowAwareMarginBeforeForChild(child) + flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child);
> 
> You compute this on line 503 as well. Move into a helper function? flowAwareLogicalMarginBoxHeightForChild? lol.

Switched to use flowAwareMarginLogicalHeightForChild().

> > Source/WebCore/rendering/RenderFlexibleBox.cpp:555
> > +        case AlignStart:
> > +            break;
> 
> Could you check the flexAlign as the beginning of the function and early return? Then here you could ASSERT_NOT_REACHED? I guess that's a premature optimization, but a FIXME at least would be good.

I added availableLogicalHeightForChild to avoid the extra computation.  An early return wouldn't have worked since this is applied to each child.

> > Source/WebCore/rendering/RenderFlexibleBox.cpp:566
> > +            LayoutUnit ascent = child->firstLineBoxBaseline();
> > +            if (ascent == -1)
> > +                ascent = flowAwareLogicalHeightForChild(child) + flowAwareMarginAfterForChild(child);
> > +            ascent += flowAwareMarginBeforeForChild(child);
> 
> This chunk of code is exactly the same as in layoutAndPlaceChildrenInlineDirection. Pull it out into a helper function?

Done.
Comment 6 Ojan Vafai 2011-10-11 15:57:05 PDT
Comment on attachment 110575 [details]
Patch

Patch looks good to me. Would like Hyatt to do a pass just to make sure we're not doing anything egregiously wrong.
Comment 7 Dave Hyatt 2011-10-12 11:02:10 PDT
Comment on attachment 110575 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110575&action=review

> Source/WebCore/rendering/RenderFlexibleBox.cpp:571
> +        case AlignStretch: {
> +            Length height = isHorizontalFlow() ? child->style()->height() : child->style()->width();
> +            if (height.isAuto())
> +                child->setLogicalHeight(child->logicalHeight() + RenderFlexibleBox::availableLogicalHeightForChild(child));
> +            break;

This is wrong if the child is a perpendicular writing mode. You need setLogicalHeightForChild and to use logicalHeightForChild, or you could just use physical setters.
Comment 8 Tony Chang 2011-10-12 13:48:34 PDT
Created attachment 110738 [details]
Patch
Comment 9 Tony Chang 2011-10-12 13:49:17 PDT
(In reply to comment #7)
> (From update of attachment 110575 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=110575&action=review
> 
> > Source/WebCore/rendering/RenderFlexibleBox.cpp:571
> > +        case AlignStretch: {
> > +            Length height = isHorizontalFlow() ? child->style()->height() : child->style()->width();
> > +            if (height.isAuto())
> > +                child->setLogicalHeight(child->logicalHeight() + RenderFlexibleBox::availableLogicalHeightForChild(child));
> > +            break;
> 
> This is wrong if the child is a perpendicular writing mode. You need setLogicalHeightForChild and to use logicalHeightForChild, or you could just use physical setters.

Updated to use physical setters and logicalHeightForChild.  Also added a test case.
Comment 10 Ojan Vafai 2011-10-12 14:24:46 PDT
Comment on attachment 110738 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110738&action=review

> Source/WebCore/rendering/RenderFlexibleBox.cpp:578
> +                    child->setHeight(logicalHeightForChild(child) + RenderFlexibleBox::availableLogicalHeightForChild(child));
> +                else
> +                    child->setWidth(logicalHeightForChild(child) + RenderFlexibleBox::availableLogicalHeightForChild(child));

nit: move logicalHeightForChild(child) + RenderFlexibleBox::availableLogicalHeightForChild(child) into a local variable (e.g. newLogicalHeight) so you don't have to repeat the code?
Comment 11 Tony Chang 2011-10-12 14:49:22 PDT
Created attachment 110749 [details]
Patch
Comment 12 Dave Hyatt 2011-10-12 15:02:34 PDT
Comment on attachment 110749 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110749&action=review

r=me

> Source/WebCore/rendering/RenderFlexibleBox.cpp:573
> +            Length height = isHorizontalFlow() ? child->style()->height() : child->style()->width();

RenderStyle does have helpers for margins but not for logical height. If you wanted to add a logicalHeightUsing method to RenderStyle helper so you could say child->style()->logcialHeightUsing(style()) I would be fine with that. Not required though.

Also note you don't handle maxHeight clamping here. Not sure if you have to or not. I'd put a FIXME: in asking and not worry about it for now.
Comment 13 Tony Chang 2011-10-12 15:11:08 PDT
Created attachment 110754 [details]
Patch for landing
Comment 14 WebKit Review Bot 2011-10-12 15:48:33 PDT
Comment on attachment 110754 [details]
Patch for landing

Clearing flags on attachment: 110754

Committed r97313: <http://trac.webkit.org/changeset/97313>
Comment 15 WebKit Review Bot 2011-10-12 15:48:39 PDT
All reviewed patches have been landed.  Closing bug.