This commit is contained in:
Isaac 2024-05-17 00:20:40 +04:00
parent c9a651691a
commit 3a5585c1fd
10 changed files with 201 additions and 77 deletions

View File

@ -18,6 +18,35 @@ struct TransformedPath {
} }
}; };
static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) {
//TODO:remove skipApplyTransform
lottie::CATransform3D effectiveTransform = parentTransform;
if (!skipApplyTransform && item->isGroup) {
effectiveTransform = item->transform * effectiveTransform;
}
size_t maxSubitem = std::min(item->subItems.size(), subItemLimit);
lottie::CGRect boundingBox(0.0, 0.0, 0.0, 0.0);
if (item->path) {
boundingBox = item->pathBoundingBox.applyingTransform(effectiveTransform);
}
for (size_t i = 0; i < maxSubitem; i++) {
auto &subItem = item->subItems[i];
lottie::CGRect subItemBoundingBox = collectPathBoundingBoxes(subItem, INT32_MAX, effectiveTransform, false);
if (boundingBox.empty()) {
boundingBox = subItemBoundingBox;
} else {
boundingBox = boundingBox.unionWith(subItemBoundingBox);
}
}
return boundingBox;
}
static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) { static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) {
std::vector<TransformedPath> mappedPaths; std::vector<TransformedPath> mappedPaths;
@ -32,6 +61,7 @@ static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderT
if (item->path) { if (item->path) {
mappedPaths.emplace_back(item->path.value(), effectiveTransform); mappedPaths.emplace_back(item->path.value(), effectiveTransform);
} }
assert(!item->trimParams);
for (size_t i = 0; i < maxSubitem; i++) { for (size_t i = 0; i < maxSubitem; i++) {
auto &subItem = item->subItems[i]; auto &subItem = item->subItems[i];
@ -66,17 +96,8 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
int drawContentDescendants = 0; int drawContentDescendants = 0;
for (const auto &shadingVariant : contentItem->shadings) { for (const auto &shadingVariant : contentItem->shadings) {
std::vector<lottie::BezierPath> itemPaths; lottie::CGRect shapeBounds = collectPathBoundingBoxes(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true);
if (shadingVariant->explicitPath) {
itemPaths = shadingVariant->explicitPath.value();
} else {
auto rawPaths = collectPaths(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true);
for (const auto &rawPath : rawPaths) {
itemPaths.push_back(rawPath.path.copyUsingTransform(rawPath.transform));
}
}
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, itemPaths);
if (shadingVariant->stroke) { if (shadingVariant->stroke) {
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0); shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);
} else if (shadingVariant->fill) { } else if (shadingVariant->fill) {
@ -95,7 +116,8 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
} }
if (contentItem->isGroup) { if (contentItem->isGroup) {
for (const auto &subItem : contentItem->subItems) { for (auto it = contentItem->subItems.rbegin(); it != contentItem->subItems.rend(); it++) {
const auto &subItem = *it;
processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext); processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
if (subItem->renderData.isValid) { if (subItem->renderData.isValid) {
@ -491,7 +513,8 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
} }
} }
for (const auto &subItem : item->subItems) { for (auto it = item->subItems.rbegin(); it != item->subItems.rend(); it++) {
const auto &subItem = *it;
drawLottieContentItem(currentContext, subItem, renderAlpha); drawLottieContentItem(currentContext, subItem, renderAlpha);
} }

View File

@ -144,6 +144,7 @@ public:
CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths); CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths);
CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, std::vector<BezierPath> const &paths); CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, std::vector<BezierPath> const &paths);
CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, BezierPath const &path);
std::vector<BezierPath> trimBezierPaths(std::vector<BezierPath> &sourcePaths, double start, double end, double offset, TrimType type); std::vector<BezierPath> trimBezierPaths(std::vector<BezierPath> &sourcePaths, double start, double end, double offset, TrimType type);

View File

@ -424,6 +424,7 @@ public:
double alpha = 0.0; double alpha = 0.0;
std::optional<TrimParams> trimParams; std::optional<TrimParams> trimParams;
std::optional<BezierPath> path; std::optional<BezierPath> path;
CGRect pathBoundingBox = CGRect(0.0, 0.0, 0.0, 0.0);
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings; std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems; std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;

View File

