mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Lottie optimization
This commit is contained in:
parent
507aeee187
commit
0225f74d30
@ -19,94 +19,62 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalBounds;
|
std::optional<CGRect> globalRect;
|
||||||
|
|
||||||
int drawContentDescendants = 0;
|
int drawContentDescendants = 0;
|
||||||
|
|
||||||
for (const auto &shadingVariant : contentItem->shadings) {
|
for (const auto &shadingVariant : contentItem->shadings) {
|
||||||
drawContentDescendants += 1;
|
|
||||||
|
|
||||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
||||||
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);
|
||||||
if (effectiveLocalBounds) {
|
|
||||||
effectiveLocalBounds = effectiveLocalBounds->unionWith(shapeBounds);
|
|
||||||
} else {
|
|
||||||
effectiveLocalBounds = shapeBounds;
|
|
||||||
}
|
|
||||||
} else if (shadingVariant->fill) {
|
} else if (shadingVariant->fill) {
|
||||||
if (effectiveLocalBounds) {
|
|
||||||
effectiveLocalBounds = effectiveLocalBounds->unionWith(shapeBounds);
|
|
||||||
} else {
|
} else {
|
||||||
effectiveLocalBounds = shapeBounds;
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalRect;
|
drawContentDescendants += 1;
|
||||||
if (effectiveLocalBounds.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> subnodesGlobalRect;
|
CGRect shapeGlobalBounds = shapeBounds.applyingTransform(currentTransform);
|
||||||
|
if (globalRect) {
|
||||||
|
globalRect = globalRect->unionWith(shapeGlobalBounds);
|
||||||
|
} else {
|
||||||
|
globalRect = shapeGlobalBounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &subItem : contentItem->subItems) {
|
for (const auto &subItem : contentItem->subItems) {
|
||||||
processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
||||||
|
|
||||||
|
if (subItem->renderData.isValid) {
|
||||||
drawContentDescendants += subItem->renderData.drawContentDescendants;
|
drawContentDescendants += subItem->renderData.drawContentDescendants;
|
||||||
|
if (globalRect) {
|
||||||
if (!subItem->renderData.localRect.empty()) {
|
globalRect = globalRect->unionWith(subItem->renderData.globalRect);
|
||||||
if (effectiveLocalRect.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalRect->unionWith(subItem->renderData.localRect);
|
|
||||||
} else {
|
} else {
|
||||||
effectiveLocalRect = subItem->renderData.localRect;
|
globalRect = subItem->renderData.globalRect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
if (!globalRect) {
|
||||||
subnodesGlobalRect = subnodesGlobalRect->unionWith(subItem->renderData.globalRect);
|
|
||||||
} else {
|
|
||||||
subnodesGlobalRect = subItem->renderData.globalRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> fuzzyGlobalRect;
|
|
||||||
|
|
||||||
if (effectiveLocalBounds) {
|
|
||||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(effectiveGlobalBounds);
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = effectiveGlobalBounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(subnodesGlobalRect.value());
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = subnodesGlobalRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fuzzyGlobalRect) {
|
|
||||||
contentItem->renderData.isValid = false;
|
contentItem->renderData.isValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGRect globalRect(
|
CGRect integralGlobalRect(
|
||||||
std::floor(fuzzyGlobalRect->x),
|
std::floor(globalRect->x),
|
||||||
std::floor(fuzzyGlobalRect->y),
|
std::floor(globalRect->y),
|
||||||
std::ceil(fuzzyGlobalRect->width + fuzzyGlobalRect->x - floor(fuzzyGlobalRect->x)),
|
std::ceil(globalRect->width + globalRect->x - floor(globalRect->x)),
|
||||||
std::ceil(fuzzyGlobalRect->height + fuzzyGlobalRect->y - floor(fuzzyGlobalRect->y))
|
std::ceil(globalRect->height + globalRect->y - floor(globalRect->y))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(globalRect)) {
|
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(integralGlobalRect)) {
|
||||||
|
contentItem->renderData.isValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (integralGlobalRect.width <= 0.0 || integralGlobalRect.height <= 0.0) {
|
||||||
contentItem->renderData.isValid = false;
|
contentItem->renderData.isValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGRect localRect = effectiveLocalRect.value_or(CGRect(0.0, 0.0, 0.0, 0.0)).applyingTransform(localTransform);
|
|
||||||
|
|
||||||
contentItem->renderData.isValid = true;
|
contentItem->renderData.isValid = true;
|
||||||
|
|
||||||
@ -117,10 +85,8 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
|
|||||||
contentItem->renderData.layer._masksToBounds = false;
|
contentItem->renderData.layer._masksToBounds = false;
|
||||||
contentItem->renderData.layer._isHidden = false;
|
contentItem->renderData.layer._isHidden = false;
|
||||||
|
|
||||||
contentItem->renderData.globalRect = globalRect;
|
contentItem->renderData.globalRect = integralGlobalRect;
|
||||||
contentItem->renderData.localRect = localRect;
|
|
||||||
contentItem->renderData.globalTransform = currentTransform;
|
contentItem->renderData.globalTransform = currentTransform;
|
||||||
contentItem->renderData.drawsContent = effectiveLocalBounds.has_value();
|
|
||||||
contentItem->renderData.drawContentDescendants = drawContentDescendants;
|
contentItem->renderData.drawContentDescendants = drawContentDescendants;
|
||||||
contentItem->renderData.isInvertedMatte = false;
|
contentItem->renderData.isInvertedMatte = false;
|
||||||
}
|
}
|
||||||
@ -151,100 +117,59 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int drawContentDescendants = 0;
|
||||||
|
std::optional<CGRect> globalRect;
|
||||||
if (node->_contentItem) {
|
if (node->_contentItem) {
|
||||||
processRenderContentItem(node->_contentItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
processRenderContentItem(node->_contentItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
||||||
|
if (node->_contentItem->renderData.isValid) {
|
||||||
|
drawContentDescendants += node->_contentItem->renderData.drawContentDescendants;
|
||||||
|
globalRect = node->_contentItem->renderData.globalRect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalBounds;
|
|
||||||
|
|
||||||
bool isInvertedMatte = isInvertedMask;
|
bool isInvertedMatte = isInvertedMask;
|
||||||
if (isInvertedMatte) {
|
if (isInvertedMatte) {
|
||||||
effectiveLocalBounds = node->bounds();
|
CGRect globalBounds = node->bounds().applyingTransform(currentTransform);
|
||||||
|
if (globalRect) {
|
||||||
|
globalRect = globalRect->unionWith(globalBounds);
|
||||||
|
} else {
|
||||||
|
globalRect = globalBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effectiveLocalBounds && effectiveLocalBounds->empty()) {
|
|
||||||
effectiveLocalBounds = std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalRect;
|
|
||||||
if (effectiveLocalBounds.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> subnodesGlobalRect;
|
|
||||||
bool masksToBounds = node->masksToBounds();
|
|
||||||
|
|
||||||
int drawContentDescendants = 0;
|
|
||||||
|
|
||||||
for (const auto &item : node->subnodes()) {
|
for (const auto &item : node->subnodes()) {
|
||||||
processRenderTree(item, globalSize, currentTransform, false, bezierPathsBoundingBoxContext);
|
processRenderTree(item, globalSize, currentTransform, false, bezierPathsBoundingBoxContext);
|
||||||
if (item->renderData.isValid) {
|
if (item->renderData.isValid) {
|
||||||
drawContentDescendants += item->renderData.drawContentDescendants;
|
drawContentDescendants += item->renderData.drawContentDescendants;
|
||||||
|
|
||||||
if (item->_contentItem) {
|
if (globalRect) {
|
||||||
drawContentDescendants += 1;
|
globalRect = globalRect->unionWith(item->renderData.globalRect);
|
||||||
}
|
|
||||||
|
|
||||||
if (!item->renderData.localRect.empty()) {
|
|
||||||
if (effectiveLocalRect.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalRect->unionWith(item->renderData.localRect);
|
|
||||||
} else {
|
} else {
|
||||||
effectiveLocalRect = item->renderData.localRect;
|
globalRect = item->renderData.globalRect;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
|
||||||
subnodesGlobalRect = subnodesGlobalRect->unionWith(item->renderData.globalRect);
|
|
||||||
} else {
|
|
||||||
subnodesGlobalRect = item->renderData.globalRect;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (masksToBounds && effectiveLocalRect.has_value()) {
|
if (!globalRect) {
|
||||||
if (node->bounds().contains(effectiveLocalRect.value())) {
|
|
||||||
masksToBounds = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> fuzzyGlobalRect;
|
|
||||||
|
|
||||||
if (effectiveLocalBounds) {
|
|
||||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(effectiveGlobalBounds);
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = effectiveGlobalBounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(subnodesGlobalRect.value());
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = subnodesGlobalRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fuzzyGlobalRect) {
|
|
||||||
node->renderData.isValid = false;
|
node->renderData.isValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGRect globalRect(
|
CGRect integralGlobalRect(
|
||||||
std::floor(fuzzyGlobalRect->x),
|
std::floor(globalRect->x),
|
||||||
std::floor(fuzzyGlobalRect->y),
|
std::floor(globalRect->y),
|
||||||
std::ceil(fuzzyGlobalRect->width + fuzzyGlobalRect->x - floor(fuzzyGlobalRect->x)),
|
std::ceil(globalRect->width + globalRect->x - floor(globalRect->x)),
|
||||||
std::ceil(fuzzyGlobalRect->height + fuzzyGlobalRect->y - floor(fuzzyGlobalRect->y))
|
std::ceil(globalRect->height + globalRect->y - floor(globalRect->y))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(globalRect)) {
|
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(integralGlobalRect)) {
|
||||||
node->renderData.isValid = false;
|
node->renderData.isValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (masksToBounds && effectiveLocalBounds) {
|
bool masksToBounds = node->masksToBounds();
|
||||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
if (masksToBounds) {
|
||||||
|
CGRect effectiveGlobalBounds = node->bounds().applyingTransform(currentTransform);
|
||||||
if (effectiveGlobalBounds.contains(CGRect(0.0, 0.0, globalSize.x, globalSize.y))) {
|
if (effectiveGlobalBounds.contains(CGRect(0.0, 0.0, globalSize.x, globalSize.y))) {
|
||||||
masksToBounds = false;
|
masksToBounds = false;
|
||||||
}
|
}
|
||||||
@ -253,7 +178,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
if (node->mask()) {
|
if (node->mask()) {
|
||||||
processRenderTree(node->mask(), globalSize, currentTransform, node->invertMask(), bezierPathsBoundingBoxContext);
|
processRenderTree(node->mask(), globalSize, currentTransform, node->invertMask(), bezierPathsBoundingBoxContext);
|
||||||
if (node->mask()->renderData.isValid) {
|
if (node->mask()->renderData.isValid) {
|
||||||
if (!node->mask()->renderData.globalRect.intersects(globalRect)) {
|
if (!node->mask()->renderData.globalRect.intersects(integralGlobalRect)) {
|
||||||
node->renderData.isValid = false;
|
node->renderData.isValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -263,7 +188,10 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CGRect localRect = effectiveLocalRect.value_or(CGRect(0.0, 0.0, 0.0, 0.0)).applyingTransform(localTransform);
|
if (integralGlobalRect.width <= 0.0 || integralGlobalRect.height <= 0.0) {
|
||||||
|
node->renderData.isValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
node->renderData.isValid = true;
|
node->renderData.isValid = true;
|
||||||
|
|
||||||
@ -274,10 +202,8 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
node->renderData.layer._masksToBounds = masksToBounds;
|
node->renderData.layer._masksToBounds = masksToBounds;
|
||||||
node->renderData.layer._isHidden = node->isHidden();
|
node->renderData.layer._isHidden = node->isHidden();
|
||||||
|
|
||||||
node->renderData.globalRect = globalRect;
|
node->renderData.globalRect = integralGlobalRect;
|
||||||
node->renderData.localRect = localRect;
|
|
||||||
node->renderData.globalTransform = currentTransform;
|
node->renderData.globalTransform = currentTransform;
|
||||||
node->renderData.drawsContent = effectiveLocalBounds.has_value();
|
|
||||||
node->renderData.drawContentDescendants = drawContentDescendants;
|
node->renderData.drawContentDescendants = drawContentDescendants;
|
||||||
node->renderData.isInvertedMatte = isInvertedMatte;
|
node->renderData.isInvertedMatte = isInvertedMatte;
|
||||||
}
|
}
|
||||||
@ -286,9 +212,49 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContentItem> item) {
|
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, double parentAlpha) {
|
||||||
context->saveState();
|
if (!item->renderData.isValid) {
|
||||||
context->concatenate(item->transform);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float normalizedOpacity = item->renderData.layer.opacity();
|
||||||
|
double layerAlpha = ((double)normalizedOpacity) * parentAlpha;
|
||||||
|
|
||||||
|
if (item->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentContext->saveState();
|
||||||
|
|
||||||
|
std::shared_ptr<lottieRendering::Canvas> currentContext;
|
||||||
|
std::shared_ptr<lottieRendering::Canvas> tempContext;
|
||||||
|
|
||||||
|
bool needsTempContext = false;
|
||||||
|
needsTempContext = layerAlpha != 1.0 && item->renderData.drawContentDescendants > 1;
|
||||||
|
|
||||||
|
if (needsTempContext) {
|
||||||
|
auto tempContextValue = parentContext->makeLayer((int)(item->renderData.globalRect.width), (int)(item->renderData.globalRect.height));
|
||||||
|
tempContext = tempContextValue;
|
||||||
|
|
||||||
|
currentContext = tempContextValue;
|
||||||
|
currentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.globalRect.x, -item->renderData.globalRect.y)));
|
||||||
|
|
||||||
|
currentContext->saveState();
|
||||||
|
currentContext->concatenate(item->renderData.globalTransform);
|
||||||
|
} else {
|
||||||
|
currentContext = parentContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(item->renderData.layer.position().x, item->renderData.layer.position().y)));
|
||||||
|
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.layer.bounds().x, -item->renderData.layer.bounds().y)));
|
||||||
|
parentContext->concatenate(item->renderData.layer.transform());
|
||||||
|
|
||||||
|
double renderAlpha = 1.0;
|
||||||
|
if (tempContext) {
|
||||||
|
renderAlpha = 1.0;
|
||||||
|
} else {
|
||||||
|
renderAlpha = layerAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &shading : item->shadings) {
|
for (const auto &shading : item->shadings) {
|
||||||
if (shading->explicitPath->empty()) {
|
if (shading->explicitPath->empty()) {
|
||||||
@ -398,7 +364,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
dashPattern = shading->stroke->dashPattern;
|
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));
|
currentContext->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 * renderAlpha));
|
||||||
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||||
//TODO:gradient stroke
|
//TODO:gradient stroke
|
||||||
}
|
}
|
||||||
@ -422,7 +388,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
||||||
lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->fill->shading.get();
|
lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->fill->shading.get();
|
||||||
if (solidShading->opacity != 0.0) {
|
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));
|
currentContext->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity * renderAlpha));
|
||||||
}
|
}
|
||||||
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||||
lottie::RenderTreeNodeContentItem::GradientShading *gradientShading = (lottie::RenderTreeNodeContentItem::GradientShading *)shading->fill->shading.get();
|
lottie::RenderTreeNodeContentItem::GradientShading *gradientShading = (lottie::RenderTreeNodeContentItem::GradientShading *)shading->fill->shading.get();
|
||||||
@ -431,7 +397,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
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 * gradientShading->opacity));
|
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a * gradientShading->opacity * renderAlpha));
|
||||||
}
|
}
|
||||||
locations = gradientShading->locations;
|
locations = gradientShading->locations;
|
||||||
|
|
||||||
@ -441,11 +407,11 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
|
|
||||||
switch (gradientShading->gradientType) {
|
switch (gradientShading->gradientType) {
|
||||||
case lottie::GradientType::Linear: {
|
case lottie::GradientType::Linear: {
|
||||||
context->linearGradientFillPath(path, rule, gradient, start, end);
|
currentContext->linearGradientFillPath(path, rule, gradient, start, end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case lottie::GradientType::Radial: {
|
case lottie::GradientType::Radial: {
|
||||||
context->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
currentContext->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -458,10 +424,19 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &subItem : item->subItems) {
|
for (const auto &subItem : item->subItems) {
|
||||||
drawLottieContentItem(context, subItem);
|
drawLottieContentItem(currentContext, subItem, renderAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
context->restoreState();
|
if (tempContext) {
|
||||||
|
tempContext->restoreState();
|
||||||
|
|
||||||
|
parentContext->concatenate(item->renderData.globalTransform.inverted());
|
||||||
|
parentContext->setAlpha(layerAlpha);
|
||||||
|
parentContext->draw(tempContext, item->renderData.globalRect);
|
||||||
|
parentContext->setAlpha(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
parentContext->restoreState();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
@ -528,10 +503,8 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
|
|||||||
renderAlpha = layerAlpha;
|
renderAlpha = layerAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentContext->setAlpha(renderAlpha);
|
|
||||||
|
|
||||||
if (node->_contentItem) {
|
if (node->_contentItem) {
|
||||||
drawLottieContentItem(currentContext, node->_contentItem);
|
drawLottieContentItem(currentContext, node->_contentItem, renderAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->renderData.isInvertedMatte) {
|
if (node->renderData.isInvertedMatte) {
|
||||||
|
@ -78,7 +78,7 @@ private final class ReferenceCompareTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var continueFromName: String?
|
var continueFromName: String?
|
||||||
//continueFromName = "778160933443732778.json"
|
continueFromName = "1391391008142393362.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 {
|
||||||
|
@ -75,9 +75,7 @@ public:
|
|||||||
false
|
false
|
||||||
),
|
),
|
||||||
globalRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
globalRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
||||||
localRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
|
||||||
globalTransform(CATransform3D::identity()),
|
globalTransform(CATransform3D::identity()),
|
||||||
drawsContent(false),
|
|
||||||
drawContentDescendants(false),
|
drawContentDescendants(false),
|
||||||
isInvertedMatte(false) {
|
isInvertedMatte(false) {
|
||||||
|
|
||||||
@ -86,9 +84,7 @@ public:
|
|||||||
bool isValid = false;
|
bool isValid = false;
|
||||||
LayerParams layer;
|
LayerParams layer;
|
||||||
CGRect globalRect;
|
CGRect globalRect;
|
||||||
CGRect localRect;
|
|
||||||
CATransform3D globalTransform;
|
CATransform3D globalTransform;
|
||||||
bool drawsContent;
|
|
||||||
int drawContentDescendants;
|
int drawContentDescendants;
|
||||||
bool isInvertedMatte;
|
bool isInvertedMatte;
|
||||||
};
|
};
|
||||||
|
@ -65,9 +65,7 @@
|
|||||||
result.layer.isHidden = node->renderData.layer._isHidden;
|
result.layer.isHidden = node->renderData.layer._isHidden;
|
||||||
|
|
||||||
result.globalRect = CGRectMake(node->renderData.globalRect.x, node->renderData.globalRect.y, node->renderData.globalRect.width, node->renderData.globalRect.height);
|
result.globalRect = CGRectMake(node->renderData.globalRect.x, node->renderData.globalRect.y, node->renderData.globalRect.width, node->renderData.globalRect.height);
|
||||||
result.localRect = CGRectMake(node->renderData.localRect.x, node->renderData.localRect.y, node->renderData.localRect.width, node->renderData.localRect.height);
|
|
||||||
result.globalTransform = lottie::nativeTransform(node->renderData.globalTransform);
|
result.globalTransform = lottie::nativeTransform(node->renderData.globalTransform);
|
||||||
result.drawsContent = node->renderData.drawsContent;
|
|
||||||
result.hasSimpleContents = node->renderData.drawContentDescendants <= 1;
|
result.hasSimpleContents = node->renderData.drawContentDescendants <= 1;
|
||||||
result.drawContentDescendants = node->renderData.drawContentDescendants;
|
result.drawContentDescendants = node->renderData.drawContentDescendants;
|
||||||
result.isInvertedMatte = node->renderData.isInvertedMatte;
|
result.isInvertedMatte = node->renderData.isInvertedMatte;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user