mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-17 09:10:30 +00:00
Lottie optimization
This commit is contained in:
parent
2cf5bd724a
commit
920de21020
@ -38,6 +38,54 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
|
|
||||||
double alpha = node->alpha();
|
double alpha = node->alpha();
|
||||||
|
|
||||||
|
/*if (node->_contentItem) {
|
||||||
|
RenderTreeNodeContentItem *contentItem = node->_contentItem.get();
|
||||||
|
for (const auto &shadingVariant : contentItem->shadings) {
|
||||||
|
if (shadingVariant->stroke) {
|
||||||
|
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
||||||
|
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);
|
||||||
|
effectiveLocalBounds = shapeBounds;
|
||||||
|
|
||||||
|
switch (shadingVariant->stroke->shading->type()) {
|
||||||
|
case RenderTreeNodeContent::ShadingType::Solid: {
|
||||||
|
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shadingVariant->stroke->shading.get();
|
||||||
|
|
||||||
|
alpha *= solidShading->opacity;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RenderTreeNodeContent::ShadingType::Gradient: {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (shadingVariant->fill) {
|
||||||
|
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
||||||
|
effectiveLocalBounds = shapeBounds;
|
||||||
|
|
||||||
|
switch (shadingVariant->fill->shading->type()) {
|
||||||
|
case RenderTreeNodeContent::ShadingType::Solid: {
|
||||||
|
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shadingVariant->fill->shading.get();
|
||||||
|
|
||||||
|
alpha *= solidShading->opacity;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RenderTreeNodeContent::ShadingType::Gradient: {
|
||||||
|
RenderTreeNodeContent::GradientShading *gradientShading = (RenderTreeNodeContent::GradientShading *)shadingVariant->fill->shading.get();
|
||||||
|
|
||||||
|
alpha *= gradientShading->opacity;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
if (node->content()) {
|
if (node->content()) {
|
||||||
RenderTreeNodeContent *shapeContent = node->content().get();
|
RenderTreeNodeContent *shapeContent = node->content().get();
|
||||||
|
|
||||||
@ -47,7 +95,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
shapeBounds = shapeBounds.insetBy(-shapeContent->stroke->lineWidth / 2.0, -shapeContent->stroke->lineWidth / 2.0);
|
shapeBounds = shapeBounds.insetBy(-shapeContent->stroke->lineWidth / 2.0, -shapeContent->stroke->lineWidth / 2.0);
|
||||||
effectiveLocalBounds = shapeBounds;
|
effectiveLocalBounds = shapeBounds;
|
||||||
|
|
||||||
switch (shapeContent->stroke->shading->type()) {
|
/*switch (shapeContent->stroke->shading->type()) {
|
||||||
case RenderTreeNodeContent::ShadingType::Solid: {
|
case RenderTreeNodeContent::ShadingType::Solid: {
|
||||||
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->stroke->shading.get();
|
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->stroke->shading.get();
|
||||||
|
|
||||||
@ -61,11 +109,11 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
} else if (shapeContent->fill) {
|
} else if (shapeContent->fill) {
|
||||||
effectiveLocalBounds = shapeBounds;
|
effectiveLocalBounds = shapeBounds;
|
||||||
|
|
||||||
switch (shapeContent->fill->shading->type()) {
|
/*switch (shapeContent->fill->shading->type()) {
|
||||||
case RenderTreeNodeContent::ShadingType::Solid: {
|
case RenderTreeNodeContent::ShadingType::Solid: {
|
||||||
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->fill->shading.get();
|
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->fill->shading.get();
|
||||||
|
|
||||||
@ -82,7 +130,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +158,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
if (item->renderData.isValid) {
|
if (item->renderData.isValid) {
|
||||||
drawContentDescendants += item->renderData.drawContentDescendants;
|
drawContentDescendants += item->renderData.drawContentDescendants;
|
||||||
|
|
||||||
if (item->content()) {
|
if (item->content() || item->_contentItem) {
|
||||||
drawContentDescendants += 1;
|
drawContentDescendants += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +370,7 @@ static void drawLottieRenderableItem(std::shared_ptr<lottieRendering::Canvas> co
|
|||||||
dashPattern = item->stroke->dashPattern;
|
dashPattern = item->stroke->dashPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
context->strokePath(path, item->stroke->lineWidth, lineJoin, lineCap, item->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a));
|
context->strokePath(path, item->stroke->lineWidth, lineJoin, lineCap, item->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
} else if (item->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
} else if (item->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
||||||
//TODO:gradient stroke
|
//TODO:gradient stroke
|
||||||
}
|
}
|
||||||
@ -344,14 +392,14 @@ static void drawLottieRenderableItem(std::shared_ptr<lottieRendering::Canvas> co
|
|||||||
|
|
||||||
if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
||||||
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)item->fill->shading.get();
|
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)item->fill->shading.get();
|
||||||
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a));
|
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
} else if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
} else if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
||||||
lottie::RenderTreeNodeContent::GradientShading *gradientShading = (lottie::RenderTreeNodeContent::GradientShading *)item->fill->shading.get();
|
lottie::RenderTreeNodeContent::GradientShading *gradientShading = (lottie::RenderTreeNodeContent::GradientShading *)item->fill->shading.get();
|
||||||
|
|
||||||
std::vector<lottieRendering::Color> colors;
|
std::vector<lottieRendering::Color> colors;
|
||||||
std::vector<double> locations;
|
std::vector<double> locations;
|
||||||
for (const auto &color : gradientShading->colors) {
|
for (const auto &color : gradientShading->colors) {
|
||||||
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a));
|
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a * gradientShading->opacity));
|
||||||
}
|
}
|
||||||
locations = gradientShading->locations;
|
locations = gradientShading->locations;
|
||||||
|
|
||||||
@ -376,6 +424,179 @@ static void drawLottieRenderableItem(std::shared_ptr<lottieRendering::Canvas> co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContentItem> item) {
|
||||||
|
if (item->shadings.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &shading : item->shadings) {
|
||||||
|
if (shading->explicitPath->empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<lottie::CGPath> path = lottie::CGPath::makePath();
|
||||||
|
|
||||||
|
const auto iterate = [&](LottiePathItem const *pathItem) {
|
||||||
|
switch (pathItem->type) {
|
||||||
|
case LottiePathItemTypeMoveTo: {
|
||||||
|
path->moveTo(lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LottiePathItemTypeLineTo: {
|
||||||
|
path->addLineTo(lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LottiePathItemTypeCurveTo: {
|
||||||
|
path->addCurveTo(lottie::Vector2D(pathItem->points[2].x, pathItem->points[2].y), lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y), lottie::Vector2D(pathItem->points[1].x, pathItem->points[1].y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LottiePathItemTypeClose: {
|
||||||
|
path->closeSubpath();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LottiePathItem pathItem;
|
||||||
|
for (const auto &path : shading->explicitPath.value()) {
|
||||||
|
std::optional<lottie::PathElement> previousElement;
|
||||||
|
for (const auto &element : path.elements()) {
|
||||||
|
if (previousElement.has_value()) {
|
||||||
|
if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) {
|
||||||
|
pathItem.type = LottiePathItemTypeLineTo;
|
||||||
|
pathItem.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||||
|
iterate(&pathItem);
|
||||||
|
} else {
|
||||||
|
pathItem.type = LottiePathItemTypeCurveTo;
|
||||||
|
pathItem.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||||
|
pathItem.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y);
|
||||||
|
pathItem.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y);
|
||||||
|
iterate(&pathItem);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pathItem.type = LottiePathItemTypeMoveTo;
|
||||||
|
pathItem.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
||||||
|
iterate(&pathItem);
|
||||||
|
}
|
||||||
|
previousElement = element;
|
||||||
|
}
|
||||||
|
if (path.closed().value_or(true)) {
|
||||||
|
pathItem.type = LottiePathItemTypeClose;
|
||||||
|
iterate(&pathItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shading->stroke) {
|
||||||
|
if (shading->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
||||||
|
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)shading->stroke->shading.get();
|
||||||
|
|
||||||
|
if (solidShading->opacity != 0.0) {
|
||||||
|
lottieRendering::LineJoin lineJoin = lottieRendering::LineJoin::Bevel;
|
||||||
|
switch (shading->stroke->lineJoin) {
|
||||||
|
case lottie::LineJoin::Bevel: {
|
||||||
|
lineJoin = lottieRendering::LineJoin::Bevel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::LineJoin::Round: {
|
||||||
|
lineJoin = lottieRendering::LineJoin::Round;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::LineJoin::Miter: {
|
||||||
|
lineJoin = lottieRendering::LineJoin::Miter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lottieRendering::LineCap lineCap = lottieRendering::LineCap::Square;
|
||||||
|
switch (shading->stroke->lineCap) {
|
||||||
|
case lottie::LineCap::Butt: {
|
||||||
|
lineCap = lottieRendering::LineCap::Butt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::LineCap::Round: {
|
||||||
|
lineCap = lottieRendering::LineCap::Round;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::LineCap::Square: {
|
||||||
|
lineCap = lottieRendering::LineCap::Square;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> dashPattern;
|
||||||
|
if (!shading->stroke->dashPattern.empty()) {
|
||||||
|
dashPattern = shading->stroke->dashPattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->strokePath(path, shading->stroke->lineWidth, lineJoin, lineCap, shading->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
|
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
||||||
|
//TODO:gradient stroke
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (shading->fill) {
|
||||||
|
lottieRendering::FillRule rule = lottieRendering::FillRule::NonZeroWinding;
|
||||||
|
switch (shading->fill->rule) {
|
||||||
|
case lottie::FillRule::EvenOdd: {
|
||||||
|
rule = lottieRendering::FillRule::EvenOdd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::FillRule::NonZeroWinding: {
|
||||||
|
rule = lottieRendering::FillRule::NonZeroWinding;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shading->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
||||||
|
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)shading->fill->shading.get();
|
||||||
|
if (solidShading->opacity != 0.0) {
|
||||||
|
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
|
}
|
||||||
|
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
||||||
|
lottie::RenderTreeNodeContent::GradientShading *gradientShading = (lottie::RenderTreeNodeContent::GradientShading *)shading->fill->shading.get();
|
||||||
|
|
||||||
|
if (gradientShading->opacity != 0.0) {
|
||||||
|
std::vector<lottieRendering::Color> colors;
|
||||||
|
std::vector<double> locations;
|
||||||
|
for (const auto &color : gradientShading->colors) {
|
||||||
|
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a * gradientShading->opacity));
|
||||||
|
}
|
||||||
|
locations = gradientShading->locations;
|
||||||
|
|
||||||
|
lottieRendering::Gradient gradient(colors, locations);
|
||||||
|
lottie::Vector2D start(gradientShading->start.x, gradientShading->start.y);
|
||||||
|
lottie::Vector2D end(gradientShading->end.x, gradientShading->end.y);
|
||||||
|
|
||||||
|
switch (gradientShading->gradientType) {
|
||||||
|
case lottie::GradientType::Linear: {
|
||||||
|
context->linearGradientFillPath(path, rule, gradient, start, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case lottie::GradientType::Radial: {
|
||||||
|
context->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, double parentAlpha) {
|
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, double parentAlpha) {
|
||||||
if (!node->renderData.isValid) {
|
if (!node->renderData.isValid) {
|
||||||
return;
|
return;
|
||||||
@ -442,9 +663,12 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
|
|||||||
|
|
||||||
currentContext->setAlpha(renderAlpha);
|
currentContext->setAlpha(renderAlpha);
|
||||||
|
|
||||||
if (node->content()) {
|
if (node->content() && (int64_t)"" < 0) {
|
||||||
drawLottieRenderableItem(currentContext, node->content());
|
drawLottieRenderableItem(currentContext, node->content());
|
||||||
}
|
}
|
||||||
|
if (node->_contentItem) {//} && (int64_t)"" < 0) {
|
||||||
|
drawLottieContentItem(currentContext, node->_contentItem);
|
||||||
|
}
|
||||||
|
|
||||||
if (node->renderData.isInvertedMatte) {
|
if (node->renderData.isInvertedMatte) {
|
||||||
currentContext->fill(lottie::CGRect(node->renderData.layer.bounds().x, node->renderData.layer.bounds().y, node->renderData.layer.bounds().width, node->renderData.layer.bounds().height), lottieRendering::Color(0.0, 0.0, 0.0, 1.0));
|
currentContext->fill(lottie::CGRect(node->renderData.layer.bounds().x, node->renderData.layer.bounds().y, node->renderData.layer.bounds().width, node->renderData.layer.bounds().height), lottieRendering::Color(0.0, 0.0, 0.0, 1.0));
|
||||||
|
@ -103,6 +103,11 @@ func processDrawAnimation(baseCachePath: String, path: String, name: String, siz
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*if #available(iOS 16.0, *) {
|
||||||
|
try? await Task.sleep(for: .seconds(0.1))
|
||||||
|
}*/
|
||||||
|
|
||||||
if !frameResult {
|
if !frameResult {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ private final class ReferenceCompareTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var continueFromName: String?
|
var continueFromName: String?
|
||||||
//continueFromName = "1258816259754282.json"
|
//continueFromName = "35707580709863498.json"
|
||||||
|
|
||||||
let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in
|
let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in
|
||||||
if let continueFromNameValue = continueFromName {
|
if let continueFromNameValue = continueFromName {
|
||||||
@ -119,7 +119,7 @@ public final class ViewController: UIViewController {
|
|||||||
|
|
||||||
self.view.layer.addSublayer(MetalEngine.shared.rootLayer)
|
self.view.layer.addSublayer(MetalEngine.shared.rootLayer)
|
||||||
|
|
||||||
if !"".isEmpty {
|
if "".isEmpty {
|
||||||
if #available(iOS 13.0, *) {
|
if #available(iOS 13.0, *) {
|
||||||
self.test = ReferenceCompareTest(view: self.view)
|
self.test = ReferenceCompareTest(view: self.view)
|
||||||
}
|
}
|
||||||
|
@ -1072,6 +1072,8 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
|
|||||||
private var processedDidAppear: Bool = false
|
private var processedDidAppear: Bool = false
|
||||||
private var processedDidDisappear: Bool = false
|
private var processedDidDisappear: Bool = false
|
||||||
|
|
||||||
|
private var isActiveDisposable: Disposable?
|
||||||
|
|
||||||
override public var overlayWantsToBeBelowKeyboard: Bool {
|
override public var overlayWantsToBeBelowKeyboard: Bool {
|
||||||
if let componentView = self.node.hostView.componentView as? ChatSendMessageContextScreenComponent.View {
|
if let componentView = self.node.hostView.componentView as? ChatSendMessageContextScreenComponent.View {
|
||||||
return componentView.wantsToBeBelowKeyboard()
|
return componentView.wantsToBeBelowKeyboard()
|
||||||
@ -1136,6 +1138,16 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
|
|||||||
|
|
||||||
self.lockOrientation = true
|
self.lockOrientation = true
|
||||||
self.blocksBackgroundWhenInOverlay = true
|
self.blocksBackgroundWhenInOverlay = true
|
||||||
|
|
||||||
|
self.isActiveDisposable = (context.sharedContext.applicationBindings.applicationInForeground
|
||||||
|
|> filter { !$0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.dismiss()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
@ -1143,6 +1155,7 @@ public class ChatSendMessageContextScreen: ViewControllerComponentContainer, Cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
self.isActiveDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include <LottieCpp/ShapeAttributes.h>
|
#include <LottieCpp/ShapeAttributes.h>
|
||||||
#include <LottieCpp/BezierPath.h>
|
#include <LottieCpp/BezierPath.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace lottie {
|
namespace lottie {
|
||||||
|
|
||||||
class RenderableItem {
|
class RenderableItem {
|
||||||
@ -229,14 +231,7 @@ public:
|
|||||||
CGRect bounds;
|
CGRect bounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderTreeNodeContentItem {
|
class RenderTreeNodeContentItem;
|
||||||
public:
|
|
||||||
RenderTreeNodeContentItem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RenderTreeNodeContent {
|
class RenderTreeNodeContent {
|
||||||
public:
|
public:
|
||||||
@ -360,6 +355,30 @@ public:
|
|||||||
std::shared_ptr<Fill> fill;
|
std::shared_ptr<Fill> fill;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RenderTreeNodeContentShadingVariant {
|
||||||
|
public:
|
||||||
|
RenderTreeNodeContentShadingVariant() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<RenderTreeNodeContent::Stroke> stroke;
|
||||||
|
std::shared_ptr<RenderTreeNodeContent::Fill> fill;
|
||||||
|
std::optional<std::vector<BezierPath>> explicitPath;
|
||||||
|
|
||||||
|
size_t subItemLimit = 0;
|
||||||
|
bool isGroup = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderTreeNodeContentItem {
|
||||||
|
public:
|
||||||
|
RenderTreeNodeContentItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isGroup = false;
|
||||||
|
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
||||||
|
};
|
||||||
|
|
||||||
class ProcessedRenderTreeNodeData {
|
class ProcessedRenderTreeNodeData {
|
||||||
public:
|
public:
|
||||||
struct LayerParams {
|
struct LayerParams {
|
||||||
@ -518,6 +537,7 @@ public:
|
|||||||
bool _masksToBounds = false;
|
bool _masksToBounds = false;
|
||||||
bool _isHidden = false;
|
bool _isHidden = false;
|
||||||
std::shared_ptr<RenderTreeNodeContent> _content;
|
std::shared_ptr<RenderTreeNodeContent> _content;
|
||||||
|
std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>> _subnodes;
|
std::vector<std::shared_ptr<RenderTreeNode>> _subnodes;
|
||||||
std::shared_ptr<RenderTreeNode> _mask;
|
std::shared_ptr<RenderTreeNode> _mask;
|
||||||
bool _invertMask = false;
|
bool _invertMask = false;
|
||||||
|
@ -899,7 +899,7 @@ public:
|
|||||||
std::shared_ptr<RenderTreeNode> _renderTree;
|
std::shared_ptr<RenderTreeNode> _renderTree;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<TransformedPath> collectPaths(AnimationFrameTime frameTime, size_t subItemLimit, CATransform3D parentTransform) {
|
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D parentTransform) {
|
||||||
std::vector<TransformedPath> mappedPaths;
|
std::vector<TransformedPath> mappedPaths;
|
||||||
|
|
||||||
CATransform3D effectiveTransform = parentTransform;
|
CATransform3D effectiveTransform = parentTransform;
|
||||||
@ -908,7 +908,6 @@ public:
|
|||||||
size_t maxSubitem = std::min(subItems.size(), subItemLimit);
|
size_t maxSubitem = std::min(subItems.size(), subItemLimit);
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
path->update(frameTime);
|
|
||||||
mappedPaths.emplace_back(*(path->currentPath()), effectiveTransform);
|
mappedPaths.emplace_back(*(path->currentPath()), effectiveTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,17 +916,19 @@ public:
|
|||||||
CATransform3D subItemTransform = effectiveChildTransform;
|
CATransform3D subItemTransform = effectiveChildTransform;
|
||||||
|
|
||||||
if (subItem->isGroup && subItem->transform) {
|
if (subItem->isGroup && subItem->transform) {
|
||||||
subItem->transform->update(frameTime);
|
//update?
|
||||||
|
//subItem->transform->update(frameTime);
|
||||||
subItemTransform = subItem->transform->transform() * subItemTransform;
|
subItemTransform = subItem->transform->transform() * subItemTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<TrimParams> currentTrim;
|
std::optional<TrimParams> currentTrim;
|
||||||
if (!trims.empty()) {
|
if (!trims.empty()) {
|
||||||
trims[0]->update(frameTime);
|
//update?
|
||||||
|
//trims[0]->update(frameTime);
|
||||||
currentTrim = trims[0]->trimParams();
|
currentTrim = trims[0]->trimParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto subItemPaths = subItem->collectPaths(frameTime, INT32_MAX, subItemTransform);
|
auto subItemPaths = subItem->collectPaths(INT32_MAX, subItemTransform);
|
||||||
|
|
||||||
if (currentTrim) {
|
if (currentTrim) {
|
||||||
CompoundBezierPath tempPath;
|
CompoundBezierPath tempPath;
|
||||||
@ -986,6 +987,9 @@ public:
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_renderTree->_contentItem = std::make_shared<RenderTreeNodeContentItem>();
|
||||||
|
_renderTree->_contentItem->isGroup = isGroup;
|
||||||
|
|
||||||
if (!shadings.empty()) {
|
if (!shadings.empty()) {
|
||||||
for (int i = 0; i < shadings.size(); i++) {
|
for (int i = 0; i < shadings.size(); i++) {
|
||||||
auto &shadingVariant = shadings[i];
|
auto &shadingVariant = shadings[i];
|
||||||
@ -1008,6 +1012,28 @@ public:
|
|||||||
);
|
);
|
||||||
shadingVariant.renderTree = shadingRenderTree;
|
shadingVariant.renderTree = shadingRenderTree;
|
||||||
_renderTree->_subnodes.push_back(shadingRenderTree);
|
_renderTree->_subnodes.push_back(shadingRenderTree);
|
||||||
|
|
||||||
|
auto itemShadingVariant = std::make_shared<RenderTreeNodeContentShadingVariant>();
|
||||||
|
if (shadingVariant.fill) {
|
||||||
|
itemShadingVariant->fill = std::make_shared<RenderTreeNodeContent::Fill>(
|
||||||
|
nullptr,
|
||||||
|
FillRule::NonZeroWinding
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (shadingVariant.stroke) {
|
||||||
|
itemShadingVariant->stroke = std::make_shared<RenderTreeNodeContent::Stroke>(
|
||||||
|
nullptr,
|
||||||
|
0.0,
|
||||||
|
LineJoin::Bevel,
|
||||||
|
LineCap::Round,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
std::vector<double>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
itemShadingVariant->subItemLimit = shadingVariant.subItemLimit;
|
||||||
|
|
||||||
|
_renderTree->_contentItem->shadings.push_back(itemShadingVariant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1036,11 +1062,36 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void updateChildren(AnimationFrameTime frameTime, std::optional<TrimParams> parentTrim) {
|
void updateFrame(AnimationFrameTime frameTime) {
|
||||||
|
if (transform) {
|
||||||
|
transform->update(frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
path->update(frameTime);
|
||||||
|
}
|
||||||
|
for (const auto &trim : trims) {
|
||||||
|
trim->update(frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &shadingVariant : shadings) {
|
||||||
|
if (shadingVariant.fill) {
|
||||||
|
shadingVariant.fill->update(frameTime);
|
||||||
|
}
|
||||||
|
if (shadingVariant.stroke) {
|
||||||
|
shadingVariant.stroke->update(frameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &subItem : subItems) {
|
||||||
|
subItem->updateFrame(frameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateChildren(std::optional<TrimParams> parentTrim) {
|
||||||
CATransform3D containerTransform = CATransform3D::identity();
|
CATransform3D containerTransform = CATransform3D::identity();
|
||||||
double containerOpacity = 1.0;
|
double containerOpacity = 1.0;
|
||||||
if (transform) {
|
if (transform) {
|
||||||
transform->update(frameTime);
|
|
||||||
containerTransform = transform->transform();
|
containerTransform = transform->transform();
|
||||||
containerOpacity = transform->opacity();
|
containerOpacity = transform->opacity();
|
||||||
}
|
}
|
||||||
@ -1055,7 +1106,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompoundBezierPath compoundPath;
|
CompoundBezierPath compoundPath;
|
||||||
auto paths = collectPaths(frameTime, shadingVariant.subItemLimit, CATransform3D::identity());
|
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity());
|
||||||
for (const auto &path : paths) {
|
for (const auto &path : paths) {
|
||||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||||
}
|
}
|
||||||
@ -1079,13 +1130,11 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Fill> fill;
|
std::shared_ptr<RenderTreeNodeContent::Fill> fill;
|
||||||
if (shadingVariant.fill) {
|
if (shadingVariant.fill) {
|
||||||
shadingVariant.fill->update(frameTime);
|
|
||||||
fill = shadingVariant.fill->fill();
|
fill = shadingVariant.fill->fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Stroke> stroke;
|
std::shared_ptr<RenderTreeNodeContent::Stroke> stroke;
|
||||||
if (shadingVariant.stroke) {
|
if (shadingVariant.stroke) {
|
||||||
shadingVariant.stroke->update(frameTime);
|
|
||||||
stroke = shadingVariant.stroke->stroke();
|
stroke = shadingVariant.stroke->stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,14 +1145,16 @@ public:
|
|||||||
);
|
);
|
||||||
|
|
||||||
shadingVariant.renderTree->_content = content;
|
shadingVariant.renderTree->_content = content;
|
||||||
|
|
||||||
|
_renderTree->_contentItem->shadings[i]->stroke = stroke;
|
||||||
|
_renderTree->_contentItem->shadings[i]->fill = fill;
|
||||||
|
_renderTree->_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGroup && !subItems.empty()) {
|
if (isGroup && !subItems.empty()) {
|
||||||
for (int i = (int)subItems.size() - 1; i >= 0; i--) {
|
for (int i = (int)subItems.size() - 1; i >= 0; i--) {
|
||||||
std::optional<TrimParams> childTrim = parentTrim;
|
std::optional<TrimParams> childTrim = parentTrim;
|
||||||
for (const auto &trim : trims) {
|
for (const auto &trim : trims) {
|
||||||
trim->update(frameTime);
|
|
||||||
|
|
||||||
if (i < (int)trim->trimParams().subItemLimit) {
|
if (i < (int)trim->trimParams().subItemLimit) {
|
||||||
//TODO:allow combination
|
//TODO:allow combination
|
||||||
//assert(!parentTrim);
|
//assert(!parentTrim);
|
||||||
@ -1111,7 +1162,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subItems[i]->updateChildren(frameTime, childTrim);
|
subItems[i]->updateChildren(childTrim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1284,14 +1335,16 @@ CompositionLayer(solidLayer, Vector2D::Zero()) {
|
|||||||
void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates) {
|
void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpdates) {
|
||||||
_frameTime = frame;
|
_frameTime = frame;
|
||||||
_frameTimeInitialized = true;
|
_frameTimeInitialized = true;
|
||||||
_contentTree->itemTree->updateChildren(_frameTime, std::nullopt);
|
_contentTree->itemTree->updateFrame(_frameTime);
|
||||||
|
_contentTree->itemTree->updateChildren(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
||||||
if (!_frameTimeInitialized) {
|
if (!_frameTimeInitialized) {
|
||||||
_frameTime = 0.0;
|
_frameTime = 0.0;
|
||||||
_frameTimeInitialized = true;
|
_frameTimeInitialized = true;
|
||||||
_contentTree->itemTree->updateChildren(_frameTime, std::nullopt);
|
_contentTree->itemTree->updateFrame(_frameTime);
|
||||||
|
_contentTree->itemTree->updateChildren(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_renderTreeNode) {
|
if (!_renderTreeNode) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user