Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
#ifndef mozilla_MotionPathUtils_h
#define mozilla_MotionPathUtils_h
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/Maybe.h"
#include "mozilla/ServoStyleConsts.h"
#include "Units.h"
class nsIFrame;
namespace nsStyleTransformMatrix {
class TransformReferenceBox;
namespace mozilla {
using RayFunction = StyleRayFunction<StyleAngle>;
namespace layers {
class MotionPathData;
class PathCommand;
} // namespace layers
struct ResolvedMotionPathData {
gfx::Point mTranslate;
float mRotate;
// The delta value between transform-origin and offset-anchor.
gfx::Point mShift;
struct RayReferenceData {
// The initial position related to the containing block.
CSSPoint mInitialPosition;
// The rect of the containing block.
CSSRect mContainingBlockRect;
RayReferenceData() = default;
explicit RayReferenceData(const nsIFrame* aFrame);
bool operator==(const RayReferenceData& aOther) const {
return mInitialPosition == aOther.mInitialPosition &&
mContainingBlockRect == aOther.mContainingBlockRect;
// The collected information for offset-path. We preprocess the value of
// offset-path and use this data for resolving motion path.
struct OffsetPathData {
enum class Type : uint8_t {
struct PathData {
RefPtr<gfx::Path> mGfxPath;
bool mIsClosedIntervals;
struct RayData {
const RayFunction* mRay;
RayReferenceData mData;
Type mType;
union {
PathData mPath;
RayData mRay;
static OffsetPathData None() { return OffsetPathData(); }
static OffsetPathData Path(const StyleSVGPathData& aPath,
already_AddRefed<gfx::Path>&& aGfxPath) {
const auto& path = aPath._0.AsSpan();
return OffsetPathData(std::move(aGfxPath),
!path.empty() && path.rbegin()->IsClosePath());
static OffsetPathData Ray(const RayFunction& aRay,
const RayReferenceData& aData) {
return OffsetPathData(&aRay, aData);
static OffsetPathData Ray(const RayFunction& aRay, RayReferenceData&& aData) {
return OffsetPathData(&aRay, std::move(aData));
bool IsNone() const { return mType == Type::None; }
bool IsPath() const { return mType == Type::Path; }
bool IsRay() const { return mType == Type::Ray; }
const PathData& AsPath() const {
return mPath;
const RayData& AsRay() const {
return mRay;
~OffsetPathData() {
switch (mType) {
case Type::Path:
case Type::Ray:
OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) {
switch (mType) {
case Type::Path:
mPath = aOther.mPath;
case Type::Ray:
mRay = aOther.mRay;
OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) {
switch (mType) {
case Type::Path:
mPath = std::move(aOther.mPath);
case Type::Ray:
mRay = std::move(aOther.mRay);
OffsetPathData() : mType(Type::None) {}
OffsetPathData(already_AddRefed<gfx::Path>&& aPath, bool aIsClosed)
: mType(Type::Path), mPath{std::move(aPath), aIsClosed} {}
OffsetPathData(const RayFunction* aRay, RayReferenceData&& aRef)
: mType(Type::Ray), mRay{aRay, std::move(aRef)} {}
OffsetPathData(const RayFunction* aRay, const RayReferenceData& aRef)
: mType(Type::Ray), mRay{aRay, aRef} {}
OffsetPathData& operator=(const OffsetPathData&) = delete;
OffsetPathData& operator=(OffsetPathData&&) = delete;
// MotionPathUtils is a namespace class containing utility functions related to
// processing motion path in the [motion-1].
class MotionPathUtils final {
using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox;
// SVG frames (unlike other frames) have a reference box that can be (and
// typically is) offset from the TopLeft() of the frame.
// In motion path, we have to make sure the object is aligned with offset-path
// when using content area, so we should tweak the anchor point by a given
// offset.
static CSSPoint ComputeAnchorPointAdjustment(const nsIFrame& aFrame);
* Generate the motion path transform result. This function may be called on
* the compositor thread.
static Maybe<ResolvedMotionPathData> ResolveMotionPath(
const OffsetPathData& aPath, const LengthPercentage& aDistance,
const StyleOffsetRotate& aRotate, const StylePositionOrAuto& aAnchor,
const CSSPoint& aTransformOrigin, TransformReferenceBox&,
const CSSPoint& aAnchorPointAdjustment);
* Generate the motion path transform result with |nsIFrame|. This is only
* called in the main thread.
static Maybe<ResolvedMotionPathData> ResolveMotionPath(
const nsIFrame* aFrame, TransformReferenceBox&);
* Generate the motion path transfrom result with styles and
* layers::MotionPathData.
* This is only called by the compositor.
static Maybe<ResolvedMotionPathData> ResolveMotionPath(
const StyleOffsetPath* aPath, const StyleLengthPercentage* aDistance,
const StyleOffsetRotate* aRotate, const StylePositionOrAuto* aAnchor,
const Maybe<layers::MotionPathData>& aMotionPathData,
TransformReferenceBox&, gfx::Path* aCachedMotionPath);
* Normalize StyleSVGPathData.
* The algorithm of normalization is the same as normalize() in
* servo/components/style/values/specified/
* FIXME: Bug 1489392: We don't have to normalize the path here if we accept
* the spec issue which would like to normalize svg paths at computed time.
static StyleSVGPathData NormalizeSVGPathData(const StyleSVGPathData& aPath);
* Build a gfx::Path from the computed svg path. We should give it a path
* builder. If |aPathBuilder| is nullptr, we return null path.
* */
static already_AddRefed<gfx::Path> BuildPath(const StyleSVGPathData& aPath,
gfx::PathBuilder* aPathBuilder);
* Get a path builder for compositor.
static already_AddRefed<gfx::PathBuilder> GetCompositorPathBuilder();
} // namespace mozilla
#endif // mozilla_MotionPathUtils_h