@ -82,7 +82,7 @@ public:
return _contentsLayer; return _contentsLayer;
} }
void displayWithFrame(double frame, bool forceUpdates) { void displayWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) {
_transformNode->updateTree(frame, forceUpdates); _transformNode->updateTree(frame, forceUpdates);
bool layerVisible = isInRangeOrEqual(frame, _inFrame, _outFrame); bool layerVisible = isInRangeOrEqual(frame, _inFrame, _outFrame);
@ -93,14 +93,14 @@ public:
/// Only update contents if current time is within the layers time bounds. /// Only update contents if current time is within the layers time bounds.
if (layerVisible) { if (layerVisible) {
displayContentsWithFrame(frame, forceUpdates); displayContentsWithFrame(frame, forceUpdates, boundingBoxContext);
if (_maskLayer) { if (_maskLayer) {
_maskLayer->updateWithFrame(frame, forceUpdates); _maskLayer->updateWithFrame(frame, forceUpdates);
} }
} }
} }
virtual void displayContentsWithFrame(double frame, bool forceUpdates) { virtual void displayContentsWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) {
/// To be overridden by subclass /// To be overridden by subclass
} }
@ -151,11 +151,11 @@ public:
return _timeStretch; return _timeStretch;
} }
virtual std::shared_ptr<RenderTreeNode> renderTreeNode() { virtual std::shared_ptr<RenderTreeNode> renderTreeNode(BezierPathsBoundingBoxContext &boundingBoxContext) {
return nullptr; return nullptr;
} }
virtual void updateRenderTree() { virtual void updateRenderTree(BezierPathsBoundingBoxContext &boundingBoxContext) {
} }
public: public:

View File

