Bug 233144

Summary: Integrate motion path transforms in transformation pipeline
Product: WebKit Reporter: Kiet Ho <tho22>
Component: CSSAssignee: Kiet Ho <tho22>
Status: RESOLVED FIXED    
Severity: Normal CC: changseok, dino, esprehn+autocc, ews-watchlist, fred.wang, glenn, jonlee, kondapallykalyan, pdr, simon.fraser, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari Technology Preview   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 203847    
Attachments:
Description Flags
WIP
none
WIP
none
Patch
none
Patch
none
Patch none

Description Kiet Ho 2021-11-15 13:42:45 PST
Integrate motion path transforms in transformation pipeline
Comment 1 Kiet Ho 2021-11-16 03:19:00 PST
Created attachment 444367 [details]
WIP
Comment 2 Kiet Ho 2021-11-16 12:05:27 PST
Created attachment 444419 [details]
WIP
Comment 3 Simon Fraser (smfr) 2021-11-17 14:54:44 PST
Comment on attachment 444419 [details]
WIP

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

> Source/WebCore/platform/graphics/Path.cpp:567
> +    apply([&lastElementIsClosed](const WebCore::PathElement& element) {
> +        lastElementIsClosed = (element.type == PathElement::Type::CloseSubpath);
> +    });

This is a bit subtle; I didn't understand at first reading. Maybe add a comment, or find a more efficient way to do this.

> Source/WebCore/rendering/style/RenderStyle.cpp:1459
> +static std::optional<Path> getPathFromPathOperation(const FloatRect& box, const PathOperation* operation)

It looks like the only caller null-checks already, so it would be nicer if this took a const PathOperation&.

> Source/WebCore/rendering/style/RenderStyle.cpp:1474
> +    auto distanceValue = floatValueForLength(distance, pathLength);

Do we have enough context here to resolve things like viewport units and calc() in the Length here? I think not. Maybe the caller needs to resolve the length first. If this is broken, it should gain some tests.

> Source/WebCore/rendering/style/RenderStyle.cpp:1487
> +    if (path.isClosed()) {
> +        if (pathLength) {
> +            resolvedLength = fmod(distanceValue, pathLength);
> +            if (resolvedLength < 0)
> +                resolvedLength += pathLength;
> +        }
> +    } else
> +        resolvedLength = clampTo<float>(distanceValue, 0, pathLength);
> +
> +    ASSERT(resolvedLength >= 0);
> +    return path.traversalStateAtLength(resolvedLength);

Maybe traversalStateAtLength() could do the "isClosed" check and the fmod(), so you don't even need the isClosed() implementation?

> Source/WebCore/rendering/style/RenderStyle.cpp:1508
> +    if (!offsetAnchor().x().isAuto())
> +        anchor = floatPointForLengthPoint(offsetAnchor(), boundingBox.size()) + boundingBox.location();

Why is it OK to only check .x()?

> Source/WebCore/rendering/style/RenderStyle.cpp:1514
> +    FloatPoint shiftToOrigin {
> +        anchor.x() - transformOrigin.x(),
> +        anchor.y() - transformOrigin.y()
> +    };

This could be:
auto shiftToOrigin = anchor - toFloatSize(transformOrigin);

I think it's slightly more logical for shiftToOrigin to be a FloatSize.

> Source/WebCore/rendering/style/RenderStyle.cpp:1520
> +        transform.rotate(traversalState.normalAngle() + rotation.angle());

Are these angles in the correct units (radians vs. degrees)?

> Source/WebCore/rendering/style/RenderStyle.h:649
> +    bool hasTransform() const { return !m_rareNonInheritedData->transform->operations.operations().isEmpty() || offsetPath(); }

This makes me think that we need to examine all callers of hasTransformRelatedProperty() to see if they need offsetPath handling.
Comment 4 Kiet Ho 2021-11-18 15:48:16 PST
Comment on attachment 444419 [details]
WIP

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

