Source code

Revision control

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 http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_MotionPathUtils_h
#define mozilla_MotionPathUtils_h
#include "mozilla/gfx/Point.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 {
None,
Path,
Ray,
};
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 {
MOZ_ASSERT(IsPath());
return mPath;
}
const RayData& AsRay() const {
MOZ_ASSERT(IsRay());
return mRay;
}
~OffsetPathData() {
switch (mType) {
case Type::Path:
mPath.~PathData();
break;
case Type::Ray:
mRay.~RayData();
break;
default:
break;
}
}
OffsetPathData(const OffsetPathData& aOther) : mType(aOther.mType) {
switch (mType) {
case Type::Path:
mPath = aOther.mPath;
break;
case Type::Ray:
mRay = aOther.mRay;
break;
default:
break;
}
}
OffsetPathData(OffsetPathData&& aOther) : mType(aOther.mType) {
switch (mType) {
case Type::Path:
mPath = std::move(aOther.mPath);
break;
case Type::Ray:
mRay = std::move(aOther.mRay);
break;
default:
break;
}
}
private:
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;
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);
/**
* 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/svg_path.rs
* 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