@ -86,7 +86,7 @@ public:
return result; return result;
} }
virtual void displayContentsWithFrame(double frame, bool forceUpdates) override { virtual void displayContentsWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) override {
double localFrame = 0.0; double localFrame = 0.0;
if (_remappingNode) { if (_remappingNode) {
_remappingNode->update(frame); _remappingNode->update(frame);
@ -96,11 +96,11 @@ public:
} }
for (const auto &animationLayer : _animationLayers) { for (const auto &animationLayer : _animationLayers) {
animationLayer->displayWithFrame(localFrame, forceUpdates); animationLayer->displayWithFrame(localFrame, forceUpdates, boundingBoxContext);
} }
} }
virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override { virtual std::shared_ptr<RenderTreeNode> renderTreeNode(BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (!_renderTreeNode) { if (!_renderTreeNode) {
_contentsTreeNode = std::make_shared<RenderTreeNode>( _contentsTreeNode = std::make_shared<RenderTreeNode>(
CGRect(0.0, 0.0, 0.0, 0.0), CGRect(0.0, 0.0, 0.0, 0.0),
@ -120,7 +120,7 @@ public:
std::shared_ptr<RenderTreeNode> maskNode; std::shared_ptr<RenderTreeNode> maskNode;
bool invertMask = false; bool invertMask = false;
if (_matteLayer) { if (_matteLayer) {
maskNode = _matteLayer->renderTreeNode(); maskNode = _matteLayer->renderTreeNode(boundingBoxContext);
if (maskNode && _matteType.has_value() && _matteType.value() == MatteType::Invert) { if (maskNode && _matteType.has_value() && _matteType.value() == MatteType::Invert) {
invertMask = true; invertMask = true;
} }
@ -148,7 +148,7 @@ public:
} }
} }
if (found) { if (found) {
auto node = animationLayer->renderTreeNode(); auto node = animationLayer->renderTreeNode(boundingBoxContext);
if (node) { if (node) {
renderTreeSubnodes.push_back(node); renderTreeSubnodes.push_back(node);
} }
@ -177,9 +177,9 @@ public:
return _renderTreeNode; return _renderTreeNode;
} }
virtual void updateRenderTree() override { virtual void updateRenderTree(BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (_matteLayer) { if (_matteLayer) {
_matteLayer->updateRenderTree(); _matteLayer->updateRenderTree(boundingBoxContext);
} }
for (const auto &animationLayer : _animationLayers) { for (const auto &animationLayer : _animationLayers) {
@ -191,7 +191,7 @@ public:
} }
} }
if (found) { if (found) {
animationLayer->updateRenderTree(); animationLayer->updateRenderTree(boundingBoxContext);
} }
} }

View File

@ -506,8 +506,9 @@ public:
} }
virtual ~PathOutput() = default; virtual ~PathOutput() = default;
virtual void update(AnimationFrameTime frameTime) = 0; virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) = 0;
virtual BezierPath const *currentPath() = 0; virtual BezierPath const *currentPath() = 0;
virtual CGRect const &currentPathBounds() = 0;
}; };
class StaticPathOutput : public PathOutput { class StaticPathOutput : public PathOutput {
@ -516,15 +517,26 @@ public:
resolvedPath(path) { resolvedPath(path) {
} }
virtual void update(AnimationFrameTime frameTime) override { virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (!isPathBoundsResolved) {
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
isPathBoundsResolved = true;
}
} }
virtual BezierPath const *currentPath() override { virtual BezierPath const *currentPath() override {
return &resolvedPath; return &resolvedPath;
} }
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
}
private: private:
BezierPath resolvedPath; BezierPath resolvedPath;
bool isPathBoundsResolved = false;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
}; };
class ShapePathOutput : public PathOutput { class ShapePathOutput : public PathOutput {
@ -533,9 +545,10 @@ public:
path(shape.path.keyframes) { path(shape.path.keyframes) {
} }
virtual void update(AnimationFrameTime frameTime) override { virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (!hasValidData || path.hasUpdate(frameTime)) { if (!hasValidData || path.hasUpdate(frameTime)) {
path.update(frameTime, resolvedPath); path.update(frameTime, resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
} }
hasValidData = true; hasValidData = true;
@ -545,12 +558,17 @@ public:
return &resolvedPath; return &resolvedPath;
} }
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
}
private: private:
bool hasValidData = false; bool hasValidData = false;
BezierPathKeyframeInterpolator path; BezierPathKeyframeInterpolator path;
BezierPath resolvedPath; BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
}; };
class RectanglePathOutput : public PathOutput { class RectanglePathOutput : public PathOutput {
@ -562,7 +580,7 @@ public:
cornerRadius(rectangle.cornerRadius.keyframes) { cornerRadius(rectangle.cornerRadius.keyframes) {
} }
virtual void update(AnimationFrameTime frameTime) override { virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
bool hasUpdates = false; bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) { if (!hasValidData || position.hasUpdate(frameTime)) {
@ -580,6 +598,7 @@ public:
if (hasUpdates) { if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath); ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
} }
hasValidData = true; hasValidData = true;
@ -589,6 +608,10 @@ public:
return &resolvedPath; return &resolvedPath;
} }
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
}
private: private:
bool hasValidData = false; bool hasValidData = false;
@ -604,6 +627,7 @@ public:
double cornerRadiusValue = 0.0; double cornerRadiusValue = 0.0;
BezierPath resolvedPath; BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
}; };
class EllipsePathOutput : public PathOutput { class EllipsePathOutput : public PathOutput {
@ -614,7 +638,7 @@ public:
size(ellipse.size.keyframes) { size(ellipse.size.keyframes) {
} }
virtual void update(AnimationFrameTime frameTime) override { virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
bool hasUpdates = false; bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) { if (!hasValidData || position.hasUpdate(frameTime)) {
@ -628,6 +652,7 @@ public:
if (hasUpdates) { if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath); ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
} }
hasValidData = true; hasValidData = true;
@ -637,6 +662,10 @@ public:
return &resolvedPath; return &resolvedPath;
} }
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
}
private: private:
bool hasValidData = false; bool hasValidData = false;
@ -649,6 +678,7 @@ public:
Vector3D sizeValue = Vector3D(0.0, 0.0, 0.0); Vector3D sizeValue = Vector3D(0.0, 0.0, 0.0);
BezierPath resolvedPath; BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
}; };
class StarPathOutput : public PathOutput { class StarPathOutput : public PathOutput {
@ -673,7 +703,7 @@ public:
} }
} }
virtual void update(AnimationFrameTime frameTime) override { virtual void update(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) override {
bool hasUpdates = false; bool hasUpdates = false;
if (!hasValidData || position.hasUpdate(frameTime)) { if (!hasValidData || position.hasUpdate(frameTime)) {
@ -715,6 +745,7 @@ public:
if (hasUpdates) { if (hasUpdates) {
ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath); ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath);
resolvedPathBounds = bezierPathsBoundingBoxParallel(boundingBoxContext, resolvedPath);
} }
hasValidData = true; hasValidData = true;
@ -724,6 +755,10 @@ public:
return &resolvedPath; return &resolvedPath;
} }
virtual CGRect const &currentPathBounds() override {
return resolvedPathBounds;
}
private: private:
bool hasValidData = false; bool hasValidData = false;
@ -751,6 +786,7 @@ public:
double pointsValue = 0.0; double pointsValue = 0.0;
BezierPath resolvedPath; BezierPath resolvedPath;
CGRect resolvedPathBounds = CGRect(0.0, 0.0, 0.0, 0.0);
}; };
class TransformOutput { class TransformOutput {
@ -903,11 +939,7 @@ public:
std::shared_ptr<RenderTreeNodeContentItem> _contentItem; std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
private: private:
bool hasTrims(size_t subItemLimit) { std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform) {
return false;
}
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform, bool &hasTrims) {
std::vector<TransformedPath> mappedPaths; std::vector<TransformedPath> mappedPaths;
//TODO:remove skipApplyTransform //TODO:remove skipApplyTransform
@ -930,10 +962,9 @@ public:
currentTrim = trims[0]->trimParams(); currentTrim = trims[0]->trimParams();
} }
auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false, hasTrims); auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false);
if (currentTrim) { if (currentTrim) {
hasTrims = true;
CompoundBezierPath tempPath; CompoundBezierPath tempPath;
for (auto &path : subItemPaths) { for (auto &path : subItemPaths) {
tempPath.appendPath(path.path.copyUsingTransform(path.transform)); tempPath.appendPath(path.path.copyUsingTransform(path.transform));
@ -1007,23 +1038,22 @@ public:
if (isGroup && !subItems.empty()) { if (isGroup && !subItems.empty()) {
std::vector<std::shared_ptr<RenderTreeNode>> subItemNodes; std::vector<std::shared_ptr<RenderTreeNode>> subItemNodes;
for (int i = (int)subItems.size() - 1; i >= 0; i--) { for (const auto &subItem : subItems) {
subItems[i]->initializeRenderChildren(); subItem->initializeRenderChildren();
_contentItem->subItems.push_back(subItems[i]->_contentItem); _contentItem->subItems.push_back(subItem->_contentItem);
} }
} }
} }
public: public:
void updateFrame(AnimationFrameTime frameTime) { void updateFrame(AnimationFrameTime frameTime, BezierPathsBoundingBoxContext &boundingBoxContext) {
if (transform) { if (transform) {
transform->update(frameTime); transform->update(frameTime);
} }
if (path) { if (path) {
path->update(frameTime); path->update(frameTime, boundingBoxContext);
} else { _contentItem->pathBoundingBox = path->currentPathBounds();
_contentItem->path = std::nullopt;
} }
for (const auto &trim : trims) { for (const auto &trim : trims) {
trim->update(frameTime); trim->update(frameTime);
@ -1039,10 +1069,24 @@ public:
} }
for (const auto &subItem : subItems) { for (const auto &subItem : subItems) {
subItem->updateFrame(frameTime); subItem->updateFrame(frameTime, boundingBoxContext);
} }
} }
bool hasTrims() {
if (!trims.empty()) {
return true;
}
for (const auto &subItem : subItems) {
if (subItem->hasTrims()) {
return true;
}
}
return false;
}
void updateContents(std::optional<TrimParams> parentTrim) { void updateContents(std::optional<TrimParams> parentTrim) {
CATransform3D containerTransform = CATransform3D::identity(); CATransform3D containerTransform = CATransform3D::identity();
double containerOpacity = 1.0; double containerOpacity = 1.0;
@ -1053,6 +1097,10 @@ public:
_contentItem->transform = containerTransform; _contentItem->transform = containerTransform;
_contentItem->alpha = containerOpacity; _contentItem->alpha = containerOpacity;
if (!trims.empty()) {
_contentItem->trimParams = trims[0]->trimParams();
}
for (int i = 0; i < shadings.size(); i++) { for (int i = 0; i < shadings.size(); i++) {
const auto &shadingVariant = shadings[i]; const auto &shadingVariant = shadings[i];
@ -1066,11 +1114,9 @@ public:
currentTrim = trims[0]; currentTrim = trims[0];
}*/ }*/
bool hasTrims = false;
if (parentTrim) { if (parentTrim) {
CompoundBezierPath compoundPath; CompoundBezierPath compoundPath;
hasTrims = true; auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true);
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims);
for (const auto &path : paths) { for (const auto &path : paths) {
compoundPath.appendPath(path.path.copyUsingTransform(path.transform)); compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
} }
@ -1083,21 +1129,20 @@ public:
} }
_contentItem->shadings[i]->explicitPath = resultPaths; _contentItem->shadings[i]->explicitPath = resultPaths;
} else { } else {
CompoundBezierPath compoundPath; if (hasTrims()) {
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims); CompoundBezierPath compoundPath;
for (const auto &path : paths) { auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true);
compoundPath.appendPath(path.path.copyUsingTransform(path.transform)); for (const auto &path : paths) {
} compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
std::vector<BezierPath> resultPaths; }
for (const auto &path : compoundPath.paths) { std::vector<BezierPath> resultPaths;
resultPaths.push_back(path); for (const auto &path : compoundPath.paths) {
} resultPaths.push_back(path);
}
if (hasTrims) {
_contentItem->shadings[i]->explicitPath = resultPaths; _contentItem->shadings[i]->explicitPath = resultPaths;
} else { } else {
_contentItem->shadings[i]->explicitPath = std::nullopt; _contentItem->shadings[i]->explicitPath = std::nullopt;
_contentItem->shadings[i]->explicitPath = resultPaths;
} }
} }
} }
@ -1288,18 +1333,18 @@ CompositionLayer(solidLayer, Vector2D::Zero()) {
_contentTree = std::make_shared<ShapeLayerPresentationTree>(solidLayer); _contentTree = std::make_shared<ShapeLayerPresentationTree>(solidLayer);
} }
void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates) { void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) {
_frameTime = frame; _frameTime = frame;
_frameTimeInitialized = true; _frameTimeInitialized = true;
_contentTree->itemTree->updateFrame(_frameTime); _contentTree->itemTree->updateFrame(_frameTime, boundingBoxContext);
_contentTree->itemTree->updateContents(std::nullopt); _contentTree->itemTree->updateContents(std::nullopt);
} }
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() { std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode(BezierPathsBoundingBoxContext &boundingBoxContext) {
if (!_frameTimeInitialized) { if (!_frameTimeInitialized) {
_frameTime = 0.0; _frameTime = 0.0;
_frameTimeInitialized = true; _frameTimeInitialized = true;
_contentTree->itemTree->updateFrame(_frameTime); _contentTree->itemTree->updateFrame(_frameTime, boundingBoxContext);
_contentTree->itemTree->updateContents(std::nullopt); _contentTree->itemTree->updateContents(std::nullopt);
} }
@ -1324,7 +1369,7 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
std::shared_ptr<RenderTreeNode> maskNode; std::shared_ptr<RenderTreeNode> maskNode;
bool invertMask = false; bool invertMask = false;
if (_matteLayer) { if (_matteLayer) {
maskNode = _matteLayer->renderTreeNode(); maskNode = _matteLayer->renderTreeNode(boundingBoxContext);
if (maskNode && _matteType.has_value() && _matteType.value() == MatteType::Invert) { if (maskNode && _matteType.has_value() && _matteType.value() == MatteType::Invert) {
invertMask = true; invertMask = true;
} }
@ -1346,9 +1391,9 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
return _renderTreeNode; return _renderTreeNode;
} }
void ShapeCompositionLayer::updateRenderTree() { void ShapeCompositionLayer::updateRenderTree(BezierPathsBoundingBoxContext &boundingBoxContext) {
if (_matteLayer) { if (_matteLayer) {
_matteLayer->updateRenderTree(); _matteLayer->updateRenderTree(boundingBoxContext);
} }
_contentRenderTreeNode->_bounds = _contentsLayer->bounds(); _contentRenderTreeNode->_bounds = _contentsLayer->bounds();

View File

@ -16,9 +16,9 @@ public:
ShapeCompositionLayer(std::shared_ptr<ShapeLayerModel> const &shapeLayer); ShapeCompositionLayer(std::shared_ptr<ShapeLayerModel> const &shapeLayer);
ShapeCompositionLayer(std::shared_ptr<SolidLayerModel> const &solidLayer); ShapeCompositionLayer(std::shared_ptr<SolidLayerModel> const &solidLayer);
virtual void displayContentsWithFrame(double frame, bool forceUpdates) override; virtual void displayContentsWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) override;
virtual std::shared_ptr<RenderTreeNode> renderTreeNode() override; virtual std::shared_ptr<RenderTreeNode> renderTreeNode(BezierPathsBoundingBoxContext &boundingBoxContext) override;
virtual void updateRenderTree() override; virtual void updateRenderTree(BezierPathsBoundingBoxContext &boundingBoxContext) override;
private: private:
std::shared_ptr<ShapeLayerPresentationTree> _contentTree; std::shared_ptr<ShapeLayerPresentationTree> _contentTree;

View File

@ -42,7 +42,7 @@ public:
_fontProvider = fontProvider; _fontProvider = fontProvider;
} }
virtual void displayContentsWithFrame(double frame, bool forceUpdates) override { virtual void displayContentsWithFrame(double frame, bool forceUpdates, BezierPathsBoundingBoxContext &boundingBoxContext) override {
if (!_textDocument) { if (!_textDocument) {
return; return;
} }

View File

@ -103,7 +103,7 @@ public:
newFrame = floor(newFrame); newFrame = floor(newFrame);
} }
for (const auto &layer : _animationLayers) { for (const auto &layer : _animationLayers) {
layer->displayWithFrame(newFrame, false); layer->displayWithFrame(newFrame, false, _boundingBoxContext);
} }
} }
@ -118,7 +118,7 @@ public:
/// Forces the view to update its drawing. /// Forces the view to update its drawing.
void forceDisplayUpdate() { void forceDisplayUpdate() {
for (const auto &layer : _animationLayers) { for (const auto &layer : _animationLayers) {
layer->displayWithFrame(currentFrame(), true); layer->displayWithFrame(currentFrame(), true, _boundingBoxContext);
} }
} }
@ -193,7 +193,7 @@ public:
_currentFrame = currentFrame; _currentFrame = currentFrame;
for (size_t i = 0; i < _animationLayers.size(); i++) { for (size_t i = 0; i < _animationLayers.size(); i++) {
_animationLayers[i]->displayWithFrame(_currentFrame, false); _animationLayers[i]->displayWithFrame(_currentFrame, false, _boundingBoxContext);
} }
} }
@ -230,7 +230,7 @@ public:
} }
} }
if (found) { if (found) {
auto node = animationLayer->renderTreeNode(); auto node = animationLayer->renderTreeNode(_boundingBoxContext);
if (node) { if (node) {
subnodes.push_back(node); subnodes.push_back(node);
} }
@ -264,7 +264,7 @@ public:
} }
} }
if (found) { if (found) {
animationLayer->updateRenderTree(); animationLayer->updateRenderTree(_boundingBoxContext);
} }
} }
} }
@ -288,6 +288,8 @@ private:
std::shared_ptr<LayerFontProvider> _layerFontProvider; std::shared_ptr<LayerFontProvider> _layerFontProvider;
std::shared_ptr<RenderTreeNode> _renderTreeNode; std::shared_ptr<RenderTreeNode> _renderTreeNode;
BezierPathsBoundingBoxContext _boundingBoxContext;
}; };
} }