>> Source/WebCore/platform/graphics/Path.cpp:567
>> +    });
> 
> This is a bit subtle; I didn't understand at first reading. Maybe add a comment, or find a more efficient way to do this.

I'll add a comment.

>> Source/WebCore/rendering/style/RenderStyle.cpp:1459
>> +static std::optional<Path> getPathFromPathOperation(const FloatRect& box, const PathOperation* operation)
> 
> It looks like the only caller null-checks already, so it would be nicer if this took a const PathOperation&.

Will fix.

>> Source/WebCore/rendering/style/RenderStyle.cpp:1474
>> +    auto distanceValue = floatValueForLength(distance, pathLength);
> 
> Do we have enough context here to resolve things like viewport units and calc() in the Length here? I think not. Maybe the caller needs to resolve the length first. If this is broken, it should gain some tests.

offset-distance is first parsed into a CSSPrimitiveValue, then it's converted to a Length using BuilderConverter::convertLength. I briefly went through the code, and it properly handles all CSS units and calc().

>> Source/WebCore/rendering/style/RenderStyle.cpp:1487
>> +    return path.traversalStateAtLength(resolvedLength);
> 
> Maybe traversalStateAtLength() could do the "isClosed" check and the fmod(), so you don't even need the isClosed() implementation?

My justification is that Path::isClose() might be useful to someone in the future, but if you want to, I can move the check into this function.

>> Source/WebCore/rendering/style/RenderStyle.cpp:1508
>> +        anchor = floatPointForLengthPoint(offsetAnchor(), boundingBox.size()) + boundingBox.location();
> 
> Why is it OK to only check .x()?

If offset-anchor is auto, then both x() and y() are auto. It's not possible to have an auto x() and non-auto y(), and vice versa.

>> Source/WebCore/rendering/style/RenderStyle.cpp:1514
>> +    };
> 
> This could be:
> auto shiftToOrigin = anchor - toFloatSize(transformOrigin);
> 
> I think it's slightly more logical for shiftToOrigin to be a FloatSize.

Will fix.

>> Source/WebCore/rendering/style/RenderStyle.cpp:1520
>> +        transform.rotate(traversalState.normalAngle() + rotation.angle());
> 
> Are these angles in the correct units (radians vs. degrees)?

Both of them are in degrees.

>> Source/WebCore/rendering/style/RenderStyle.h:649
>> +    bool hasTransform() const { return !m_rareNonInheritedData->transform->operations.operations().isEmpty() || offsetPath(); }
> 
> This makes me think that we need to examine all callers of hasTransformRelatedProperty() to see if they need offsetPath handling.

Most certainly. I did try to go through every caller of hasTransform(), but I get overwhelmed rather quickly.
Comment 5 Kiet Ho 2021-11-18 16:13:48 PST
Created attachment 444752 [details]
Patch
Comment 6 Kiet Ho 2021-11-19 06:59:56 PST
Created attachment 444816 [details]
Patch
Comment 7 Radar WebKit Bug Importer 2021-11-19 11:06:48 PST
<rdar://problem/85611888>
Comment 8 Dean Jackson 2021-11-19 13:52:44 PST
Comment on attachment 444816 [details]
Patch

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

> Source/WebCore/rendering/style/RenderStyle.cpp:1468
> +    // FIXME: support Reference and Box type.

Can you file a bugzilla for this and mention it here?

> Source/WebCore/rendering/style/RenderStyle.cpp:1505
> +    // Default value of offset-anchor is transform-origin

Nit: This comment should end with a period. However, I don't think you need the comment anyway :)

> Source/WebCore/rendering/style/RenderStyle.cpp:1507
> +    // Handle the case if offset-anchor is not auto

Same with this. The comment isn't necessary.
Comment 9 Kiet Ho 2021-11-19 14:03:10 PST
Created attachment 444851 [details]
Patch
Comment 10 EWS 2021-11-19 16:49:28 PST
Committed r286085 (244472@main): <https://commits.webkit.org/244472@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 444851 [details].