264 lines
8.7 KiB
C++
264 lines
8.7 KiB
C++
/* -*- 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 http://mozilla.org/MPL/2.0/. */
|
||
|
||
#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 {
|
||
|
||
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;
|
||
};
|
||
|
||
// 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 {
|
||
None,
|
||
Shape,
|
||
Ray,
|
||
};
|
||
|
||
struct ShapeData {
|
||
RefPtr<gfx::Path> mGfxPath;
|
||
// The current position of this transfromed box in the coordinate system of
|
||
// its containing block.
|
||
nsPoint mCurrentPosition;
|
||
// True if it is a closed loop; false if it is a unclosed interval.
|
||
// https://drafts.fxtf.org/motion/#path-distance
|
||
bool mIsClosedLoop;
|
||
};
|
||
|
||
struct RayData {
|
||
const StyleRayFunction* mRay;
|
||
// The coord box of the containing block.
|
||
nsRect mCoordBox;
|
||
// The current position of this transfromed box in the coordinate system of
|
||
// its containing block.
|
||
nsPoint mCurrentPosition;
|
||
// The reference length for computing ray(contain).
|
||
CSSCoord mContainReferenceLength;
|
||
};
|
||
|
||
Type mType;
|
||
union {
|
||
ShapeData mShape;
|
||
RayData mRay;
|
||
};
|
||
|
||
static OffsetPathData None() { return OffsetPathData(); }
|
||
static OffsetPathData Shape(already_AddRefed<gfx::Path>&& aGfxPath,
|
||
nsPoint&& aCurrentPosition, bool aIsClosedPath) {
|
||
return OffsetPathData(std::move(aGfxPath), std::move(aCurrentPosition),
|
||
aIsClosedPath);
|
||
}
|
||
static OffsetPathData Ray(const StyleRayFunction& aRay, nsRect&& aCoordBox,
|
||
nsPoint&& aPosition,
|
||
CSSCoord&& aContainReferenceLength) {
|
||
return OffsetPathData(&aRay, std::move(aCoordBox), std::move(aPosition),
|
||
std::move(aContainReferenceLength));
|
||
}
|
||
static OffsetPathData Ray(const StyleRayFunction& aRay,
|
||
const nsRect& aCoordBox, const nsPoint& aPosition,
|
||
const CSSCoord& aContainReferenceLength) {
|
||
return OffsetPathData(&aRay, aCoordBox, aPosition, aContainReferenceLength);
|
||
}
|
||
|
||
bool IsNone() const { return mType == Type::None; }
|
||
bool IsShape() const { return mType == Type::Shape; }
|
||
bool IsRay() const { return mType == Type::Ray; }
|
||
|
||
const ShapeData& AsShape() const {
|
||
MOZ_ASSERT(IsShape());
|
||
return mShape;
|
||
}
|
||
|
||
const RayData& AsRay() const {
|
||
MOZ_ASSERT(IsRay());
|
||
return mRay;
|
||
}
|
||
|
||
~OffsetPathData() {
|
||
switch (mType) {
|
||
case Type::Shape:
|
||
mShape.~ShapeData();
|
||
break;
|
||
case Type::Ray:
|
||
mRay.~RayData();
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) {
|
||
switch (mType) {
|
||
case Type::Shape:
|
||
mShape = aOther.mShape;
|
||
break;
|
||
case Type::Ray:
|
||
mRay = aOther.mRay;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) {
|
||
switch (mType) {
|
||
case Type::Shape:
|
||
mShape = std::move(aOther.mShape);
|
||
break;
|
||
case Type::Ray:
|
||
mRay = std::move(aOther.mRay);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
private:
|
||
OffsetPathData() : mType(Type::None) {}
|
||
OffsetPathData(already_AddRefed<gfx::Path>&& aPath,
|
||
nsPoint&& aCurrentPosition, bool aIsClosed)
|
||
: mType(Type::Shape),
|
||
mShape{std::move(aPath), std::move(aCurrentPosition), aIsClosed} {}
|
||
OffsetPathData(const StyleRayFunction* aRay, nsRect&& aCoordBox,
|
||
nsPoint&& aPosition, CSSCoord&& aContainReferenceLength)
|
||
: mType(Type::Ray),
|
||
mRay{aRay, std::move(aCoordBox), std::move(aPosition),
|
||
std::move(aContainReferenceLength)} {}
|
||
OffsetPathData(const StyleRayFunction* aRay, const nsRect& aCoordBox,
|
||
const nsPoint& aPosition,
|
||
const CSSCoord& aContainReferenceLength)
|
||
: mType(Type::Ray),
|
||
mRay{aRay, aCoordBox, aPosition, aContainReferenceLength} {}
|
||
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].
|
||
// https://drafts.fxtf.org/motion-1/
|
||
class MotionPathUtils final {
|
||
using TransformReferenceBox = nsStyleTransformMatrix::TransformReferenceBox;
|
||
|
||
public:
|
||
/**
|
||
* 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);
|
||
|
||
/**
|
||
* In CSS context, this returns the the box being referenced from the element
|
||
* that establishes the containing block for this element.
|
||
* In SVG context, we always use view-box.
|
||
* https://drafts.fxtf.org/motion-1/#valdef-offset-path-coord-box
|
||
*/
|
||
static const nsIFrame* GetOffsetPathReferenceBox(const nsIFrame* aFrame,
|
||
nsRect& aOutputRect);
|
||
|
||
/**
|
||
* Return the width or the height of the element’s border box, whichever is
|
||
* larger. This is for computing the ray() with "contain" keyword.
|
||
*/
|
||
static CSSCoord GetRayContainReferenceSize(nsIFrame* aFrame);
|
||
|
||
/**
|
||
* Get the resolved radius for inset(0 round X), where X is the parameter of
|
||
* |aRadius|.
|
||
* This returns an empty array if we cannot compute the radii; otherwise, it
|
||
* returns an array with 8 elements.
|
||
*/
|
||
static nsTArray<nscoord> ComputeBorderRadii(
|
||
const StyleBorderRadius& aBorderRadius, const nsRect& aCoordBox);
|
||
|
||
/**
|
||
* 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 StyleOffsetPosition& aPosition, 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 StyleOffsetPosition* aPosition,
|
||
const Maybe<layers::MotionPathData>& aMotionPathData,
|
||
TransformReferenceBox&, gfx::Path* aCachedMotionPath);
|
||
|
||
/**
|
||
* Build a gfx::Path from the svg path data. We should give it a path builder.
|
||
* If |aPathBuilder| is nullptr, we return null path.
|
||
* This can be used on the main thread or on the compositor thread.
|
||
*/
|
||
static already_AddRefed<gfx::Path> BuildSVGPath(
|
||
const StyleSVGPathData& aPath, gfx::PathBuilder* aPathBuilder);
|
||
|
||
/**
|
||
* Build a gfx::Path from the computed basic shape.
|
||
*/
|
||
static already_AddRefed<gfx::Path> BuildPath(const StyleBasicShape&,
|
||
const StyleOffsetPosition&,
|
||
const nsRect& aCoordBox,
|
||
const nsPoint& aCurrentPosition,
|
||
gfx::PathBuilder*);
|
||
|
||
/**
|
||
* Get a path builder for motion path on the main thread.
|
||
*/
|
||
static already_AddRefed<gfx::PathBuilder> GetPathBuilder();
|
||
|
||
/**
|
||
* Get a path builder for compositor.
|
||
*/
|
||
static already_AddRefed<gfx::PathBuilder> GetCompositorPathBuilder();
|
||
};
|
||
|
||
} // namespace mozilla
|
||
|
||
#endif // mozilla_MotionPathUtils_h
|