View File

@ -582,6 +582,58 @@ CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, st
return calculateBoundingRectOpt(pointsX, pointsY, pointCount); return calculateBoundingRectOpt(pointsX, pointsY, pointCount);
} }
CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, BezierPath const &path) {
int pointCount = 0;
float *pointsX = context.pointsX;
float *pointsY = context.pointsY;
int pointsSize = context.pointsSize;
PathElement const *pathElements = path.elements().data();
int pathElementCount = (int)path.elements().size();
for (int i = 0; i < pathElementCount; i++) {
const auto &element = pathElements[i];
if (pointsSize < pointCount + 1) {
pointsSize = (pointCount + 1) * 2;
pointsX = (float *)realloc(pointsX, pointsSize * 4);
pointsY = (float *)realloc(pointsY, pointsSize * 4);
}
pointsX[pointCount] = (float)element.vertex.point.x;
pointsY[pointCount] = (float)element.vertex.point.y;
pointCount++;
if (i != 0) {
const auto &previousElement = pathElements[i - 1];
if (previousElement.vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) {
} else {
if (pointsSize < pointCount + 1) {
pointsSize = (pointCount + 2) * 2;
pointsX = (float *)realloc(pointsX, pointsSize * 4);
pointsY = (float *)realloc(pointsY, pointsSize * 4);
}
pointsX[pointCount] = (float)previousElement.vertex.outTangent.x;
pointsY[pointCount] = (float)previousElement.vertex.outTangent.y;
pointCount++;
pointsX[pointCount] = (float)element.vertex.inTangent.x;
pointsY[pointCount] = (float)element.vertex.inTangent.y;
pointCount++;
}
}
}
context.pointsX = pointsX;
context.pointsY = pointsY;
context.pointsSize = pointsSize;
if (pointCount == 0) {
return CGRect(0.0, 0.0, 0.0, 0.0);
}
return calculateBoundingRectOpt(pointsX, pointsY, pointCount);
}
CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths) { CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths) {
int pointCount = 0; int pointCount = 0;