⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286085 in webkit


Ignore:
Timestamp:
Nov 19, 2021, 4:49:21 PM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Integrate motion path transforms in transformation pipeline
https://bugs.webkit.org/show_bug.cgi?id=233144

Patch by Kiet Ho <Kiet Ho> on 2021-11-19
Reviewed by Dean Jackson.

Source/WebCore:

This patch ties everything together and renders CSS Motion Path out onto the screen.
Motion path properties are desugared into two transformations: one translate to move
the element to the specified location on the path, and one rotate to rotate the element
to the correct orientation specified by offset-rotate. The two transformations are applied
after scale() and before the individual transform functions, as specified in the CSS
Transforms spec.

Tests: imported/w3c/web-platform-tests/css/motion/animation/reftests/offset-path-with-transforms-001.html

imported/w3c/web-platform-tests/css/motion/offset-distance-001.html
imported/w3c/web-platform-tests/css/motion/offset-distance-002.html
imported/w3c/web-platform-tests/css/motion/offset-distance-003.html
imported/w3c/web-platform-tests/css/motion/offset-distance-004.html
imported/w3c/web-platform-tests/css/motion/offset-distance-005.html
imported/w3c/web-platform-tests/css/motion/offset-distance-006.html
imported/w3c/web-platform-tests/css/motion/offset-distance-007.html
imported/w3c/web-platform-tests/css/motion/offset-distance-008.html
imported/w3c/web-platform-tests/css/motion/offset-distance-009.html
imported/w3c/web-platform-tests/css/motion/offset-path-string-001.html
imported/w3c/web-platform-tests/css/motion/offset-path-string-002.html
imported/w3c/web-platform-tests/css/motion/offset-rotate-003.html
imported/w3c/web-platform-tests/css/motion/offset-rotate-004.html
imported/w3c/web-platform-tests/css/motion/offset-rotate-005.html

  • platform/graphics/Path.cpp:

(WebCore::Path::isClosed const): Added method to determine if a Path is closed (i.e,
the last draw command is CloseSubpath). This is required because offset-distance is
handled differently depending on if the Path is closed or not.

  • platform/graphics/Path.h:
  • rendering/RenderLayerCompositor.cpp:

(WebCore::recompositeChangeRequiresGeometryUpdate): Account in changes in motion path properties.

  • rendering/RenderObject.h:

(WebCore::RenderObject::hasTransform const): Account in motion path properties.

  • rendering/style/RenderStyle.cpp:

(WebCore::rareNonInheritedDataChangeRequiresLayout):
(WebCore::RenderStyle::applyTransform const): Add an additional step to apply motion path transforms.
(WebCore::getPathFromPathOperation):
(WebCore::getTraversalStateAtDistance):
(WebCore::RenderStyle::applyMotionPathTransform const): Added method to apply motion path transforms.

  • rendering/style/RenderStyle.h:

(WebCore::RenderStyle::hasTransform const): Account for motion path properties.

LayoutTests:

