diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h index 571f5199d4..cc5f5e0049 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h @@ -37,6 +37,7 @@ public: virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; virtual void clip(CGRect const &rect) override; + virtual bool clipPath(CanvasPathEnumerator const &enumeratePath, FillRule fillRule, Transform2D const &transform) override; virtual void concatenate(lottie::Transform2D const &transform) override; virtual std::shared_ptr makeImage(); diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm index 96288db99d..fe9016c9b4 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm @@ -503,6 +503,29 @@ void CoreGraphicsCanvasImpl::clip(CGRect const &rect) { CGContextClipToRect(currentLayer()->context(), CGRectMake(rect.x, rect.y, rect.width, rect.height)); } +bool CoreGraphicsCanvasImpl::clipPath(CanvasPathEnumerator const &enumeratePath, FillRule fillRule, Transform2D const &transform) { + CGContextSaveGState(currentLayer()->context()); + concatenate(transform); + + if (!addEnumeratedPath(currentLayer()->context(), enumeratePath)) { + CGContextRestoreGState(currentLayer()->context()); + return false; + } + CGContextRestoreGState(currentLayer()->context()); + switch (fillRule) { + case lottie::FillRule::EvenOdd: { + CGContextEOClip(currentLayer()->context()); + break; + } + default: { + CGContextClip(currentLayer()->context()); + break; + } + } + + return true; +} + void CoreGraphicsCanvasImpl::concatenate(lottie::Transform2D const &transform) { CGContextConcatCTM(currentLayer()->context(), CATransform3DGetAffineTransform(nativeTransform(transform))); } diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp index d659821a79..48f02e6b16 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.cpp @@ -50,6 +50,17 @@ void skPath(CanvasPathEnumerator const &enumeratePath, SkPath &nativePath) { }); } +SkMatrix skMatrix(Transform2D const &transform) { + SkScalar m9[9] = { + transform.rows().columns[0][0], transform.rows().columns[1][0], transform.rows().columns[2][0], + transform.rows().columns[0][1], transform.rows().columns[1][1], transform.rows().columns[2][1], + transform.rows().columns[0][2], transform.rows().columns[1][2], transform.rows().columns[2][2] + }; + SkMatrix matrix; + matrix.set9(m9); + return matrix; +} + } SkiaCanvasImpl::SkiaCanvasImpl(int width, int height) { @@ -243,15 +254,20 @@ void SkiaCanvasImpl::clip(CGRect const &rect) { _canvas->clipRect(SkRect::MakeXYWH(rect.x, rect.y, rect.width, rect.height), true); } +bool SkiaCanvasImpl::clipPath(CanvasPathEnumerator const &enumeratePath, FillRule fillRule, Transform2D const &transform) { + SkPath nativePath; + skPath(enumeratePath, nativePath); + nativePath.setFillType(fillRule == FillRule::EvenOdd ? SkPathFillType::kEvenOdd : SkPathFillType::kWinding); + if (!transform.isIdentity()) { + nativePath.transform(skMatrix(transform)); + } + _canvas->clipPath(nativePath, true); + + return true; +} + void SkiaCanvasImpl::concatenate(lottie::Transform2D const &transform) { - SkScalar m9[9] = { - transform.rows().columns[0][0], transform.rows().columns[1][0], transform.rows().columns[2][0], - transform.rows().columns[0][1], transform.rows().columns[1][1], transform.rows().columns[2][1], - transform.rows().columns[0][2], transform.rows().columns[1][2], transform.rows().columns[2][2] - }; - SkMatrix matrix; - matrix.set9(m9); - _canvas->concat(matrix); + _canvas->concat(skMatrix(transform)); } bool SkiaCanvasImpl::pushLayer(CGRect const &rect, float alpha, std::optional maskMode) { diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h index ea8ddec7d6..59c0b4f48e 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SkiaCanvasImpl.h @@ -25,6 +25,7 @@ public: virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; virtual void clip(CGRect const &rect) override; + virtual bool clipPath(CanvasPathEnumerator const &enumeratePath, FillRule fillRule, Transform2D const &transform) override; virtual void concatenate(lottie::Transform2D const &transform) override; virtual bool pushLayer(CGRect const &rect, float alpha, std::optional maskMode) override; diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm index 43a8b83412..afa87543d5 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm @@ -4,7 +4,6 @@ #import #import "CoreGraphicsCanvasImpl.h" -#import "ThorVGCanvasImpl.h" #import "SkiaCanvasImpl.h" #include @@ -113,32 +112,6 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) { return image; } - } else if ((int64_t)"" < 0) { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - lottie::ThorVGCanvasImpl::initializeOnce(); - }); - - int bytesPerRow = ((int)size.width) * 4; - auto context = std::make_shared((int)size.width, (int)size.height, bytesPerRow); - - _canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration); - - context->flush(); - - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; - - CGContextRef targetContext = CGBitmapContextCreate((void *)context->backingData(), (int)size.width, (int)size.height, 8, bytesPerRow, colorSpace, bitmapInfo); - CGColorSpaceRelease(colorSpace); - - CGImageRef bitmapImage = CGBitmapContextCreateImage(targetContext); - UIImage *image = [[UIImage alloc] initWithCGImage:bitmapImage scale:1.0f orientation:UIImageOrientationDownMirrored]; - CGImageRelease(bitmapImage); - - CGContextRelease(targetContext); - - return image; } else { auto context = std::make_shared((int)size.width, (int)size.height); _canvasRenderer->render(_renderer, context, lottie::Vector2D(size.width, size.height), configuration); diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.cpp b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.cpp deleted file mode 100644 index 30b64828b6..0000000000 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "ThorVGCanvasImpl.h" - -namespace lottie { - -namespace { - -void tvgPath(CanvasPathEnumerator const &enumeratePath, tvg::Shape *shape) { - enumeratePath([&](PathCommand const &command) { - switch (command.type) { - case PathCommandType::MoveTo: { - shape->moveTo(command.points[0].x, command.points[0].y); - break; - } - case PathCommandType::LineTo: { - shape->lineTo(command.points[0].x, command.points[0].y); - break; - } - case PathCommandType::CurveTo: { - shape->cubicTo(command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y); - break; - } - case PathCommandType::Close: { - shape->close(); - break; - } - } - }); -} - -tvg::Matrix tvgTransform(lottie::Transform2D const &transform) { - tvg::Matrix result; - result.e11 = transform.rows().columns[0][0]; - result.e21 = transform.rows().columns[0][1]; - result.e31 = transform.rows().columns[0][2]; - result.e12 = transform.rows().columns[1][0]; - result.e22 = transform.rows().columns[1][1]; - result.e32 = transform.rows().columns[1][2]; - result.e13 = transform.rows().columns[2][0]; - result.e23 = transform.rows().columns[2][1]; - result.e33 = transform.rows().columns[2][2]; - - return result; -} - -} - -void ThorVGCanvasImpl::initializeOnce() { - tvg::Initializer::init(0); -} - -ThorVGCanvasImpl::ThorVGCanvasImpl(int width, int height, int bytesPerRow) : -_transform(lottie::Transform2D::identity()) { - _canvas = tvg::SwCanvas::gen(); - - _bytesPerRow = bytesPerRow; - - _backingData = (uint32_t *)malloc(_bytesPerRow * height); - memset(_backingData, 0, _bytesPerRow * height); - - _canvas->target(_backingData, _bytesPerRow / 4, width, height, tvg::SwCanvas::ARGB8888); -} - -ThorVGCanvasImpl::~ThorVGCanvasImpl() { -} - -void ThorVGCanvasImpl::saveState() { - _stateStack.push_back(_transform); -} - -void ThorVGCanvasImpl::restoreState() { - if (_stateStack.empty()) { - assert(false); - return; - } - _transform = _stateStack[_stateStack.size() - 1]; - _stateStack.pop_back(); -} - -void ThorVGCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) { - auto shape = tvg::Shape::gen(); - tvgPath(enumeratePath, shape.get()); - - shape->transform(tvgTransform(_transform)); - - shape->fill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0)); - shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); - - _canvas->push(std::move(shape)); -} - -void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { - auto shape = tvg::Shape::gen(); - tvgPath(enumeratePath, shape.get()); - - shape->transform(tvgTransform(_transform)); - - auto fill = tvg::LinearGradient::gen(); - fill->linear(start.x, start.y, end.x, end.y); - - std::vector colors; - for (size_t i = 0; i < gradient.colors().size(); i++) { - const auto &color = gradient.colors()[i]; - tvg::Fill::ColorStop colorStop; - colorStop.offset = gradient.locations()[i]; - colorStop.r = (int)(color.r * 255.0); - colorStop.g = (int)(color.g * 255.0); - colorStop.b = (int)(color.b * 255.0); - colorStop.a = (int)(color.a * 255.0); - colors.push_back(colorStop); - } - fill->colorStops(colors.data(), (uint32_t)colors.size()); - shape->fill(std::move(fill)); - - shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); - - _canvas->push(std::move(shape)); -} - -void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, Vector2D const ¢er, float radius) { - auto shape = tvg::Shape::gen(); - tvgPath(enumeratePath, shape.get()); - - shape->transform(tvgTransform(_transform)); - - auto fill = tvg::RadialGradient::gen(); - fill->radial(center.x, center.y, radius); - - std::vector colors; - for (size_t i = 0; i < gradient.colors().size(); i++) { - const auto &color = gradient.colors()[i]; - tvg::Fill::ColorStop colorStop; - colorStop.offset = gradient.locations()[i]; - colorStop.r = (int)(color.r * 255.0); - colorStop.g = (int)(color.g * 255.0); - colorStop.b = (int)(color.b * 255.0); - colorStop.a = (int)(color.a * 255.0); - colors.push_back(colorStop); - } - fill->colorStops(colors.data(), (uint32_t)colors.size()); - shape->fill(std::move(fill)); - - shape->fill(fillRule == lottie::FillRule::EvenOdd ? tvg::FillRule::EvenOdd : tvg::FillRule::Winding); - - _canvas->push(std::move(shape)); -} - -void ThorVGCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { - auto shape = tvg::Shape::gen(); - tvgPath(enumeratePath, shape.get()); - - shape->transform(tvgTransform(_transform)); - - shape->strokeFill((int)(color.r * 255.0), (int)(color.g * 255.0), (int)(color.b * 255.0), (int)(color.a * 255.0)); - shape->strokeWidth(lineWidth); - - switch (lineJoin) { - case lottie::LineJoin::Miter: { - shape->strokeJoin(tvg::StrokeJoin::Miter); - break; - } - case lottie::LineJoin::Round: { - shape->strokeJoin(tvg::StrokeJoin::Round); - break; - } - case lottie::LineJoin::Bevel: { - shape->strokeJoin(tvg::StrokeJoin::Bevel); - break; - } - default: { - shape->strokeJoin(tvg::StrokeJoin::Bevel); - break; - } - } - - switch (lineCap) { - case lottie::LineCap::Butt: { - shape->strokeCap(tvg::StrokeCap::Butt); - break; - } - case lottie::LineCap::Round: { - shape->strokeCap(tvg::StrokeCap::Round); - break; - } - case lottie::LineCap::Square: { - shape->strokeCap(tvg::StrokeCap::Square); - break; - } - default: { - shape->strokeCap(tvg::StrokeCap::Square); - break; - } - } - - if (!dashPattern.empty()) { - std::vector intervals; - intervals.reserve(dashPattern.size()); - for (auto value : dashPattern) { - intervals.push_back(value); - } - shape->strokeDash(intervals.data(), (uint32_t)intervals.size()); - //TODO:phase - } - - _canvas->push(std::move(shape)); -} - -void ThorVGCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { -} - -void ThorVGCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { -} - -void ThorVGCanvasImpl::concatenate(lottie::Transform2D const &transform) { - _transform = transform * _transform; -} - -void ThorVGCanvasImpl::flush() { - _canvas->draw(); - _canvas->sync(); - - _statsNumStrokes = 0; -} - -} diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h deleted file mode 100644 index 9b20b6344e..0000000000 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ThorVGCanvasImpl_h -#define ThorVGCanvasImpl_h - -#include - -#include - -namespace lottie { - -class ThorVGCanvasImpl: public Canvas { -public: - static void initializeOnce(); - - ThorVGCanvasImpl(int width, int height, int bytesPerRow); - virtual ~ThorVGCanvasImpl(); - - virtual void saveState() override; - virtual void restoreState() override; - - virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override; - virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Gradient const &gradient, Vector2D const ¢er, float radius) override; - virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; - virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; - - virtual void concatenate(lottie::Transform2D const &transform) override; - - uint32_t *backingData() { - return _backingData; - } - - int bytesPerRow() const { - return _bytesPerRow; - } - - void flush(); - -private: - std::unique_ptr _canvas; - - lottie::Transform2D _transform; - std::vector _stateStack; - int _bytesPerRow = 0; - uint32_t *_backingData = nullptr; - int _statsNumStrokes = 0; -}; - -} - -#endif diff --git a/Tests/LottieMetalTest/Sources/ViewController.swift b/Tests/LottieMetalTest/Sources/ViewController.swift index 4db3e67960..af9a122446 100644 --- a/Tests/LottieMetalTest/Sources/ViewController.swift +++ b/Tests/LottieMetalTest/Sources/ViewController.swift @@ -88,7 +88,7 @@ private final class ReferenceCompareTest { } var continueFromName: String? - //continueFromName = "1258816259754165.json" + //continueFromName = "562563904580878375.json" let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: !testNonReference, process: { path, name, alwaysDraw in if let continueFromNameValue = continueFromName { @@ -152,6 +152,10 @@ private final class ManualReferenceCompareTest { let bundlePath = Bundle.main.path(forResource: "TestDataBundle", ofType: "bundle")! self.fileList = buildAnimationFolderItems(basePath: bundlePath, path: "") + if let index = self.fileList.firstIndex(where: { $0.fileName == "shit.json" }) { + self.currentFileIndex = index + } + self.renderSize = CGSize(width: 256.0, height: 256.0) self.view = view diff --git a/Tests/LottieMetalTest/skia/device/libskia.framework/Info.plist b/Tests/LottieMetalTest/skia/device/libskia.framework/Info.plist new file mode 100644 index 0000000000..ac23c3e15d Binary files /dev/null and b/Tests/LottieMetalTest/skia/device/libskia.framework/Info.plist differ diff --git a/Tests/LottieMetalTest/skia/device/libskia.framework/libskia b/Tests/LottieMetalTest/skia/device/libskia.framework/libskia new file mode 100755 index 0000000000..e342d3df44 Binary files /dev/null and b/Tests/LottieMetalTest/skia/device/libskia.framework/libskia differ diff --git a/submodules/LottieCpp/lottiecpp b/submodules/LottieCpp/lottiecpp index 2b10b84f62..b885e63e76 160000 --- a/submodules/LottieCpp/lottiecpp +++ b/submodules/LottieCpp/lottiecpp @@ -1 +1 @@ -Subproject commit 2b10b84f626c66288366f0ad2d6af2a396ec454e +Subproject commit b885e63e766890d1cbf36b66cfe27cca55a6ec90 diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index b489cc44de..8437adddd2 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -4141,7 +4141,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } } else if self.interactiveReadActionDisposable == nil { if case let .peer(peerId) = self.chatLocation { - if !self.context.sharedContext.immediateExperimentalUISettings.skipReadHistory { + if !self.context.sharedContext.immediateExperimentalUISettings.skipReadHistory && !self.context.account.isSupportUser { self.interactiveReadActionDisposable = self.context.engine.messages.installInteractiveReadMessagesAction(peerId: peerId) } }