Removed ImageOnlyFailure expectations for tests that should now pass.

Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r286064 r286085  
     12021-11-19  Kiet Ho  <tho22@apple.com>
     2
     3        Integrate motion path transforms in transformation pipeline
     4        https://bugs.webkit.org/show_bug.cgi?id=233144
     5
     6        Reviewed by Dean Jackson.
     7
     8        Removed ImageOnlyFailure expectations for tests that should now pass.
     9
     10        * TestExpectations:
     11
    1122021-11-19  Antti Koivisto  <antti@apple.com>
    213
  • trunk/LayoutTests/TestExpectations

    r286011 r286085  
    50905090imported/w3c/web-platform-tests/html/semantics/forms/the-textarea-element/placeholder-white-space.tentative.html [ ImageOnlyFailure ]
    50915091
    5092 # CSS motion path tests, currently failing.
    5093 imported/w3c/web-platform-tests/css/motion/animation/reftests/offset-path-with-transforms-001.html [ ImageOnlyFailure ]
    5094 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-001.html [ ImageOnlyFailure ]
    5095 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-002.html [ ImageOnlyFailure ]
    5096 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-003.html [ ImageOnlyFailure ]
    5097 imported/w3c/web-platform-tests/css/motion/offset-distance-001.html [ ImageOnlyFailure ]
    5098 imported/w3c/web-platform-tests/css/motion/offset-distance-002.html [ ImageOnlyFailure ]
    5099 imported/w3c/web-platform-tests/css/motion/offset-distance-003.html [ ImageOnlyFailure ]
    5100 imported/w3c/web-platform-tests/css/motion/offset-distance-004.html [ ImageOnlyFailure ]
    5101 imported/w3c/web-platform-tests/css/motion/offset-distance-005.html [ ImageOnlyFailure ]
    5102 imported/w3c/web-platform-tests/css/motion/offset-distance-006.html [ ImageOnlyFailure ]
    5103 imported/w3c/web-platform-tests/css/motion/offset-distance-007.html [ ImageOnlyFailure ]
    5104 imported/w3c/web-platform-tests/css/motion/offset-distance-008.html [ ImageOnlyFailure ]
    5105 imported/w3c/web-platform-tests/css/motion/offset-distance-009.html [ ImageOnlyFailure ]
    5106 imported/w3c/web-platform-tests/css/motion/offset-path-ray-001.html [ ImageOnlyFailure ]
    5107 imported/w3c/web-platform-tests/css/motion/offset-path-ray-002.html [ ImageOnlyFailure ]
    5108 imported/w3c/web-platform-tests/css/motion/offset-path-ray-003.html [ ImageOnlyFailure ]
    5109 imported/w3c/web-platform-tests/css/motion/offset-path-ray-004.html [ ImageOnlyFailure ]
    5110 imported/w3c/web-platform-tests/css/motion/offset-path-ray-005.html [ ImageOnlyFailure ]
    5111 imported/w3c/web-platform-tests/css/motion/offset-path-ray-006.html [ ImageOnlyFailure ]
    5112 imported/w3c/web-platform-tests/css/motion/offset-path-ray-007.html [ ImageOnlyFailure ]
    5113 imported/w3c/web-platform-tests/css/motion/offset-path-ray-008.html [ ImageOnlyFailure ]
    5114 imported/w3c/web-platform-tests/css/motion/offset-path-ray-009.html [ ImageOnlyFailure ]
    5115 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-001.html [ ImageOnlyFailure ]
    5116 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-002.html [ ImageOnlyFailure ]
    5117 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-003.html [ ImageOnlyFailure ]
    5118 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-004.html [ ImageOnlyFailure ]
    5119 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-005.html [ ImageOnlyFailure ]
    5120 imported/w3c/web-platform-tests/css/motion/offset-path-string-001.html [ ImageOnlyFailure ]
    5121 imported/w3c/web-platform-tests/css/motion/offset-path-string-002.html [ ImageOnlyFailure ]
    5122 imported/w3c/web-platform-tests/css/motion/offset-rotate-001.html [ ImageOnlyFailure ]
    5123 imported/w3c/web-platform-tests/css/motion/offset-rotate-002.html [ ImageOnlyFailure ]
    5124 imported/w3c/web-platform-tests/css/motion/offset-rotate-003.html [ ImageOnlyFailure ]
    5125 imported/w3c/web-platform-tests/css/motion/offset-rotate-004.html [ ImageOnlyFailure ]
    5126 imported/w3c/web-platform-tests/css/motion/offset-rotate-005.html [ ImageOnlyFailure ]
     5092# CSS motion path tests failing for unknown reasons, needs investigation.
     5093webkit.org/b/233340 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-001.html [ ImageOnlyFailure ]
     5094webkit.org/b/233340 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-002.html [ ImageOnlyFailure ]
     5095webkit.org/b/233340 imported/w3c/web-platform-tests/css/motion/offset-anchor-transform-box-fill-box-003.html [ ImageOnlyFailure ]
     5096
     5097# CSS motion path that depends on ray(), currently not implemented.
     5098webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-001.html [ ImageOnlyFailure ]
     5099webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-002.html [ ImageOnlyFailure ]
     5100webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-003.html [ ImageOnlyFailure ]
     5101webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-004.html [ ImageOnlyFailure ]
     5102webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-005.html [ ImageOnlyFailure ]
     5103webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-006.html [ ImageOnlyFailure ]
     5104webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-007.html [ ImageOnlyFailure ]
     5105webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-008.html [ ImageOnlyFailure ]
     5106webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-009.html [ ImageOnlyFailure ]
     5107webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-001.html [ ImageOnlyFailure ]
     5108webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-002.html [ ImageOnlyFailure ]
     5109webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-003.html [ ImageOnlyFailure ]
     5110webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-004.html [ ImageOnlyFailure ]
     5111webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-path-ray-contain-005.html [ ImageOnlyFailure ]
     5112webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-rotate-001.html [ ImageOnlyFailure ]
     5113webkit.org/b/233344 imported/w3c/web-platform-tests/css/motion/offset-rotate-002.html [ ImageOnlyFailure ]
    51275114
    51285115# IPC test failing in Debug mode due to assert.
  • trunk/Source/WebCore/ChangeLog

    r286084 r286085  
     12021-11-19  Kiet Ho  <tho22@apple.com>
     2
     3        Integrate motion path transforms in transformation pipeline
     4        https://bugs.webkit.org/show_bug.cgi?id=233144
     5
     6        Reviewed by Dean Jackson.
     7
     8        This patch ties everything together and renders CSS Motion Path out onto the screen.
     9        Motion path properties are desugared into two transformations: one translate to move
     10        the element to the specified location on the path, and one rotate to rotate the element
     11        to the correct orientation specified by offset-rotate. The two transformations are applied
     12        after scale() and before the individual transform functions, as specified in the CSS
     13        Transforms spec.
     14
     15        Tests: imported/w3c/web-platform-tests/css/motion/animation/reftests/offset-path-with-transforms-001.html
     16               imported/w3c/web-platform-tests/css/motion/offset-distance-001.html
     17               imported/w3c/web-platform-tests/css/motion/offset-distance-002.html
     18               imported/w3c/web-platform-tests/css/motion/offset-distance-003.html
     19               imported/w3c/web-platform-tests/css/motion/offset-distance-004.html
     20               imported/w3c/web-platform-tests/css/motion/offset-distance-005.html
     21               imported/w3c/web-platform-tests/css/motion/offset-distance-006.html
     22               imported/w3c/web-platform-tests/css/motion/offset-distance-007.html
     23               imported/w3c/web-platform-tests/css/motion/offset-distance-008.html
     24               imported/w3c/web-platform-tests/css/motion/offset-distance-009.html
     25               imported/w3c/web-platform-tests/css/motion/offset-path-string-001.html
     26               imported/w3c/web-platform-tests/css/motion/offset-path-string-002.html
     27               imported/w3c/web-platform-tests/css/motion/offset-rotate-003.html
     28               imported/w3c/web-platform-tests/css/motion/offset-rotate-004.html
     29               imported/w3c/web-platform-tests/css/motion/offset-rotate-005.html
     30
     31        * platform/graphics/Path.cpp:
     32        (WebCore::Path::isClosed const): Added method to determine if a Path is closed (i.e,
     33        the last draw command is CloseSubpath). This is required because offset-distance is
     34        handled differently depending on if the Path is closed or not.
     35        * platform/graphics/Path.h:
     36        * rendering/RenderLayerCompositor.cpp:
     37        (WebCore::recompositeChangeRequiresGeometryUpdate): Account in changes in motion path properties.
     38        * rendering/RenderObject.h:
     39        (WebCore::RenderObject::hasTransform const): Account in motion path properties.
     40        * rendering/style/RenderStyle.cpp:
     41        (WebCore::rareNonInheritedDataChangeRequiresLayout):
     42        (WebCore::RenderStyle::applyTransform const): Add an additional step to apply motion path transforms.
     43        (WebCore::getPathFromPathOperation):
     44        (WebCore::getTraversalStateAtDistance):
     45        (WebCore::RenderStyle::applyMotionPathTransform const): Added method to apply motion path transforms.
     46        * rendering/style/RenderStyle.h:
     47        (WebCore::RenderStyle::hasTransform const): Account for motion path properties.
     48
    1492021-11-19  Alex Christensen  <achristensen@webkit.org>
    250
  • trunk/Source/WebCore/platform/graphics/Path.cpp

    r284095 r286085  
    276276}
    277277
     278bool Path::isClosed() const
     279{
     280    bool lastElementIsClosed = false;
     281
     282    // The path is closed if the type of the last PathElement is CloseSubpath. Unfortunately,
     283    // the only way to access PathElements is sequentially through apply(), there's no random
     284    // access as if they're in a vector.
     285    // The lambda below sets lastElementIsClosed if the last PathElement is CloseSubpath.
     286    // Because lastElementIsClosed is overridden if there are any remaining PathElements
     287    // to be iterated, its final value is the value of the last iteration.
     288    // (i.e the last PathElement).
     289    // FIXME: find a more efficient way to implement this, that does not require iterating
     290    // through all PathElements.
     291    apply([&lastElementIsClosed](const WebCore::PathElement& element) {
     292        lastElementIsClosed = (element.type == PathElement::Type::CloseSubpath);
     293    });
     294
     295    return lastElementIsClosed;
     296}
     297
    278298size_t Path::elementCount() const
    279299{
  • trunk/Source/WebCore/platform/graphics/Path.h

    r284857 r286085  
    161161    FloatPoint currentPoint() const;
    162162
     163    bool isClosed() const;
     164
    163165    WEBCORE_EXPORT void moveTo(const FloatPoint&);
    164166    WEBCORE_EXPORT void addLineTo(const FloatPoint&);
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r285316 r286085  
    16481648        || oldStyle.perspectiveOriginY() != newStyle.perspectiveOriginY()
    16491649        || oldStyle.backfaceVisibility() != newStyle.backfaceVisibility()
     1650        || !arePointingToEqualData(oldStyle.offsetPath(), newStyle.offsetPath())
     1651        || oldStyle.offsetAnchor() != newStyle.offsetAnchor()
     1652        || oldStyle.offsetPosition() != newStyle.offsetPosition()
     1653        || oldStyle.offsetDistance() != newStyle.offsetDistance()
     1654        || oldStyle.offsetRotate() != newStyle.offsetRotate()
    16501655        || !arePointingToEqualData(oldStyle.clipPath(), newStyle.clipPath());
    16511656}
  • trunk/Source/WebCore/rendering/RenderObject.h

    r285885 r286085  
    445445
    446446    bool hasTransformRelatedProperty() const { return m_bitfields.hasTransformRelatedProperty(); } // Transform, perspective or transform-style: preserve-3d.
    447     bool hasTransform() const { return hasTransformRelatedProperty() && (style().hasTransform() || style().translate() || style().scale() || style().rotate()); }
     447    bool hasTransform() const { return hasTransformRelatedProperty() && (style().hasTransform() || style().translate() || style().scale() || style().rotate() || style().offsetPath()); }
    448448
    449449    inline bool preservesNewline() const;
  • trunk/Source/WebCore/rendering/style/RenderStyle.cpp

    r285615 r286085  
    3737#include "InlineTextBoxStyle.h"
    3838#include "Pagination.h"
     39#include "PathTraversalState.h"
    3940#include "QuotesData.h"
    4041#include "RenderBlock.h"
     
    697698        || !arePointingToEqualData(first.rotate, second.rotate)
    698699        || !arePointingToEqualData(first.translate, second.translate))
     700        changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Transform);
     701
     702    if (!arePointingToEqualData(first.offsetPath, second.offsetPath)
     703        || first.offsetPosition != second.offsetPosition
     704        || first.offsetDistance != second.offsetDistance
     705        || first.offsetAnchor != second.offsetAnchor
     706        || first.offsetRotate != second.offsetRotate)
    699707        changedContextSensitiveProperties.add(StyleDifferenceContextSensitiveProperty::Transform);
    700708
     
    14081416
    14091417    auto& transformOperations = m_rareNonInheritedData->transform->operations;
    1410     bool applyTransformOrigin = options.contains(RenderStyle::TransformOperationOption::TransformOrigin) && ((m_rareNonInheritedData->rotate && !m_rareNonInheritedData->rotate->isIdentity()) || (m_rareNonInheritedData->scale && !m_rareNonInheritedData->scale->isIdentity()) || transformOperations.affectedByTransformOrigin());
     1418    bool applyTransformOrigin = options.contains(RenderStyle::TransformOperationOption::TransformOrigin)
     1419        && ((m_rareNonInheritedData->rotate && !m_rareNonInheritedData->rotate->isIdentity())
     1420            || (m_rareNonInheritedData->scale && !m_rareNonInheritedData->scale->isIdentity())
     1421            || transformOperations.affectedByTransformOrigin()
     1422            || offsetPath());
    14111423
    14121424    // 2. Translate by the computed X, Y, and Z values of transform-origin.
     
    14361448    }
    14371449
    1438     // 6. Translate and rotate by the transform specified by offset. (FIXME: we don't support the offset property)
     1450    // 6. Translate and rotate by the transform specified by offset.
     1451    if (options.contains(RenderStyle::TransformOperationOption::Offset))
     1452        applyMotionPathTransform(transform, boundingBox);
    14391453
    14401454    // 7. Multiply by each of the transform functions in transform from left to right.
     
    14451459    if (applyTransformOrigin)
    14461460        transform.translate3d(-originTranslate.x(), -originTranslate.y(), -originTranslate.z());
     1461}
     1462
     1463static std::optional<Path> getPathFromPathOperation(const FloatRect& box, const PathOperation& operation)
     1464{
     1465    if (operation.type() == PathOperation::Shape)
     1466        return downcast<ShapePathOperation>(operation).pathForReferenceRect(box);
     1467
     1468    // FIXME: support Reference and Box type.
     1469    // https://bugs.webkit.org/show_bug.cgi?id=233382
     1470    return std::nullopt;
     1471}
     1472
     1473static PathTraversalState getTraversalStateAtDistance(const Path& path, const Length& distance)
     1474{
     1475    auto pathLength = path.length();
     1476    auto distanceValue = floatValueForLength(distance, pathLength);
     1477
     1478    float resolvedLength = 0;
     1479    if (path.isClosed()) {
     1480        if (pathLength) {
     1481            resolvedLength = fmod(distanceValue, pathLength);
     1482            if (resolvedLength < 0)
     1483                resolvedLength += pathLength;
     1484        }
     1485    } else
     1486        resolvedLength = clampTo<float>(distanceValue, 0, pathLength);
     1487
     1488    ASSERT(resolvedLength >= 0);
     1489    return path.traversalStateAtLength(resolvedLength);
     1490}
     1491
     1492void RenderStyle::applyMotionPathTransform(TransformationMatrix& transform, const FloatRect& boundingBox) const
     1493{
     1494    if (!offsetPath())
     1495        return;
     1496
     1497    // Shift element to the point on path specified by offset-path and offset-distance.
     1498    auto path = getPathFromPathOperation(boundingBox, *offsetPath());
     1499    if (!path)
     1500        return;
     1501    auto traversalState = getTraversalStateAtDistance(*path, offsetDistance());
     1502    transform.translate(traversalState.current().x(), traversalState.current().y());
     1503
     1504    // Shift element to the anchor specified by offset-anchor.
     1505    auto transformOrigin = floatPointForLengthPoint(transformOriginXY(), boundingBox.size()) + boundingBox.location();
     1506    auto anchor = transformOrigin;
     1507    if (!offsetAnchor().x().isAuto())
     1508        anchor = floatPointForLengthPoint(offsetAnchor(), boundingBox.size()) + boundingBox.location();
     1509    transform.translate(-anchor.x(), -anchor.y());
     1510
     1511    auto shiftToOrigin = anchor - transformOrigin;
     1512    transform.translate(shiftToOrigin.width(), shiftToOrigin.height());
     1513
     1514    // Apply rotation.
     1515    auto rotation = offsetRotate();
     1516    if (rotation.hasAuto())
     1517        transform.rotate(traversalState.normalAngle() + rotation.angle());
     1518    else
     1519        transform.rotate(rotation.angle());
     1520
     1521    transform.translate(-shiftToOrigin.width(), -shiftToOrigin.height());
    14471522}
    14481523
  • trunk/Source/WebCore/rendering/style/RenderStyle.h

    r285918 r286085  
    646646
    647647    const TransformOperations& transform() const { return m_rareNonInheritedData->transform->operations; }
    648     bool hasTransform() const { return !m_rareNonInheritedData->transform->operations.operations().isEmpty(); }
     648    bool hasTransform() const { return !m_rareNonInheritedData->transform->operations.operations().isEmpty() || offsetPath(); }
    649649    const Length& transformOriginX() const { return m_rareNonInheritedData->transform->x; }
    650650    const Length& transformOriginY() const { return m_rareNonInheritedData->transform->y; }
     
    685685        Translate       = 1 << 1,
    686686        Rotate          = 1 << 2,
    687         Scale           = 1 << 3
     687        Scale           = 1 << 3,
     688        Offset          = 1 << 4
    688689    };
    689690
    690     static constexpr OptionSet<TransformOperationOption> allTransformOperations = { TransformOperationOption::TransformOrigin, TransformOperationOption::Translate, TransformOperationOption::Rotate, TransformOperationOption::Scale };
    691     static constexpr OptionSet<TransformOperationOption> individualTransformOperations = { TransformOperationOption::Translate, TransformOperationOption::Rotate, TransformOperationOption::Scale };
     691    static constexpr OptionSet<TransformOperationOption> allTransformOperations = { TransformOperationOption::TransformOrigin, TransformOperationOption::Translate, TransformOperationOption::Rotate, TransformOperationOption::Scale , TransformOperationOption::Offset };
     692    static constexpr OptionSet<TransformOperationOption> individualTransformOperations = { TransformOperationOption::Translate, TransformOperationOption::Rotate, TransformOperationOption::Scale, TransformOperationOption::Offset };
    692693    void applyTransform(TransformationMatrix&, const FloatRect& boundingBox, OptionSet<TransformOperationOption> = allTransformOperations) const;
     694    void applyMotionPathTransform(TransformationMatrix&, const FloatRect& boundingBox) const;
    693695    void setPageScaleTransform(float);
    694696
Note: See TracChangeset for help on using the changeset viewer.