From 1ac6055be90c6584f54159049237e7cbd6fbdcb1 Mon Sep 17 00:00:00 2001 From: AmirHossein Aghajari Date: Tue, 5 Jan 2021 21:09:45 +0330 Subject: [PATCH] 1.0.2 --- AXrLottie/src/main/cpp/CMakeLists.txt | 1 - AXrLottie/src/main/cpp/gif/gif.h | 18 +- AXrLottie/src/main/cpp/inc/CMakeLists.txt | 0 AXrLottie/src/main/cpp/inc/meson.build | 5 + AXrLottie/src/main/cpp/inc/rlottie.h | 182 +- AXrLottie/src/main/cpp/inc/rlottie_capi.h | 127 +- AXrLottie/src/main/cpp/inc/rlottiecommon.h | 140 +- AXrLottie/src/main/cpp/lottie.cpp | 124 +- AXrLottie/src/main/cpp/lottie.h | 5 + AXrLottie/src/main/cpp/src/CMakeLists.txt | 0 .../src/main/cpp/src/lottie/CMakeLists.txt | 1 + .../main/cpp/src/lottie/lottieanimation.cpp | 307 ++- .../src/main/cpp/src/lottie/lottieitem.cpp | 1463 +++++------- .../src/main/cpp/src/lottie/lottieitem.h | 906 +++---- .../src/main/cpp/src/lottie/lottiekeypath.h | 55 +- .../src/main/cpp/src/lottie/lottieloader.cpp | 175 +- .../src/main/cpp/src/lottie/lottieloader.h | 39 - .../src/main/cpp/src/lottie/lottiemodel.cpp | 263 ++- .../src/main/cpp/src/lottie/lottiemodel.h | 1583 +++++++------ .../src/main/cpp/src/lottie/lottieparser.cpp | 1830 +++++++-------- .../src/main/cpp/src/lottie/lottieparser.h | 37 - .../main/cpp/src/lottie/lottieproxymodel.h | 381 --- .../cpp/src/lottie/rapidjson/allocators.h | 8 +- .../lottie/rapidjson/cursorstreamwrapper.h | 0 .../main/cpp/src/lottie/rapidjson/document.h | 108 +- .../cpp/src/lottie/rapidjson/encodedstream.h | 0 .../main/cpp/src/lottie/rapidjson/encodings.h | 0 .../main/cpp/src/lottie/rapidjson/error/en.h | 0 .../cpp/src/lottie/rapidjson/error/error.h | 0 .../cpp/src/lottie/rapidjson/filereadstream.h | 0 .../src/lottie/rapidjson/filewritestream.h | 0 .../src/main/cpp/src/lottie/rapidjson/fwd.h | 2 +- .../lottie/rapidjson/internal/biginteger.h | 2 +- .../cpp/src/lottie/rapidjson/internal/clzll.h | 0 .../cpp/src/lottie/rapidjson/internal/diyfp.h | 18 +- .../cpp/src/lottie/rapidjson/internal/dtoa.h | 0 .../src/lottie/rapidjson/internal/ieee754.h | 0 .../cpp/src/lottie/rapidjson/internal/itoa.h | 0 .../cpp/src/lottie/rapidjson/internal/meta.h | 0 .../cpp/src/lottie/rapidjson/internal/pow10.h | 0 .../cpp/src/lottie/rapidjson/internal/regex.h | 7 +- .../cpp/src/lottie/rapidjson/internal/stack.h | 0 .../src/lottie/rapidjson/internal/strfunc.h | 0 .../src/lottie/rapidjson/internal/strtod.h | 0 .../cpp/src/lottie/rapidjson/internal/swap.h | 0 .../cpp/src/lottie/rapidjson/istreamwrapper.h | 0 .../cpp/src/lottie/rapidjson/memorybuffer.h | 0 .../cpp/src/lottie/rapidjson/memorystream.h | 0 .../lottie/rapidjson/msinttypes/inttypes.h | 0 .../src/lottie/rapidjson/msinttypes/stdint.h | 0 .../cpp/src/lottie/rapidjson/ostreamwrapper.h | 0 .../main/cpp/src/lottie/rapidjson/pointer.h | 9 +- .../cpp/src/lottie/rapidjson/prettywriter.h | 2 +- .../main/cpp/src/lottie/rapidjson/rapidjson.h | 40 +- .../main/cpp/src/lottie/rapidjson/reader.h | 74 +- .../main/cpp/src/lottie/rapidjson/schema.h | 3 +- .../main/cpp/src/lottie/rapidjson/stream.h | 29 +- .../cpp/src/lottie/rapidjson/stringbuffer.h | 0 .../main/cpp/src/lottie/rapidjson/writer.h | 15 +- .../src/main/cpp/src/vector/CMakeLists.txt | 3 +- AXrLottie/src/main/cpp/src/vector/config.h | 13 - .../cpp/src/vector/freetype/CMakeLists.txt | 0 .../cpp/src/vector/freetype/v_ft_math.cpp | 33 +- .../main/cpp/src/vector/freetype/v_ft_math.h | 0 .../cpp/src/vector/freetype/v_ft_raster.cpp | 459 ++-- .../cpp/src/vector/freetype/v_ft_raster.h | 6 - .../cpp/src/vector/freetype/v_ft_stroker.cpp | 497 ++-- .../cpp/src/vector/freetype/v_ft_stroker.h | 0 .../main/cpp/src/vector/freetype/v_ft_types.h | 0 .../main/cpp/src/vector/pixman/CMakeLists.txt | 5 - .../src/vector/pixman/pixman-arm-neon-asm.S | 0 .../src/vector/pixman/pixman-arm-neon-asm.h | 0 .../vector/pixman/pixman-arma64-neon-asm.S | 418 ---- .../vector/pixman/pixman-arma64-neon-asm.h | 1223 ---------- .../main/cpp/src/vector/pixman/vregion.cpp | 2086 ----------------- .../src/main/cpp/src/vector/pixman/vregion.h | 89 - .../main/cpp/src/vector/stb/CMakeLists.txt | 0 .../src/main/cpp/src/vector/stb/stb_image.cpp | 58 +- .../src/main/cpp/src/vector/stb/stb_image.h | 207 +- .../src/main/cpp/src/vector/varenaalloc.cpp | 0 .../src/main/cpp/src/vector/varenaalloc.h | 0 AXrLottie/src/main/cpp/src/vector/vbezier.cpp | 68 +- AXrLottie/src/main/cpp/src/vector/vbezier.h | 69 +- AXrLottie/src/main/cpp/src/vector/vbitmap.cpp | 244 +- AXrLottie/src/main/cpp/src/vector/vbitmap.h | 91 +- AXrLottie/src/main/cpp/src/vector/vbrush.cpp | 99 +- AXrLottie/src/main/cpp/src/vector/vbrush.h | 99 +- .../cpp/src/vector/vcompositionfunctions.cpp | 174 -- AXrLottie/src/main/cpp/src/vector/vcowptr.h | 52 +- AXrLottie/src/main/cpp/src/vector/vdasher.cpp | 102 +- AXrLottie/src/main/cpp/src/vector/vdasher.h | 46 +- AXrLottie/src/main/cpp/src/vector/vdebug.cpp | 34 +- AXrLottie/src/main/cpp/src/vector/vdebug.h | 36 +- .../src/main/cpp/src/vector/vdrawable.cpp | 119 +- AXrLottie/src/main/cpp/src/vector/vdrawable.h | 94 +- .../src/main/cpp/src/vector/vdrawhelper.cpp | 491 ++-- .../src/main/cpp/src/vector/vdrawhelper.h | 246 +- .../cpp/src/vector/vdrawhelper_common.cpp | 0 .../main/cpp/src/vector/vdrawhelper_neon.cpp | 10 +- .../main/cpp/src/vector/vdrawhelper_sse2.cpp | 0 .../src/main/cpp/src/vector/velapsedtimer.cpp | 35 +- .../src/main/cpp/src/vector/velapsedtimer.h | 36 +- AXrLottie/src/main/cpp/src/vector/vglobal.h | 159 +- .../src/main/cpp/src/vector/vimageloader.cpp | 68 +- .../src/main/cpp/src/vector/vimageloader.h | 2 +- .../src/main/cpp/src/vector/vinterpolator.cpp | 46 +- .../src/main/cpp/src/vector/vinterpolator.h | 42 +- AXrLottie/src/main/cpp/src/vector/vline.h | 43 +- AXrLottie/src/main/cpp/src/vector/vmatrix.cpp | 112 +- AXrLottie/src/main/cpp/src/vector/vmatrix.h | 58 +- .../src/main/cpp/src/vector/vpainter.cpp | 126 +- AXrLottie/src/main/cpp/src/vector/vpainter.h | 56 +- AXrLottie/src/main/cpp/src/vector/vpath.cpp | 58 +- AXrLottie/src/main/cpp/src/vector/vpath.h | 50 +- .../src/main/cpp/src/vector/vpathmesure.cpp | 40 +- .../src/main/cpp/src/vector/vpathmesure.h | 38 +- AXrLottie/src/main/cpp/src/vector/vpoint.h | 45 +- AXrLottie/src/main/cpp/src/vector/vraster.cpp | 200 +- AXrLottie/src/main/cpp/src/vector/vraster.h | 38 +- AXrLottie/src/main/cpp/src/vector/vrect.cpp | 34 +- AXrLottie/src/main/cpp/src/vector/vrect.h | 68 +- AXrLottie/src/main/cpp/src/vector/vrle.cpp | 745 +++--- AXrLottie/src/main/cpp/src/vector/vrle.h | 215 +- .../src/main/cpp/src/vector/vsharedptr.h | 0 .../src/main/cpp/src/vector/vstackallocator.h | 36 +- .../src/main/cpp/src/vector/vtaskqueue.h | 36 +- .../java/com/aghajari/rlottie/AXrLottie.java | 92 +- .../aghajari/rlottie/AXrLottieDrawable.java | 103 +- .../aghajari/rlottie/AXrLottieImageView.java | 6 - .../aghajari/rlottie/AXrLottieLayerInfo.java | 40 +- .../com/aghajari/rlottie/AXrLottieMarker.java | 85 + .../com/aghajari/rlottie/AXrLottieNative.java | 10 +- .../aghajari/rlottie/AXrLottieProperty.java | 17 +- .../com/aghajari/rlottie/DispatchQueue.java | 25 +- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 1 + app/src/main/assets/mountain.json | 1 + .../sample/axrlottie/CustomEditText.java | 43 - .../sample/axrlottie/MainActivity.java | 5 + .../activity/AXEmojiViewActivity.java | 18 +- .../activity/ColorLayerActivity.java | 26 +- .../activity/LottieEditorActivity.java | 118 + .../axrlottie/activity/SimpleActivity.java | 8 +- app/src/main/res/layout/activity_editor.xml | 25 + .../main/res/layout/activity_emoji_view.xml | 51 +- app/src/main/res/layout/activity_main.xml | 6 + app/src/main/res/layout/rv_layer_info.xml | 21 + deploy.settings | 2 +- 148 files changed, 7045 insertions(+), 11176 deletions(-) mode change 100755 => 100644 AXrLottie/src/main/cpp/inc/CMakeLists.txt create mode 100644 AXrLottie/src/main/cpp/inc/meson.build mode change 100755 => 100644 AXrLottie/src/main/cpp/inc/rlottie.h mode change 100755 => 100644 AXrLottie/src/main/cpp/inc/rlottie_capi.h mode change 100755 => 100644 AXrLottie/src/main/cpp/inc/rlottiecommon.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/CMakeLists.txt delete mode 100755 AXrLottie/src/main/cpp/src/lottie/lottieloader.h delete mode 100755 AXrLottie/src/main/cpp/src/lottie/lottieparser.h delete mode 100755 AXrLottie/src/main/cpp/src/lottie/lottieproxymodel.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/allocators.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/cursorstreamwrapper.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/document.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/encodedstream.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/encodings.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/error/en.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/error/error.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/filereadstream.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/filewritestream.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/fwd.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/biginteger.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/clzll.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/diyfp.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/dtoa.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/ieee754.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/itoa.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/meta.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/pow10.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/regex.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/stack.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strfunc.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strtod.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/swap.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/istreamwrapper.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/memorybuffer.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/memorystream.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/inttypes.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/stdint.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/ostreamwrapper.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/pointer.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/prettywriter.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/rapidjson.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/reader.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/schema.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/stream.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/stringbuffer.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/lottie/rapidjson/writer.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/CMakeLists.txt delete mode 100755 AXrLottie/src/main/cpp/src/vector/config.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/CMakeLists.txt mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/freetype/v_ft_types.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/pixman/CMakeLists.txt mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.S mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.h delete mode 100755 AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.S delete mode 100755 AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.h delete mode 100755 AXrLottie/src/main/cpp/src/vector/pixman/vregion.cpp delete mode 100755 AXrLottie/src/main/cpp/src/vector/pixman/vregion.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/stb/CMakeLists.txt mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/stb/stb_image.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/stb/stb_image.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/varenaalloc.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/varenaalloc.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbezier.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbezier.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbitmap.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbitmap.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbrush.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vbrush.h delete mode 100755 AXrLottie/src/main/cpp/src/vector/vcompositionfunctions.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vcowptr.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdasher.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdasher.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdebug.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdebug.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawable.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawable.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawhelper.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawhelper.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawhelper_common.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawhelper_neon.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vdrawhelper_sse2.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/velapsedtimer.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/velapsedtimer.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vglobal.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vimageloader.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vimageloader.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vinterpolator.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vinterpolator.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vline.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vmatrix.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vmatrix.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpainter.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpainter.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpath.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpath.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpathmesure.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpathmesure.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vpoint.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vraster.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vraster.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vrect.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vrect.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vrle.cpp mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vrle.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vsharedptr.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vstackallocator.h mode change 100755 => 100644 AXrLottie/src/main/cpp/src/vector/vtaskqueue.h create mode 100644 AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieMarker.java create mode 100644 app/src/main/assets/mountain.json delete mode 100644 app/src/main/java/com/aghajari/sample/axrlottie/CustomEditText.java create mode 100644 app/src/main/java/com/aghajari/sample/axrlottie/activity/LottieEditorActivity.java create mode 100644 app/src/main/res/layout/activity_editor.xml create mode 100644 app/src/main/res/layout/rv_layer_info.xml diff --git a/AXrLottie/src/main/cpp/CMakeLists.txt b/AXrLottie/src/main/cpp/CMakeLists.txt index 03ed2a2..11d5887 100755 --- a/AXrLottie/src/main/cpp/CMakeLists.txt +++ b/AXrLottie/src/main/cpp/CMakeLists.txt @@ -205,7 +205,6 @@ target_link_libraries(jlottie rlottie2gif) target_link_libraries( # Specifies the target library. jlottie -ljnigraphics - # Links the target library to the log library # included in the NDK. ${log-lib} ) diff --git a/AXrLottie/src/main/cpp/gif/gif.h b/AXrLottie/src/main/cpp/gif/gif.h index 781909a..79a24d7 100755 --- a/AXrLottie/src/main/cpp/gif/gif.h +++ b/AXrLottie/src/main/cpp/gif/gif.h @@ -865,14 +865,14 @@ class GifBuilder { } void addFrame(rlottie::Surface &s,bool transparent, uint32_t delay = 2,int32_t bitDepth = 8, bool dither = false) { - if(!transparent) argbTorgba(s); + convertToCanvasFormat(s); GifWriteFrame(&handle, reinterpret_cast(s.buffer()), s.width(), s.height(), delay,bitDepth,dither); } - void argbTorgba(rlottie::Surface &s) + void convertToCanvasFormat(rlottie::Surface &s) { uint8_t *buffer = reinterpret_cast(s.buffer()); uint32_t totalBytes = s.height() * s.bytesPerLine(); @@ -889,20 +889,20 @@ class GifBuilder { unsigned char r2 = (unsigned char) ((float) bgColorR * ((float) (255 - a) / 255)); unsigned char g2 = (unsigned char) ((float) bgColorG * ((float) (255 - a) / 255)); unsigned char b2 = (unsigned char) ((float) bgColorB * ((float) (255 - a) / 255)); - buffer[i+2] = r + r2; + buffer[i] = r + r2; buffer[i+1] = g + g2; - buffer[i] = b + b2; + buffer[i+2] = b + b2; } else { // only swizzle r and b - buffer[i+2] = r; + buffer[i] = r; buffer[i+1] = g; - buffer[i] = b; + buffer[i+2] = b; } } else { - buffer[i] = bgColorB; + buffer[i+2] = bgColorB; buffer[i+1] = bgColorG; - buffer[i+2] = bgColorR; + buffer[i] = bgColorR; } } } @@ -938,6 +938,7 @@ class Lottie2Gif { for (size_t i = start; i < end; i++) { rlottie::Surface surface((uint32_t *) pixels, (size_t) w, (size_t)h,(size_t) stride); player->animation->renderSync(i, surface); + //LottieWrapper::convertToCanvasFormat(surface); builder.addFrame(surface, transparent,delay,bitDepth,dither); env->CallVoidMethod(store_Wlistener, mth_update, (jint) (i + 1), @@ -949,6 +950,7 @@ class Lottie2Gif { for (size_t i = start; i < end; i++) { rlottie::Surface surface((uint32_t *) pixels, (size_t)w, (size_t)h,(size_t)stride); player->animation->renderSync(i, surface); + //LottieWrapper::convertToCanvasFormat(surface); builder.addFrame(surface, transparent,delay,bitDepth,dither); } } diff --git a/AXrLottie/src/main/cpp/inc/CMakeLists.txt b/AXrLottie/src/main/cpp/inc/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/inc/meson.build b/AXrLottie/src/main/cpp/inc/meson.build new file mode 100644 index 0000000..0349fac --- /dev/null +++ b/AXrLottie/src/main/cpp/inc/meson.build @@ -0,0 +1,5 @@ +install_headers([ + 'rlottie.h', + 'rlottie_capi.h', + 'rlottiecommon.h', + ]) diff --git a/AXrLottie/src/main/cpp/inc/rlottie.h b/AXrLottie/src/main/cpp/inc/rlottie.h old mode 100755 new mode 100644 index ea0d0da..0c39196 --- a/AXrLottie/src/main/cpp/inc/rlottie.h +++ b/AXrLottie/src/main/cpp/inc/rlottie.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _RLOTTIE_H_ @@ -22,28 +26,19 @@ #include #include #include -#include -#ifdef _WIN32 -#ifdef LOT_BUILD -#ifdef DLL_EXPORT -#define LOT_EXPORT __declspec(dllexport) +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __declspec(dllexport) + #else + #define RLOTTIE_API __declspec(dllimport) + #endif #else -#define LOT_EXPORT -#endif -#else -#define LOT_EXPORT __declspec(dllimport) -#endif -#else -#ifdef __GNUC__ -#if __GNUC__ >= 4 -#define LOT_EXPORT __attribute__((visibility("default"))) -#else -#define LOT_EXPORT -#endif -#else -#define LOT_EXPORT -#endif + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __attribute__ ((visibility ("default"))) + #else + #define RLOTTIE_API + #endif #endif class AnimationImpl; @@ -52,6 +47,23 @@ struct LOTLayerNode; namespace rlottie { +/** + * @brief Configures rlottie model cache policy. + * + * Provides Library level control to configure model cache + * policy. Setting it to 0 will disable + * the cache as well as flush all the previously cached content. + * + * @param[in] cacheSize Maximum Model Cache size. + * + * @note to disable Caching configure with 0 size. + * @note to flush the current Cache content configure it with 0 and + * then reconfigure with the new size. + * + * @internal + */ +RLOTTIE_API void configureModelCacheSize(size_t cacheSize); + struct Color { Color() = default; Color(float r, float g , float b):_r(r), _g(g), _b(b){} @@ -92,14 +104,15 @@ struct FrameInfo { }; enum class Property { - Color, /*!< Color property of Fill object , value type is rlottie::Color */ + FillColor, /*!< Color property of Fill object , value type is rlottie::Color */ FillOpacity, /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */ + StrokeColor, /*!< Color property of Stroke object , value type is rlottie::Color */ StrokeOpacity, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */ - StrokeWidth, /*!< stroke with property of Stroke object , value type is float */ + StrokeWidth, /*!< stroke width property of Stroke object , value type is float */ TrAnchor, /*!< Transform Anchor property of Layer and Group object , value type is rlottie::Point */ TrPosition, /*!< Transform Position property of Layer and Group object , value type is rlottie::Point */ TrScale, /*!< Transform Scale property of Layer and Group object , value type is rlottie::Size. range[0 ..100] */ - TrRotation, /*!< Transform Scale property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/ + TrRotation, /*!< Transform Rotation property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/ TrOpacity /*!< Transform Opacity property of Layer and Group object , value type is float [ 0 .. 100] */ }; @@ -109,7 +122,7 @@ struct Size_Type{}; struct Float_Type{}; template struct MapType; -class LOT_EXPORT Surface { +class RLOTTIE_API Surface { public: /** * @brief Surface object constructor. @@ -242,15 +255,30 @@ class LOT_EXPORT Surface { }mDrawArea; }; -using LayerInfoList = std::vector>; +using MarkerList = std::vector>; +/** + * @brief https://helpx.adobe.com/after-effects/using/layer-markers-composition-markers.html + * Markers exported form AE are used to describe a segmnet of an animation {comment/tag , startFrame, endFrame} + * Marker can be use to devide a resource in to separate animations by tagging the segment with comment string , + * start frame and duration of that segment. + */ + +using LayerInfoList = std::vector>; + + +using ColorFilter = std::function; -class LOT_EXPORT Animation { +class RLOTTIE_API Animation { public: /** * @brief Constructs an animation object from file path. * * @param[in] path Lottie resource file path + * @param[in] cachePolicy whether to cache or not the model data. + * use only when need to explicit disabl caching for a + * particular resource. To disable caching at library level + * use @see configureModelCacheSize() instead. * * @return Animation object that can render the contents of the * Lottie resource represented by file path. @@ -258,7 +286,7 @@ class LOT_EXPORT Animation { * @internal */ static std::unique_ptr - loadFromFile(const std::string &path, std::map *colorReplacement); + loadFromFile(const std::string &path, bool cachePolicy=true); /** * @brief Constructs an animation object from JSON string data. @@ -266,14 +294,36 @@ class LOT_EXPORT Animation { * @param[in] jsonData The JSON string data. * @param[in] key the string that will be used to cache the JSON string data. * @param[in] resourcePath the path will be used to search for external resource. + * @param[in] cachePolicy whether to cache or not the model data. + * use only when need to explicit disabl caching for a + * particular resource. To disable caching at library level + * use @see configureModelCacheSize() instead. + * + * @return Animation object that can render the contents of the + * Lottie resource represented by JSON string data. * + * @internal + */ + static std::unique_ptr + loadFromData(std::string jsonData, const std::string &key, + const std::string &resourcePath="", bool cachePolicy=true); + + /** + * @brief Constructs an animation object from JSON string data and update. + * the color properties using ColorFilter. + + * @param[in] jsonData The JSON string data. + * @param[in] resourcePath the path will be used to search for external resource. + * @param[in] filter The color filter that will be applied for each color property + * found during parsing. + * @return Animation object that can render the contents of the * Lottie resource represented by JSON string data. * * @internal */ static std::unique_ptr - loadFromData(std::string jsonData, const std::string &key, std::map *colorReplacement, const std::string &resourcePath=""); + loadFromData(std::string jsonData, std::string resourcePath, ColorFilter filter); /** * @brief Returns default framerate of the Lottie resource. @@ -336,16 +386,40 @@ class LOT_EXPORT Animation { */ size_t frameAtPos(double pos); + /** + * @brief Renders the content to surface Asynchronously. + * it gives a future in return to get the result of the + * rendering at a future point. + * To get best performance user has to start rendering as soon as + * it finds that content at {frameNo} has to be rendered and get the + * result from the future at the last moment when the surface is needed + * to draw into the screen. + * + * + * @param[in] frameNo Content corresponds to the @p frameNo needs to be drawn + * @param[in] surface Surface in which content will be drawn + * @param[in] keepAspectRatio whether to keep the aspect ratio while scaling the content. + * + * @return future that will hold the result when rendering finished. + * + * for Synchronus rendering @see renderSync + * + * @see Surface + * @internal + */ + std::future render(size_t frameNo, Surface surface, bool keepAspectRatio=true); + /** * @brief Renders the content to surface synchronously. * for performance use the async rendering @see render * * @param[in] frameNo Content corresponds to the @p frameNo needs to be drawn * @param[in] surface Surface in which content will be drawn + * @param[in] keepAspectRatio whether to keep the aspect ratio while scaling the content. * * @internal */ - void renderSync(size_t frameNo, Surface &surface); + void renderSync(size_t frameNo, Surface surface, bool keepAspectRatio=true); /** * @brief Returns root layer of the composition updated with @@ -362,7 +436,18 @@ class LOT_EXPORT Animation { const LOTLayerNode * renderTree(size_t frameNo, size_t width, size_t height) const; /** - * @brief Returns Layer information{name, inFrame, outFrame} of all the child layers of the composition. + * @brief Returns Composition Markers. + * + * + * @return returns MarkerList of the Composition. + * + * @see MarkerList + * @internal + */ + const MarkerList& markers() const; + + /** + * @brief Returns Layer information{name, inFrame, outFrame, type} of all the child layers of the composition. * * * @return List of Layer Information of the Composition. @@ -402,8 +487,6 @@ class LOT_EXPORT Animation { */ ~Animation(); - std::map *colorMap{nullptr}; - void resetCurrentFrame(); private: void setValue(Color_Type, Property, const std::string &, Color); void setValue(Float_Type, Property, const std::string &, float); @@ -425,7 +508,8 @@ class LOT_EXPORT Animation { }; //Map Property to Value type -template<> struct MapType>: Color_Type{}; +template<> struct MapType>: Color_Type{}; +template<> struct MapType>: Color_Type{}; template<> struct MapType>: Float_Type{}; template<> struct MapType>: Float_Type{}; template<> struct MapType>: Float_Type{}; diff --git a/AXrLottie/src/main/cpp/inc/rlottie_capi.h b/AXrLottie/src/main/cpp/inc/rlottie_capi.h old mode 100755 new mode 100644 index a5cb70a..9bdf336 --- a/AXrLottie/src/main/cpp/inc/rlottie_capi.h +++ b/AXrLottie/src/main/cpp/inc/rlottie_capi.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _RLOTTIE_CAPI_H_ @@ -27,6 +31,19 @@ extern "C" { #endif +typedef enum { + LOTTIE_ANIMATION_PROPERTY_FILLCOLOR, /*!< Color property of Fill object , value type is float [0 ... 1] */ + LOTTIE_ANIMATION_PROPERTY_FILLOPACITY, /*!< Opacity property of Fill object , value type is float [ 0 .. 100] */ + LOTTIE_ANIMATION_PROPERTY_STROKECOLOR, /*!< Color property of Stroke object , value type is float [0 ... 1] */ + LOTTIE_ANIMATION_PROPERTY_STROKEOPACITY, /*!< Opacity property of Stroke object , value type is float [ 0 .. 100] */ + LOTTIE_ANIMATION_PROPERTY_STROKEWIDTH, /*!< stroke with property of Stroke object , value type is float */ + LOTTIE_ANIMATION_PROPERTY_TR_ANCHOR, /*!< Transform Anchor property of Layer and Group object , value type is int */ + LOTTIE_ANIMATION_PROPERTY_TR_POSITION, /*!< Transform Position property of Layer and Group object , value type is int */ + LOTTIE_ANIMATION_PROPERTY_TR_SCALE, /*!< Transform Scale property of Layer and Group object , value type is float range[0 ..100] */ + LOTTIE_ANIMATION_PROPERTY_TR_ROTATION, /*!< Transform Scale property of Layer and Group object , value type is float. range[0 .. 360] in degrees*/ + LOTTIE_ANIMATION_PROPERTY_TR_OPACITY /*!< Transform Opacity property of Layer and Group object , value type is float [ 0 .. 100] */ +}Lottie_Animation_Property; + typedef struct Lottie_Animation_S Lottie_Animation; /** @@ -42,7 +59,7 @@ typedef struct Lottie_Animation_S Lottie_Animation; * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT Lottie_Animation *lottie_animation_from_file(const char *path); +RLOTTIE_API Lottie_Animation *lottie_animation_from_file(const char *path); /** * @brief Constructs an animation object from JSON string data. @@ -57,7 +74,7 @@ LOT_EXPORT Lottie_Animation *lottie_animation_from_file(const char *path); * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT Lottie_Animation *lottie_animation_from_data(const char *data, const char *key, const char *resource_path); +RLOTTIE_API Lottie_Animation *lottie_animation_from_data(const char *data, const char *key, const char *resource_path); /** * @brief Free given Animation object resource. @@ -70,7 +87,7 @@ LOT_EXPORT Lottie_Animation *lottie_animation_from_data(const char *data, const * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT void lottie_animation_destroy(Lottie_Animation *animation); +RLOTTIE_API void lottie_animation_destroy(Lottie_Animation *animation); /** * @brief Returns default viewport size of the Lottie resource. @@ -82,7 +99,7 @@ LOT_EXPORT void lottie_animation_destroy(Lottie_Animation *animation); * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT void lottie_animation_get_size(const Lottie_Animation *animation, size_t *width, size_t *height); +RLOTTIE_API void lottie_animation_get_size(const Lottie_Animation *animation, size_t *width, size_t *height); /** * @brief Returns total animation duration of Lottie resource in second. @@ -100,7 +117,7 @@ LOT_EXPORT void lottie_animation_get_size(const Lottie_Animation *animation, siz * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT double lottie_animation_get_duration(const Lottie_Animation *animation); +RLOTTIE_API double lottie_animation_get_duration(const Lottie_Animation *animation); /** * @brief Returns total number of frames present in the Lottie resource. @@ -117,7 +134,7 @@ LOT_EXPORT double lottie_animation_get_duration(const Lottie_Animation *animatio * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT size_t lottie_animation_get_totalframe(const Lottie_Animation *animation); +RLOTTIE_API size_t lottie_animation_get_totalframe(const Lottie_Animation *animation); /** * @brief Returns default framerate of the Lottie resource. @@ -130,7 +147,7 @@ LOT_EXPORT size_t lottie_animation_get_totalframe(const Lottie_Animation *animat * @internal * */ -LOT_EXPORT double lottie_animation_get_framerate(const Lottie_Animation *animation); +RLOTTIE_API double lottie_animation_get_framerate(const Lottie_Animation *animation); /** * @brief Get the render tree which contains the snapshot of the animation object @@ -151,9 +168,7 @@ LOT_EXPORT double lottie_animation_get_framerate(const Lottie_Animation *animati * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT const LOTLayerNode * lottie_animation_render_tree(Lottie_Animation *animation, - size_t frame_num, - size_t width, size_t height); +RLOTTIE_API const LOTLayerNode *lottie_animation_render_tree(Lottie_Animation *animation, size_t frame_num, size_t width, size_t height); /** * @brief Maps position to frame number and returns it. @@ -168,7 +183,7 @@ LOT_EXPORT const LOTLayerNode * lottie_animation_render_tree(Lottie_Animation *a * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT size_t lottie_animation_get_frame_at_pos(const Lottie_Animation *animation, float pos); +RLOTTIE_API size_t lottie_animation_get_frame_at_pos(const Lottie_Animation *animation, float pos); /** * @brief Request to render the content of the frame @p frame_num to buffer @p buffer. @@ -184,13 +199,7 @@ LOT_EXPORT size_t lottie_animation_get_frame_at_pos(const Lottie_Animation *anim * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT void -lottie_animation_render(Lottie_Animation *animation, - size_t frame_num, - uint32_t *buffer, - size_t width, - size_t height, - size_t bytes_per_line); +RLOTTIE_API void lottie_animation_render(Lottie_Animation *animation, size_t frame_num, uint32_t *buffer, size_t width, size_t height, size_t bytes_per_line); /** * @brief Request to render the content of the frame @p frame_num to buffer @p buffer asynchronously. @@ -207,13 +216,7 @@ lottie_animation_render(Lottie_Animation *animation, * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT void -lottie_animation_render_async(Lottie_Animation *animation, - size_t frame_num, - uint32_t *buffer, - size_t width, - size_t height, - size_t bytes_per_line); +RLOTTIE_API void lottie_animation_render_async(Lottie_Animation *animation, size_t frame_num, uint32_t *buffer, size_t width, size_t height, size_t bytes_per_line); /** * @brief Request to finish the current async renderer job for this animation object. @@ -230,8 +233,46 @@ lottie_animation_render_async(Lottie_Animation *animation, * @ingroup Lottie_Animation * @internal */ -LOT_EXPORT uint32_t * -lottie_animation_render_flush(Lottie_Animation *animation); +RLOTTIE_API uint32_t *lottie_animation_render_flush(Lottie_Animation *animation); + + +/** + * @brief Request to change the properties of this animation object. + * Keypath should conatin object names separated by (.) and can handle globe(**) or wildchar(*) + * + * @usage + * To change fillcolor property of fill1 object in the layer1->group1->fill1 hirarchy to RED color + * + * lottie_animation_property_override(animation, LOTTIE_ANIMATION_PROPERTY_FILLCOLOR, "layer1.group1.fill1", 1.0, 0.0, 0.0); + * + * if all the color property inside group1 needs to be changed to GREEN color + * + * lottie_animation_property_override(animation, LOTTIE_ANIMATION_PROPERTY_FILLCOLOR, "**.group1.**", 1.0, 0.0, 0.0); + * + * @param[in] animation Animation object. + * @param[in] type Property type. (@p Lottie_Animation_Property) + * @param[in] keypath Specific content of target. + * @param[in] ... Property values. + * + * @ingroup Lottie_Animation + * @internal + * */ +RLOTTIE_API void lottie_animation_property_override(Lottie_Animation *animation, const Lottie_Animation_Property type, const char *keypath, ...); + + +/** + * @brief Returns list of markers in the Lottie resource + * @p LOTMarkerList has a @p LOTMarker list and size of list + * @p LOTMarker has the marker's name, start frame, and end frame. + * + * @param[in] animation Animation object. + * + * @return The list of marker. If there is no marker, return null. + * + * @ingroup Lottie_Animation + * @internal + * */ +RLOTTIE_API const LOTMarkerList* lottie_animation_get_markerlist(Lottie_Animation *animation); #ifdef __cplusplus } diff --git a/AXrLottie/src/main/cpp/inc/rlottiecommon.h b/AXrLottie/src/main/cpp/inc/rlottiecommon.h old mode 100755 new mode 100644 index b3ac022..784fbe2 --- a/AXrLottie/src/main/cpp/inc/rlottiecommon.h +++ b/AXrLottie/src/main/cpp/inc/rlottiecommon.h @@ -1,44 +1,40 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _RLOTTIE_COMMON_H_ #define _RLOTTIE_COMMON_H_ -#ifdef _WIN32 -#ifdef LOT_BUILD -#ifdef DLL_EXPORT -#define LOT_EXPORT __declspec(dllexport) +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __declspec(dllexport) + #else + #define RLOTTIE_API __declspec(dllimport) + #endif #else -#define LOT_EXPORT -#endif -#else -#define LOT_EXPORT __declspec(dllimport) -#endif -#else -#ifdef __GNUC__ -#if __GNUC__ >= 4 -#define LOT_EXPORT __attribute__((visibility("default"))) -#else -#define LOT_EXPORT -#endif -#else -#define LOT_EXPORT -#endif + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __attribute__ ((visibility ("default"))) + #else + #define RLOTTIE_API + #endif #endif @@ -60,22 +56,6 @@ * @ingroup Lottie_Animation */ - -/** - * @brief Enumeration for Lottie Player error code. - */ -typedef enum -{ - //TODO: Coding convention?? - LOT_ANIMATION_ERROR_NONE = 0, - LOT_ANIMATION_ERROR_NOT_PERMITTED, - LOT_ANIMATION_ERROR_OUT_OF_MEMORY, - LOT_ANIMATION_ERROR_INVALID_PARAMETER, - LOT_ANIMATION_ERROR_RESULT_OUT_OF_RANGE, - LOT_ANIMATION_ERROR_ALREADY_IN_PROGRESS, - LOT_ANIMATION_ERROR_UNKNOWN -} LOTErrorType; - typedef enum { BrushSolid = 0, @@ -125,12 +105,12 @@ typedef enum typedef struct LOTMask { struct { const float *ptPtr; - int ptCount; + size_t ptCount; const char* elmPtr; - int elmCount; + size_t elmCount; } mPath; LOTMaskType mMode; - int mAlpha; + unsigned char mAlpha; }LOTMask; typedef enum @@ -142,6 +122,17 @@ typedef enum MatteLumaInv } LOTMatteType; +typedef struct LOTMarker { + char *name; + size_t startframe; + size_t endframe; +} LOTMarker; + +typedef struct LOTMarkerList { + LOTMarker *ptr; + size_t size; +} LOTMarkerList; + typedef struct LOTNode { #define ChangeFlagNone 0x0000 @@ -151,9 +142,9 @@ typedef struct LOTNode { struct { const float *ptPtr; - int ptCount; - const char* elmPtr; - int elmCount; + size_t ptCount; + const char *elmPtr; + size_t elmCount; } mPath; struct { @@ -162,18 +153,18 @@ typedef struct LOTNode { struct { unsigned char enable; - int width; + float width; LOTCapStyle cap; LOTJoinStyle join; - int meterLimit; - float* dashArray; + float miterLimit; + float *dashArray; int dashArraySize; } mStroke; struct { - LOTGradientType type; + LOTGradientType type; LOTGradientStop *stopPtr; - unsigned int stopCount; + size_t stopCount; struct { float x, y; } start, end, center, focal; @@ -182,9 +173,10 @@ typedef struct LOTNode { } mGradient; struct { - unsigned char* data; - int width; - int height; + unsigned char *data; + size_t width; + size_t height; + unsigned char mAlpha; struct { float m11; float m12; float m13; float m21; float m22; float m23; @@ -195,6 +187,8 @@ typedef struct LOTNode { int mFlag; LOTBrushType mBrushType; LOTFillRule mFillRule; + + const char *keypath; } LOTNode; @@ -203,30 +197,30 @@ typedef struct LOTLayerNode { struct { LOTMask *ptr; - unsigned int size; + size_t size; } mMaskList; struct { const float *ptPtr; - int ptCount; - const char* elmPtr; - int elmCount; + size_t ptCount; + const char *elmPtr; + size_t elmCount; } mClipPath; struct { struct LOTLayerNode **ptr; - unsigned int size; + size_t size; } mLayerList; struct { LOTNode **ptr; - unsigned int size; + size_t size; } mNodeList; LOTMatteType mMatte; int mVisible; - int mAlpha; - const char *name; + unsigned char mAlpha; + const char *keypath; } LOTLayerNode; diff --git a/AXrLottie/src/main/cpp/lottie.cpp b/AXrLottie/src/main/cpp/lottie.cpp index a7c63c3..f0cf5cf 100755 --- a/AXrLottie/src/main/cpp/lottie.cpp +++ b/AXrLottie/src/main/cpp/lottie.cpp @@ -17,29 +17,14 @@ extern "C" { using namespace rlottie; -jlong Java_com_aghajari_rlottie_AXrLottieNative_create(JNIEnv *env, jclass clazz, jstring src, jint w, jint h, jintArray data, jboolean precache, jintArray colorReplacement, jboolean limitFps) { +jlong Java_com_aghajari_rlottie_AXrLottieNative_create(JNIEnv *env, jclass clazz, jstring src, jint w, jint h, jintArray data, jboolean precache, jboolean limitFps) { LottieInfo *info = new LottieInfo(); std::map *colors = nullptr; - int color = 0; - if (colorReplacement != nullptr) { - jint *arr = env->GetIntArrayElements(colorReplacement, 0); - if (arr != nullptr) { - jsize len = env->GetArrayLength(colorReplacement); - colors = new std::map(); - for (int32_t a = 0; a < len / 2; a++) { - (*colors)[arr[a * 2]] = arr[a * 2 + 1]; - if (color == 0) { - color = arr[a * 2 + 1]; - } - } - env->ReleaseIntArrayElements(colorReplacement, arr, 0); - } - } char const *srcString = env->GetStringUTFChars(src, 0); info->path = srcString; - info->animation = rlottie::Animation::loadFromFile(info->path, colors); + info->animation = rlottie::Animation::loadFromFile(info->path); if (srcString != 0) { env->ReleaseStringUTFChars(src, srcString); } @@ -64,9 +49,6 @@ jlong Java_com_aghajari_rlottie_AXrLottieNative_create(JNIEnv *env, jclass clazz info->cacheFile.insert(index, "/acache"); } info->cacheFile += std::to_string(w) + "_" + std::to_string(h); - if (color != 0) { - info->cacheFile += "_" + std::to_string(color); - } if (limitFps) { info->cacheFile += ".s.cache"; } else { @@ -101,25 +83,12 @@ jlong Java_com_aghajari_rlottie_AXrLottieNative_create(JNIEnv *env, jclass clazz return (jlong) (intptr_t) info; } -jlong Java_com_aghajari_rlottie_AXrLottieNative_createWithJson(JNIEnv *env, jclass clazz, jstring json, jstring name, jintArray data, jintArray colorReplacement) { - std::map *colors = nullptr; - if (colorReplacement != nullptr) { - jint *arr = env->GetIntArrayElements(colorReplacement, 0); - if (arr != nullptr) { - jsize len = env->GetArrayLength(colorReplacement); - colors = new std::map(); - for (int32_t a = 0; a < len / 2; a++) { - (*colors)[arr[a * 2]] = arr[a * 2 + 1]; - } - env->ReleaseIntArrayElements(colorReplacement, arr, 0); - } - } - +jlong Java_com_aghajari_rlottie_AXrLottieNative_createWithJson(JNIEnv *env, jclass clazz, jstring json, jstring name, jintArray data) { LottieInfo *info = new LottieInfo(); char const *jsonString = env->GetStringUTFChars(json, 0); char const *nameString = env->GetStringUTFChars(name, 0); - info->animation = rlottie::Animation::loadFromData(jsonString, nameString, colors); + info->animation = rlottie::Animation::loadFromData(jsonString, nameString); if (jsonString != 0) { env->ReleaseStringUTFChars(json, jsonString); } @@ -238,6 +207,7 @@ void Java_com_aghajari_rlottie_AXrLottieNative_createCache(JNIEnv *env, jclass c Surface &surfaceToRender = num % 2 == 0 ? surface1 : surface2; num++; info->animation->renderSync(a, surfaceToRender); + LottieWrapper::convertToCanvasFormat(surfaceToRender); if (a != 0) { std::unique_lock lk(cacheDoneMutex); cacheDoneCv.wait(lk, [] { return !frameReady.load(); }); @@ -323,6 +293,7 @@ jint Java_com_aghajari_rlottie_AXrLottieNative_getFrame(JNIEnv *env, jclass claz if (!info->nextFrameIsCacheFrame || !info->precache) { Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride); info->animation->renderSync((size_t) frame, surface); + LottieWrapper::convertToCanvasFormat(surface); info->nextFrameIsCacheFrame = true; } } @@ -332,6 +303,36 @@ jint Java_com_aghajari_rlottie_AXrLottieNative_getFrame(JNIEnv *env, jclass claz return frame; } +void LottieWrapper::convertToCanvasFormat(Surface &s) { + uint8_t *buffer = reinterpret_cast(s.buffer()); + uint32_t totalBytes = s.height() * s.bytesPerLine(); + + for (int i = 0; i < totalBytes; i += 4) { + unsigned char a = buffer[i + 3]; + // compute only if alpha is non zero + if (a) { + unsigned char r = buffer[i + 2]; + unsigned char g = buffer[i + 1]; + unsigned char b = buffer[i]; + + if (a != 255) { // un premultiply + r = (r * 255) / a; + g = (g * 255) / a; + b = (b * 255) / a; + + buffer[i] = r; + buffer[i + 1] = g; + buffer[i + 2] = b; + + } else { + buffer[i] = r; + buffer[i + 1] = g; + buffer[i + 2] = b; + } + } + } +} + jint Java_com_aghajari_rlottie_AXrLottieNative_getLayersCount(JNIEnv *env, jclass clazz, jlong ptr){ if (ptr == NULL) { return 0; @@ -346,30 +347,37 @@ jobjectArray Java_com_aghajari_rlottie_AXrLottieNative_getLayerData(JNIEnv *env, } LottieInfo *info = (LottieInfo *) (intptr_t) ptr; - jobjectArray ret =(jobjectArray)env->NewObjectArray(3,env->FindClass("java/lang/String"),env->NewStringUTF("")); + jobjectArray ret =(jobjectArray)env->NewObjectArray(4,env->FindClass("java/lang/String"),env->NewStringUTF("")); - std::tuple layer = info->animation->layers().at(index); + std::tuple layer = info->animation->layers().at(index); env->SetObjectArrayElement(ret,0,env->NewStringUTF(std::get<0>(layer).c_str())); env->SetObjectArrayElement(ret,1,env->NewStringUTF(std::to_string(std::get<1>(layer)).c_str())); env->SetObjectArrayElement(ret,2,env->NewStringUTF(std::to_string(std::get<2>(layer)).c_str())); + env->SetObjectArrayElement(ret,3,env->NewStringUTF(std::to_string(std::get<3>(layer)).c_str())); return(ret); } -void Java_com_aghajari_rlottie_AXrLottieNative_replaceColors(JNIEnv *env, jclass clazz, jlong ptr, jintArray colorReplacement) { - if (ptr == NULL || colorReplacement == nullptr) { - return; +jint Java_com_aghajari_rlottie_AXrLottieNative_getMarkersCount(JNIEnv *env, jclass clazz, jlong ptr){ + if (ptr == NULL) { + return 0; } LottieInfo *info = (LottieInfo *) (intptr_t) ptr; + return info->animation->markers().size(); +} - jint *arr = env->GetIntArrayElements(colorReplacement, 0); - if (arr != nullptr) { - jsize len = env->GetArrayLength(colorReplacement); - for (int32_t a = 0; a < len / 2; a++) { - (*info->animation->colorMap)[arr[a * 2]] = arr[a * 2 + 1]; - } - info->animation->resetCurrentFrame(); - env->ReleaseIntArrayElements(colorReplacement, arr, 0); +jobjectArray Java_com_aghajari_rlottie_AXrLottieNative_getMarkerData(JNIEnv *env, jclass clazz, jlong ptr, jint index){ + if (ptr == NULL) { + return NULL; } + LottieInfo *info = (LottieInfo *) (intptr_t) ptr; + + jobjectArray ret =(jobjectArray)env->NewObjectArray(3,env->FindClass("java/lang/String"),env->NewStringUTF("")); + + std::tuple markers = info->animation->markers().at(index); + env->SetObjectArrayElement(ret,0,env->NewStringUTF(std::get<0>(markers).c_str())); + env->SetObjectArrayElement(ret,1,env->NewStringUTF(std::to_string(std::get<1>(markers)).c_str())); + env->SetObjectArrayElement(ret,2,env->NewStringUTF(std::to_string(std::get<2>(markers)).c_str())); + return(ret); } void Java_com_aghajari_rlottie_AXrLottieNative_setLayerColor(JNIEnv *env, jclass clazz, jlong ptr, jstring layer, jint color) { @@ -378,12 +386,23 @@ void Java_com_aghajari_rlottie_AXrLottieNative_setLayerColor(JNIEnv *env, jclass } LottieInfo *info = (LottieInfo *) (intptr_t) ptr; char const *layerString = env->GetStringUTFChars(layer, 0); - info->animation->setValue(layerString, Color(((color) & 0xff) / 255.0f, ((color >> 8) & 0xff) / 255.0f, ((color >> 16) & 0xff) / 255.0f)); - if (layerString != 0) { + info->animation->setValue(layerString, rlottie::Color(((color >> 16) & 0xff) / 255.0f, ((color >> 8) & 0xff) / 255.0f, ((color) & 0xff) / 255.0f)); + if (layerString != 0) { env->ReleaseStringUTFChars(layer, layerString); } } +void Java_com_aghajari_rlottie_AXrLottieNative_setLayerStrokeColor(JNIEnv *env, jclass clazz, jlong ptr, jstring layer, jint color) { + if (ptr == NULL || layer == nullptr) { + return; + } + LottieInfo *info = (LottieInfo *) (intptr_t) ptr; + char const *layerString = env->GetStringUTFChars(layer, 0); + info->animation->setValue(layerString, rlottie::Color(((color >> 16) & 0xff) / 255.0f, ((color >> 8) & 0xff) / 255.0f, ((color) & 0xff) / 255.0f)); + if (layerString != 0) { + env->ReleaseStringUTFChars(layer, layerString); + } +} void Java_com_aghajari_rlottie_AXrLottieNative_setLayerFillOpacity(JNIEnv *env, jclass clazz, jlong ptr, jstring layer, jfloat value) { if (ptr == NULL || layer == nullptr) { @@ -481,6 +500,10 @@ void Java_com_aghajari_rlottie_AXrLottieNative_setLayerTrScale(JNIEnv *env, jcla } } +void Java_com_aghajari_rlottie_AXrLottieNative_configureModelCacheSize(JNIEnv *env, jclass clazz, jint cacheSize) { + rlottie::configureModelCacheSize((size_t )cacheSize); +} + jboolean Java_com_aghajari_rlottie_AXrLottieNative_lottie2gif(JNIEnv *env, jclass clazz, jlong ptr,jobject bitmap, jint w, jint h, jint stride, jint bgColor,jboolean transparent, jstring gifName,jint delay,jint bitDepth, jboolean dither,jint frameStart,jint frameEnd,jobject listener) { if (ptr == NULL) { return false; @@ -493,3 +516,4 @@ jboolean Java_com_aghajari_rlottie_AXrLottieNative_lottie2gif(JNIEnv *env, jclas } + diff --git a/AXrLottie/src/main/cpp/lottie.h b/AXrLottie/src/main/cpp/lottie.h index 1274c88..3cdcfc9 100644 --- a/AXrLottie/src/main/cpp/lottie.h +++ b/AXrLottie/src/main/cpp/lottie.h @@ -5,6 +5,11 @@ #ifndef AXRLOTTIE_APP_LOTTIE_H #define AXRLOTTIE_APP_LOTTIE_H +typedef struct LottieWrapper{ +public: + static void convertToCanvasFormat(rlottie::Surface &s); +}; + typedef struct LottieInfo{ ~LottieInfo() { if (decompressBuffer != nullptr) { diff --git a/AXrLottie/src/main/cpp/src/CMakeLists.txt b/AXrLottie/src/main/cpp/src/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/CMakeLists.txt b/AXrLottie/src/main/cpp/src/lottie/CMakeLists.txt index 89a2b68..09840b9 100644 --- a/AXrLottie/src/main/cpp/src/lottie/CMakeLists.txt +++ b/AXrLottie/src/main/cpp/src/lottie/CMakeLists.txt @@ -2,6 +2,7 @@ target_sources(rlottie PRIVATE "${CMAKE_CURRENT_LIST_DIR}/lottieitem.cpp" + "${CMAKE_CURRENT_LIST_DIR}/lottieitem_capi.cpp" "${CMAKE_CURRENT_LIST_DIR}/lottieloader.cpp" "${CMAKE_CURRENT_LIST_DIR}/lottiemodel.cpp" "${CMAKE_CURRENT_LIST_DIR}/lottieproxymodel.cpp" diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieanimation.cpp b/AXrLottie/src/main/cpp/src/lottie/lottieanimation.cpp index 429d6c7..0456618 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottieanimation.cpp +++ b/AXrLottie/src/main/cpp/src/lottie/lottieanimation.cpp @@ -1,29 +1,38 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "config.h" #include "lottieitem.h" -#include "lottieloader.h" #include "lottiemodel.h" #include "rlottie.h" #include using namespace rlottie; +using namespace rlottie::internal; + +RLOTTIE_API void rlottie::configureModelCacheSize(size_t cacheSize) +{ + internal::model::configureModelCacheSize(cacheSize); +} struct RenderTask { RenderTask() { receiver = sender.get_future(); } @@ -32,56 +41,61 @@ struct RenderTask { AnimationImpl * playerImpl{nullptr}; size_t frameNo{0}; Surface surface; + bool keepAspectRatio{true}; }; using SharedRenderTask = std::shared_ptr; class AnimationImpl { public: - void init(const std::shared_ptr &model); - bool update(size_t frameNo, const VSize &size); - VSize size() const { return mCompItem->size(); } + void init(std::shared_ptr composition); + bool update(size_t frameNo, const VSize &size, bool keepAspectRatio); + VSize size() const { return mModel->size(); } double duration() const { return mModel->duration(); } double frameRate() const { return mModel->frameRate(); } size_t totalFrame() const { return mModel->totalFrame(); } size_t frameAtPos(double pos) const { return mModel->frameAtPos(pos); } - Surface render(size_t frameNo, const Surface &surface); + Surface render(size_t frameNo, const Surface &surface, + bool keepAspectRatio); + std::future renderAsync(size_t frameNo, Surface &&surface, + bool keepAspectRatio); const LOTLayerNode * renderTree(size_t frameNo, const VSize &size); const LayerInfoList &layerInfoList() const { - return mModel->layerInfoList(); + if (mLayerList.empty()) { + mLayerList = mModel->layerInfoList(); + } + return mLayerList; } - void setValue(const std::string &keypath, LOTVariant &&value); - void removeFilter(const std::string &keypath, Property prop); - void resetCurrentFrame(); + + const MarkerList &markers() const { return mModel->markers(); } + void setValue(const std::string &keypath, LOTVariant &&value); + void removeFilter(const std::string &keypath, Property prop); private: - std::string mFilePath; - std::shared_ptr mModel; - std::unique_ptr mCompItem; - SharedRenderTask mTask; - std::atomic mRenderInProgress; + mutable LayerInfoList mLayerList; + model::Composition * mModel; + SharedRenderTask mTask; + std::atomic mRenderInProgress; + std::unique_ptr mRenderer{nullptr}; }; void AnimationImpl::setValue(const std::string &keypath, LOTVariant &&value) { if (keypath.empty()) return; - mCompItem->setValue(keypath, value); -} - -void AnimationImpl::resetCurrentFrame() { - mCompItem->resetCurrentFrame(); + mRenderer->setValue(keypath, value); } const LOTLayerNode *AnimationImpl::renderTree(size_t frameNo, const VSize &size) { - if (update(frameNo, size)) { - mCompItem->buildRenderTree(); + if (update(frameNo, size, true)) { + mRenderer->buildRenderTree(); } - return mCompItem->renderTree(); + return mRenderer->renderTree(); } -bool AnimationImpl::update(size_t frameNo, const VSize &size) +bool AnimationImpl::update(size_t frameNo, const VSize &size, + bool keepAspectRatio) { frameNo += mModel->startFrame(); @@ -89,11 +103,11 @@ bool AnimationImpl::update(size_t frameNo, const VSize &size) if (frameNo < mModel->startFrame()) frameNo = mModel->startFrame(); - mCompItem->resize(size); - return mCompItem->update(frameNo); + return mRenderer->update(int(frameNo), size, keepAspectRatio); } -Surface AnimationImpl::render(size_t frameNo, const Surface &surface) +Surface AnimationImpl::render(size_t frameNo, const Surface &surface, + bool keepAspectRatio) { bool renderInProgress = mRenderInProgress.load(); if (renderInProgress) { @@ -102,21 +116,139 @@ Surface AnimationImpl::render(size_t frameNo, const Surface &surface) } mRenderInProgress.store(true); - update(frameNo, - VSize(surface.drawRegionWidth(), surface.drawRegionHeight())); - mCompItem->render(surface); + update( + frameNo, + VSize(int(surface.drawRegionWidth()), int(surface.drawRegionHeight())), + keepAspectRatio); + mRenderer->render(surface); mRenderInProgress.store(false); return surface; } -void AnimationImpl::init(const std::shared_ptr &model) +void AnimationImpl::init(std::shared_ptr composition) { - mModel = model; - mCompItem = std::make_unique(mModel.get()); + mModel = composition.get(); + mRenderer = std::make_unique(composition); mRenderInProgress = false; } +#ifdef LOTTIE_THREAD_SUPPORT + +#include +#include "vtaskqueue.h" + +/* + * Implement a task stealing schduler to perform render task + * As each player draws into its own buffer we can delegate this + * task to a slave thread. The scheduler creates a threadpool depending + * on the number of cores available in the system and does a simple fair + * scheduling by assigning the task in a round-robin fashion. Each thread + * in the threadpool has its own queue. once it finishes all the task on its + * own queue it goes through rest of the queue and looks for task if it founds + * one it steals the task from it and executes. if it couldn't find one then it + * just waits for new task on its own queue. + */ +class RenderTaskScheduler { + const unsigned _count{std::thread::hardware_concurrency()}; + std::vector _threads; + std::vector> _q{_count}; + std::atomic _index{0}; + + void run(unsigned i) + { + while (true) { + bool success = false; + SharedRenderTask task; + for (unsigned n = 0; n != _count * 2; ++n) { + if (_q[(i + n) % _count].try_pop(task)) { + success = true; + break; + } + } + if (!success && !_q[i].pop(task)) break; + + auto result = task->playerImpl->render(task->frameNo, task->surface, + task->keepAspectRatio); + task->sender.set_value(result); + } + } + + RenderTaskScheduler() + { + for (unsigned n = 0; n != _count; ++n) { + _threads.emplace_back([&, n] { run(n); }); + } + } + +public: + static RenderTaskScheduler &instance() + { + static RenderTaskScheduler singleton; + return singleton; + } + + ~RenderTaskScheduler() + { + for (auto &e : _q) e.done(); + + for (auto &e : _threads) e.join(); + } + + std::future process(SharedRenderTask task) + { + auto receiver = std::move(task->receiver); + auto i = _index++; + + for (unsigned n = 0; n != _count; ++n) { + if (_q[(i + n) % _count].try_push(std::move(task))) return receiver; + } + + if (_count > 0) { + _q[i % _count].push(std::move(task)); + } + + return receiver; + } +}; + +#else +class RenderTaskScheduler { +public: + static RenderTaskScheduler &instance() + { + static RenderTaskScheduler singleton; + return singleton; + } + + std::future process(SharedRenderTask task) + { + auto result = task->playerImpl->render(task->frameNo, task->surface, + task->keepAspectRatio); + task->sender.set_value(result); + return std::move(task->receiver); + } +}; +#endif + +std::future AnimationImpl::renderAsync(size_t frameNo, + Surface &&surface, + bool keepAspectRatio) +{ + if (!mTask) { + mTask = std::make_shared(); + } else { + mTask->sender = std::promise(); + mTask->receiver = mTask->sender.get_future(); + } + mTask->playerImpl = this; + mTask->frameNo = frameNo; + mTask->surface = std::move(surface); + mTask->keepAspectRatio = keepAspectRatio; + + return RenderTaskScheduler::instance().process(mTask); +} + /** * \breif Brief abput the Api. * Description about the setFilePath Api @@ -124,46 +256,57 @@ void AnimationImpl::init(const std::shared_ptr &model) */ std::unique_ptr Animation::loadFromData( std::string jsonData, const std::string &key, - std::map *colorReplacement, - const std::string &resourcePath) + const std::string &resourcePath, bool cachePolicy) { if (jsonData.empty()) { vWarning << "jason data is empty"; return nullptr; } - LottieLoader loader; - if (loader.loadFromData(std::move(jsonData), key, - colorReplacement, - (resourcePath.empty() ? " " : resourcePath))) { + auto composition = model::loadFromData(std::move(jsonData), key, + resourcePath, cachePolicy); + if (composition) { auto animation = std::unique_ptr(new Animation); - animation->colorMap = colorReplacement; - animation->d->init(loader.model()); + animation->d->init(std::move(composition)); return animation; } - if (colorReplacement != nullptr) { - delete colorReplacement; + + return nullptr; +} + +std::unique_ptr Animation::loadFromData(std::string jsonData, + std::string resourcePath, + ColorFilter filter) +{ + if (jsonData.empty()) { + vWarning << "jason data is empty"; + return nullptr; + } + + auto composition = model::loadFromData( + std::move(jsonData), std::move(resourcePath), std::move(filter)); + if (composition) { + auto animation = std::unique_ptr(new Animation); + animation->d->init(std::move(composition)); + return animation; } return nullptr; } -std::unique_ptr Animation::loadFromFile(const std::string &path, std::map *colorReplacement) +std::unique_ptr Animation::loadFromFile(const std::string &path, + bool cachePolicy) { if (path.empty()) { vWarning << "File path is empty"; return nullptr; } - LottieLoader loader; - if (loader.load(path, colorReplacement)) { + auto composition = model::loadFromFile(path, cachePolicy); + if (composition) { auto animation = std::unique_ptr(new Animation); - animation->colorMap = colorReplacement; - animation->d->init(loader.model()); + animation->d->init(std::move(composition)); return animation; } - if (colorReplacement != nullptr) { - delete colorReplacement; - } return nullptr; } @@ -198,12 +341,19 @@ size_t Animation::frameAtPos(double pos) const LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width, size_t height) const { - return d->renderTree(frameNo, VSize(width, height)); + return d->renderTree(frameNo, VSize(int(width), int(height))); } -void Animation::renderSync(size_t frameNo, Surface &surface) +std::future Animation::render(size_t frameNo, Surface surface, + bool keepAspectRatio) { - d->render(frameNo, surface); + return d->renderAsync(frameNo, std::move(surface), keepAspectRatio); +} + +void Animation::renderSync(size_t frameNo, Surface surface, + bool keepAspectRatio) +{ + d->render(frameNo, surface, keepAspectRatio); } const LayerInfoList &Animation::layers() const @@ -211,6 +361,11 @@ const LayerInfoList &Animation::layers() const return d->layerInfoList(); } +const MarkerList &Animation::markers() const +{ + return d->markers(); +} + void Animation::setValue(Color_Type, Property prop, const std::string &keypath, Color value) { @@ -263,23 +418,9 @@ void Animation::setValue(Point_Type, Property prop, const std::string &keypath, d->setValue(keypath, LOTVariant(prop, value)); } +Animation::~Animation() = default; Animation::Animation() : d(std::make_unique()) {} -/* - * this is only to supress build fail - * because unique_ptr expects the destructor in the same translation unit. - */ -Animation::~Animation() { - if (colorMap != nullptr) { - delete colorMap; - colorMap = nullptr; - } -} - -void Animation::resetCurrentFrame() { - d->resetCurrentFrame(); -} - Surface::Surface(uint32_t *buffer, size_t width, size_t height, size_t bytesPerLine) : mBuffer(buffer), diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieitem.cpp b/AXrLottie/src/main/cpp/src/lottie/lottieitem.cpp index a70c3ea..7a746b8 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottieitem.cpp +++ b/AXrLottie/src/main/cpp/src/lottie/lottieitem.cpp @@ -1,29 +1,31 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "lottieitem.h" #include #include #include -#include #include "lottiekeypath.h" #include "vbitmap.h" -#include "vdasher.h" #include "vpainter.h" #include "vraster.h" @@ -50,7 +52,7 @@ static bool transformProp(rlottie::Property prop) static bool fillProp(rlottie::Property prop) { switch (prop) { - case rlottie::Property::Color: + case rlottie::Property::FillColor: case rlottie::Property::FillOpacity: return true; default: @@ -61,7 +63,7 @@ static bool fillProp(rlottie::Property prop) static bool strokeProp(rlottie::Property prop) { switch (prop) { - case rlottie::Property::Color: + case rlottie::Property::StrokeColor: case rlottie::Property::StrokeOpacity: case rlottie::Property::StrokeWidth: return true; @@ -70,55 +72,24 @@ static bool strokeProp(rlottie::Property prop) } } -LOTCompItem::LOTCompItem(LOTModel *model) - : mUpdateViewBox(false), mCurFrameNo(-1) -{ - mCompData = model->mRoot.get(); - mRootLayer = createLayerItem(mCompData->mRootLayer.get()); - mRootLayer->setComplexContent(false); - mViewSize = mCompData->size(); -} - -static bool isGoodParentLayer(LOTLayerItem *parent, LOTLayerItem *child) { - do { - if (parent == child) { - return false; - } - parent = parent->resolvedParentLayer(); - } while (parent); - return true; -} - -void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value) -{ - LOTKeyPath key(keypath); - mRootLayer->resolveKeyPath(key, 0, value); - mCurFrameNo = -1; -} - -void LOTCompItem::resetCurrentFrame() -{ - mCurFrameNo = -1; -} - -std::unique_ptr LOTCompItem::createLayerItem( - LOTLayerData *layerData) +static renderer::Layer *createLayerItem(model::Layer *layerData, + VArenaAlloc * allocator) { switch (layerData->mLayerType) { - case LayerType::Precomp: { - return std::make_unique(layerData); + case model::Layer::Type::Precomp: { + return allocator->make(layerData, allocator); } - case LayerType::Solid: { - return std::make_unique(layerData); + case model::Layer::Type::Solid: { + return allocator->make(layerData); } - case LayerType::Shape: { - return std::make_unique(layerData); + case model::Layer::Type::Shape: { + return allocator->make(layerData, allocator); } - case LayerType::Null: { - return std::make_unique(layerData); + case model::Layer::Type::Null: { + return allocator->make(layerData); } - case LayerType::Image: { - return std::make_unique(layerData); + case model::Layer::Type::Image: { + return allocator->make(layerData); } default: return nullptr; @@ -126,198 +97,128 @@ std::unique_ptr LOTCompItem::createLayerItem( } } -void LOTCompItem::resize(const VSize &size) +renderer::Composition::Composition(std::shared_ptr model) + : mCurFrameNo(-1) { - if (mViewSize == size) return; - mViewSize = size; - mUpdateViewBox = true; + mModel = std::move(model); + mRootLayer = createLayerItem(mModel->mRootLayer, &mAllocator); + mRootLayer->setComplexContent(false); + mViewSize = mModel->size(); } -VSize LOTCompItem::size() const +void renderer::Composition::setValue(const std::string &keypath, + LOTVariant & value) { - return mViewSize; + LOTKeyPath key(keypath); + mRootLayer->resolveKeyPath(key, 0, value); } -bool LOTCompItem::update(int frameNo) +bool renderer::Composition::update(int frameNo, const VSize &size, + bool keepAspectRatio) { // check if cached frame is same as requested frame. - if (!mUpdateViewBox && (mCurFrameNo == frameNo)) return false; + if ((mViewSize == size) && (mCurFrameNo == frameNo) && + (mKeepAspectRatio == keepAspectRatio)) + return false; + + mViewSize = size; + mCurFrameNo = frameNo; + mKeepAspectRatio = keepAspectRatio; /* * if viewbox dosen't scale exactly to the viewport * we scale the viewbox keeping AspectRatioPreserved and then align the * viewbox to the viewport using AlignCenter rule. */ - VSize viewPort = mViewSize; - VSize viewBox = mCompData->size(); - - float sx = float(viewPort.width()) / viewBox.width(); - float sy = float(viewPort.height()) / viewBox.height(); - float scale = fmin(sx, sy); - float tx = (viewPort.width() - viewBox.width() * scale) * 0.5; - float ty = (viewPort.height() - viewBox.height() * scale) * 0.5; - VMatrix m; - m.translate(tx, ty).scale(scale, scale); + VSize viewPort = mViewSize; + VSize viewBox = mModel->size(); + float sx = float(viewPort.width()) / viewBox.width(); + float sy = float(viewPort.height()) / viewBox.height(); + if (mKeepAspectRatio) { + float scale = std::min(sx, sy); + float tx = (viewPort.width() - viewBox.width() * scale) * 0.5f; + float ty = (viewPort.height() - viewBox.height() * scale) * 0.5f; + m.translate(tx, ty).scale(scale, scale); + } else { + m.scale(sx, sy); + } mRootLayer->update(frameNo, m, 1.0); - - mCurFrameNo = frameNo; - mUpdateViewBox = false; return true; } -void LOTCompItem::buildRenderTree() -{ - mRootLayer->buildLayerNode(); -} - -const LOTLayerNode *LOTCompItem::renderTree() const +bool renderer::Composition::render(const rlottie::Surface &surface) { - return mRootLayer->layerNode(); -} - -bool LOTCompItem::render(const rlottie::Surface &surface) -{ - VBitmap bitmap(reinterpret_cast(surface.buffer()), surface.width(), - surface.height(), surface.bytesPerLine(), - VBitmap::Format::ARGB32); + mSurface.reset(reinterpret_cast(surface.buffer()), + uint(surface.width()), uint(surface.height()), + uint(surface.bytesPerLine()), + VBitmap::Format::ARGB32_Premultiplied); /* schedule all preprocess task for this frame at once. */ - mDrawableList.clear(); - mRootLayer->renderList(mDrawableList); - VRect clip(0, 0, surface.drawRegionWidth(), surface.drawRegionHeight()); - for (auto &e : mDrawableList) { - e->preprocess(clip); - } + VRect clip(0, 0, int(surface.drawRegionWidth()), + int(surface.drawRegionHeight())); + mRootLayer->preprocess(clip); - VPainter painter(&bitmap); + VPainter painter(&mSurface); // set sub surface area for drawing. painter.setDrawRegion( - VRect(surface.drawRegionPosX(), surface.drawRegionPosY(), - surface.drawRegionWidth(), surface.drawRegionHeight())); - mRootLayer->render(&painter, {}, {}); - + VRect(int(surface.drawRegionPosX()), int(surface.drawRegionPosY()), + int(surface.drawRegionWidth()), int(surface.drawRegionHeight()))); + mRootLayer->render(&painter, {}, {}, mSurfaceCache); + painter.end(); return true; } -void LOTMaskItem::update(int frameNo, const VMatrix & parentMatrix, - float /*parentAlpha*/, const DirtyFlag &flag) +void renderer::Mask::update(int frameNo, const VMatrix &parentMatrix, + float /*parentAlpha*/, const DirtyFlag &flag) { + bool dirtyPath = false; + if (flag.testFlag(DirtyFlagBit::None) && mData->isStatic()) return; if (mData->mShape.isStatic()) { if (mLocalPath.empty()) { - mData->mShape.value(frameNo).toPath(mLocalPath); + dirtyPath = true; + mData->mShape.value(frameNo, mLocalPath); } } else { - mData->mShape.value(frameNo).toPath(mLocalPath); + dirtyPath = true; + mData->mShape.value(frameNo, mLocalPath); } /* mask item dosen't inherit opacity */ mCombinedAlpha = mData->opacity(frameNo); - mFinalPath.clone(mLocalPath); - mFinalPath.transform(parentMatrix); - - mRasterizer.rasterize(mFinalPath); - mRasterRequest = true; + if ( flag.testFlag(DirtyFlagBit::Matrix) || dirtyPath ) { + mFinalPath.clone(mLocalPath); + mFinalPath.transform(parentMatrix); + mRasterRequest = true; + } } -VRle LOTMaskItem::rle() -{ - if (mRasterRequest) { - mRasterRequest = false; - if (!vCompare(mCombinedAlpha, 1.0f)) - mRasterizer.rle() *= (mCombinedAlpha * 255); - if (mData->mInv) mRasterizer.rle().invert(); - } - return mRasterizer.rle(); -} - -void LOTLayerItem::buildLayerNode() -{ - if (!mLayerCNode) { - mLayerCNode = std::make_unique(); - mLayerCNode->mMaskList.ptr = nullptr; - mLayerCNode->mMaskList.size = 0; - mLayerCNode->mLayerList.ptr = nullptr; - mLayerCNode->mLayerList.size = 0; - mLayerCNode->mNodeList.ptr = nullptr; - mLayerCNode->mNodeList.size = 0; - mLayerCNode->mMatte = MatteNone; - mLayerCNode->mVisible = 0; - mLayerCNode->mAlpha = 255; - mLayerCNode->mClipPath.ptPtr = nullptr; - mLayerCNode->mClipPath.elmPtr = nullptr; - mLayerCNode->mClipPath.ptCount = 0; - mLayerCNode->mClipPath.elmCount = 0; - mLayerCNode->name = name().c_str(); - } - if (complexContent()) mLayerCNode->mAlpha = combinedAlpha() * 255; - mLayerCNode->mVisible = visible(); - // update matte - if (hasMatte()) { - switch (mLayerData->mMatteType) { - case MatteType::Alpha: - mLayerCNode->mMatte = MatteAlpha; - break; - case MatteType::AlphaInv: - mLayerCNode->mMatte = MatteAlphaInv; - break; - case MatteType::Luma: - mLayerCNode->mMatte = MatteLuma; - break; - case MatteType::LumaInv: - mLayerCNode->mMatte = MatteLumaInv; - break; - default: - mLayerCNode->mMatte = MatteNone; - break; - } - } - if (mLayerMask) { - mMasksCNode.clear(); - mMasksCNode.resize(mLayerMask->mMasks.size()); - size_t i = 0; - for (const auto &mask : mLayerMask->mMasks) { - LOTMask * cNode = &mMasksCNode[i++]; - const std::vector &elm = mask.mFinalPath.elements(); - const std::vector & pts = mask.mFinalPath.points(); - const float *ptPtr = reinterpret_cast(pts.data()); - const char * elmPtr = reinterpret_cast(elm.data()); - cNode->mPath.ptPtr = ptPtr; - cNode->mPath.ptCount = pts.size(); - cNode->mPath.elmPtr = elmPtr; - cNode->mPath.elmCount = elm.size(); - cNode->mAlpha = mask.mCombinedAlpha * 255; - switch (mask.maskMode()) { - case LOTMaskData::Mode::Add: - cNode->mMode = MaskAdd; - break; - case LOTMaskData::Mode::Substarct: - cNode->mMode = MaskSubstract; - break; - case LOTMaskData::Mode::Intersect: - cNode->mMode = MaskIntersect; - break; - case LOTMaskData::Mode::Difference: - cNode->mMode = MaskDifference; - break; - default: - cNode->mMode = MaskAdd; - break; - } - } - mLayerCNode->mMaskList.ptr = mMasksCNode.data(); - mLayerCNode->mMaskList.size = mMasksCNode.size(); +VRle renderer::Mask::rle() +{ + if (!vCompare(mCombinedAlpha, 1.0f)) { + VRle obj = mRasterizer.rle(); + obj *= uchar(mCombinedAlpha * 255); + return obj; + } else { + return mRasterizer.rle(); } } -void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) +void renderer::Mask::preprocess(const VRect &clip) { - mDrawableList.clear(); - renderList(mDrawableList); + if (mRasterRequest) + mRasterizer.rasterize(mFinalPath, FillRule::Winding, clip); +} + +void renderer::Layer::render(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, SurfaceCache &) +{ + auto renderlist = renderList(); + + if (renderlist.empty()) return; VRle mask; if (mLayerMask) { @@ -329,7 +230,7 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, mask = inheritMask; } - for (auto &i : mDrawableList) { + for (auto &i : renderlist) { painter->setBrush(i->mBrush); VRle rle = i->rle(); if (matteRle.empty()) { @@ -345,7 +246,7 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, if (!mask.empty()) rle = rle & mask; if (rle.empty()) continue; - if (matteType() == MatteType::AlphaInv) { + if (matteType() == model::MatteType::AlphaInv) { rle = rle - matteRle; painter->drawRle(VPoint(), rle); } else { @@ -356,20 +257,27 @@ void LOTLayerItem::render(VPainter *painter, const VRle &inheritMask, } } -LOTLayerMaskItem::LOTLayerMaskItem(LOTLayerData *layerData) +void renderer::LayerMask::preprocess(const VRect &clip) +{ + for (auto &i : mMasks) { + i.preprocess(clip); + } +} + +renderer::LayerMask::LayerMask(model::Layer *layerData) { if (!layerData->mExtra) return; mMasks.reserve(layerData->mExtra->mMasks.size()); for (auto &i : layerData->mExtra->mMasks) { - mMasks.emplace_back(i.get()); + mMasks.emplace_back(i); mStatic &= i->isStatic(); } } -void LOTLayerMaskItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::LayerMask::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { if (flag.testFlag(DirtyFlagBit::None) && isStatic()) return; @@ -379,29 +287,40 @@ void LOTLayerMaskItem::update(int frameNo, const VMatrix &parentMatrix, mDirty = true; } -VRle LOTLayerMaskItem::maskRle(const VRect &clipRect) +VRle renderer::LayerMask::maskRle(const VRect &clipRect) { if (!mDirty) return mRle; VRle rle; - for (auto &i : mMasks) { - switch (i.maskMode()) { - case LOTMaskData::Mode::Add: { - rle = rle + i.rle(); + for (auto &e : mMasks) { + const auto cur = [&]() { + if (e.inverted()) + return clipRect - e.rle(); + else + return e.rle(); + }(); + + switch (e.maskMode()) { + case model::Mask::Mode::Add: { + rle = rle + cur; break; } - case LOTMaskData::Mode::Substarct: { - if (rle.empty() && !clipRect.empty()) rle = VRle::toRle(clipRect); - rle = rle - i.rle(); + case model::Mask::Mode::Substarct: { + if (rle.empty() && !clipRect.empty()) + rle = clipRect - cur; + else + rle = rle - cur; break; } - case LOTMaskData::Mode::Intersect: { - if (rle.empty() && !clipRect.empty()) rle = VRle::toRle(clipRect); - rle = rle & i.rle(); + case model::Mask::Mode::Intersect: { + if (rle.empty() && !clipRect.empty()) + rle = clipRect & cur; + else + rle = rle & cur; break; } - case LOTMaskData::Mode::Difference: { - rle = rle ^ i.rle(); + case model::Mask::Mode::Difference: { + rle = rle ^ cur; break; } default: @@ -418,53 +337,49 @@ VRle LOTLayerMaskItem::maskRle(const VRect &clipRect) return mRle; } -LOTLayerItem::LOTLayerItem(LOTLayerData *layerData) : mLayerData(layerData) +renderer::Layer::Layer(model::Layer *layerData) : mLayerData(layerData) { if (mLayerData->mHasMask) - mLayerMask = std::make_unique(mLayerData); + mLayerMask = std::make_unique(mLayerData); } -bool LOTLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Layer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(name(), depth)) { return false; } if (!keyPath.skip(name())) { - if (keyPath.fullyResolvesTo(name(), depth) && transformProp(value.property())) { - mDirtyFlag = DirtyFlagBit::All; + if (keyPath.fullyResolvesTo(name(), depth) && + transformProp(value.property())) { + //@TODO handle propery update. } } - return true; } -bool LOTShapeLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::ShapeLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) { + if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { uint newDepth = keyPath.nextDepth(name(), depth); - if (mRoot->resolveKeyPath(keyPath, newDepth, value)) { - mDirtyFlag = DirtyFlagBit::All; - } + mRoot->resolveKeyPath(keyPath, newDepth, value); } return true; } return false; } -bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::CompLayer::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (LOTLayerItem::resolveKeyPath(keyPath, depth, value)) { + if (renderer::Layer::resolveKeyPath(keyPath, depth, value)) { if (keyPath.propagate(name(), depth)) { uint newDepth = keyPath.nextDepth(name(), depth); for (const auto &layer : mLayers) { - if (layer->resolveKeyPath(keyPath, newDepth, value)) { - mDirtyFlag = DirtyFlagBit::All; - } + layer->resolveKeyPath(keyPath, newDepth, value); } } return true; @@ -472,8 +387,8 @@ bool LOTCompLayerItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return false; } -void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix, - float parentAlpha) +void renderer::Layer::update(int frameNumber, const VMatrix &parentMatrix, + float parentAlpha) { mFrameNo = frameNumber; // 1. check if the layer is part of the current frame @@ -490,18 +405,20 @@ void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix, m *= parentMatrix; // 3. update the dirty flag based on the change - if (!mCombinedMatrix.fuzzyCompare(m)) { + if (mCombinedMatrix != m) { mDirtyFlag |= DirtyFlagBit::Matrix; + mCombinedMatrix = m; } + if (!vCompare(mCombinedAlpha, alpha)) { mDirtyFlag |= DirtyFlagBit::Alpha; + mCombinedAlpha = alpha; } - mCombinedMatrix = m; - mCombinedAlpha = alpha; // 4. update the mask if (mLayerMask) { - mLayerMask->update(frameNo(), m, alpha, mDirtyFlag); + mLayerMask->update(frameNo(), mCombinedMatrix, mCombinedAlpha, + mDirtyFlag); } // 5. if no parent property change and layer is static then nothing to do. @@ -516,33 +433,43 @@ void LOTLayerItem::update(int frameNumber, const VMatrix &parentMatrix, mDirtyFlag = DirtyFlagBit::None; } -VMatrix LOTLayerItem::matrix(int frameNo) const +VMatrix renderer::Layer::matrix(int frameNo) const { return mParentLayer ? (mLayerData->matrix(frameNo) * mParentLayer->matrix(frameNo)) : mLayerData->matrix(frameNo); } -bool LOTLayerItem::visible() const +bool renderer::Layer::visible() const { - if (frameNo() >= mLayerData->inFrame() && - frameNo() < mLayerData->outFrame()) - return true; - else - return false; + return (frameNo() >= mLayerData->inFrame() && + frameNo() < mLayerData->outFrame()); } -LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel) - : LOTLayerItem(layerModel) +void renderer::Layer::preprocess(const VRect &clip) { - // 1. create layer item - for (auto &i : mLayerData->mChildren) { - if (i->type() != LOTData::Type::Layer) { - continue; - } - LOTLayerData *layerModel = static_cast(i.get()); - auto layerItem = LOTCompItem::createLayerItem(layerModel); - if (layerItem) mLayers.push_back(std::move(layerItem)); + // layer dosen't contribute to the frame + if (skipRendering()) return; + + // preprocess layer masks + if (mLayerMask) mLayerMask->preprocess(clip); + + preprocessStage(clip); +} + +renderer::CompLayer::CompLayer(model::Layer *layerModel, VArenaAlloc *allocator) + : renderer::Layer(layerModel) +{ + if (!mLayerData->mChildren.empty()) + mLayers.reserve(mLayerData->mChildren.size()); + + // 1. keep the layer in back-to-front order. + // as lottie model keeps the data in front-toback-order. + for (auto it = mLayerData->mChildren.crbegin(); + it != mLayerData->mChildren.rend(); ++it) { + auto model = static_cast(*it); + auto item = createLayerItem(model, allocator); + if (item) mLayers.push_back(item); } // 2. update parent layer @@ -552,77 +479,46 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel) auto search = std::find_if(mLayers.begin(), mLayers.end(), [id](const auto &val) { return val->id() == id; }); - if (search != mLayers.end() && - isGoodParentLayer((*search).get(), layer.get())) { - layer->setParentLayer((*search).get()); - } + if (search != mLayers.end()) layer->setParentLayer(*search); } } - // 3. keep the layer in back-to-front order. - // as lottie model keeps the data in front-toback-order. - std::reverse(mLayers.begin(), mLayers.end()); - // 4. check if its a nested composition if (!layerModel->layerSize().empty()) { - mClipper = std::make_unique(layerModel->layerSize()); + mClipper = std::make_unique(layerModel->layerSize()); } if (mLayers.size() > 1) setComplexContent(true); } -void LOTCompLayerItem::buildLayerNode() -{ - LOTLayerItem::buildLayerNode(); - if (mClipper) { - const std::vector &elm = mClipper->mPath.elements(); - const std::vector & pts = mClipper->mPath.points(); - const float *ptPtr = reinterpret_cast(pts.data()); - const char * elmPtr = reinterpret_cast(elm.data()); - layerNode()->mClipPath.ptPtr = ptPtr; - layerNode()->mClipPath.elmPtr = elmPtr; - layerNode()->mClipPath.ptCount = 2 * pts.size(); - layerNode()->mClipPath.elmCount = elm.size(); - } - if (mLayers.size() != mLayersCNode.size()) { - for (const auto &layer : mLayers) { - layer->buildLayerNode(); - mLayersCNode.push_back(layer->layerNode()); - } - layerNode()->mLayerList.ptr = mLayersCNode.data(); - layerNode()->mLayerList.size = mLayersCNode.size(); - } else { - for (const auto &layer : mLayers) { - layer->buildLayerNode(); - } - } -} - -void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) +void renderer::CompLayer::render(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, SurfaceCache &cache) { if (vIsZero(combinedAlpha())) return; if (vCompare(combinedAlpha(), 1.0)) { - renderHelper(painter, inheritMask, matteRle); + renderHelper(painter, inheritMask, matteRle, cache); } else { if (complexContent()) { VSize size = painter->clipBoundingRect().size(); VPainter srcPainter; - VBitmap srcBitmap(size.width(), size.height(), - VBitmap::Format::ARGB32); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); srcPainter.begin(&srcBitmap); - renderHelper(&srcPainter, inheritMask, matteRle); + renderHelper(&srcPainter, inheritMask, matteRle, cache); srcPainter.end(); - painter->drawBitmap(VPoint(), srcBitmap, combinedAlpha() * 255); + painter->drawBitmap(VPoint(), srcBitmap, + uchar(combinedAlpha() * 255.0f)); + cache.release_surface(srcBitmap); } else { - renderHelper(painter, inheritMask, matteRle); + renderHelper(painter, inheritMask, matteRle, cache); } } } -void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, - const VRle &matteRle) +void renderer::CompLayer::renderHelper(VPainter * painter, + const VRle & inheritMask, + const VRle & matteRle, + SurfaceCache &cache) { VRle mask; if (mLayerMask) { @@ -635,25 +531,22 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, } if (mClipper) { - if (mask.empty()) { - mask = mClipper->rle(); - } else { - mask = mClipper->rle() & mask; - } + mask = mClipper->rle(mask); + if (mask.empty()) return; } - LOTLayerItem *matte = nullptr; + renderer::Layer *matte = nullptr; for (const auto &layer : mLayers) { if (layer->hasMatte()) { - matte = layer.get(); + matte = layer; } else { if (layer->visible()) { if (matte) { if (matte->visible()) - renderMatteLayer(painter, mask, matteRle, matte, - layer.get()); + renderMatteLayer(painter, mask, matteRle, matte, layer, + cache); } else { - layer->render(painter, mask, matteRle); + layer->render(painter, mask, matteRle, cache); } } matte = nullptr; @@ -661,39 +554,37 @@ void LOTCompLayerItem::renderHelper(VPainter *painter, const VRle &inheritMask, } } -void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, - const VRle & matteRle, - LOTLayerItem *layer, LOTLayerItem *src) +void renderer::CompLayer::renderMatteLayer(VPainter *painter, const VRle &mask, + const VRle & matteRle, + renderer::Layer *layer, + renderer::Layer *src, + SurfaceCache & cache) { VSize size = painter->clipBoundingRect().size(); // Decide if we can use fast matte. // 1. draw src layer to matte buffer VPainter srcPainter; - src->bitmap().reset(size.width(), size.height(), - VBitmap::Format::ARGB32); - srcPainter.begin(&src->bitmap()); - src->render(&srcPainter, mask, matteRle); + VBitmap srcBitmap = cache.make_surface(size.width(), size.height()); + srcPainter.begin(&srcBitmap); + src->render(&srcPainter, mask, matteRle, cache); srcPainter.end(); // 2. draw layer to layer buffer VPainter layerPainter; - layer->bitmap().reset(size.width(), size.height(), - VBitmap::Format::ARGB32); - layerPainter.begin(&layer->bitmap()); - layer->render(&layerPainter, mask, matteRle); + VBitmap layerBitmap = cache.make_surface(size.width(), size.height()); + layerPainter.begin(&layerBitmap); + layer->render(&layerPainter, mask, matteRle, cache); // 2.1update composition mode switch (layer->matteType()) { - case MatteType::Alpha: - case MatteType::Luma: { - layerPainter.setCompositionMode( - VPainter::CompositionMode::CompModeDestIn); + case model::MatteType::Alpha: + case model::MatteType::Luma: { + layerPainter.setBlendMode(BlendMode::DestIn); break; } - case MatteType::AlphaInv: - case MatteType::LumaInv: { - layerPainter.setCompositionMode( - VPainter::CompositionMode::CompModeDestOut); + case model::MatteType::AlphaInv: + case model::MatteType::LumaInv: { + layerPainter.setBlendMode(BlendMode::DestOut); break; } default: @@ -701,32 +592,46 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, } // 2.2 update srcBuffer if the matte is luma type - if (layer->matteType() == MatteType::Luma || - layer->matteType() == MatteType::LumaInv) { - src->bitmap().updateLuma(); + if (layer->matteType() == model::MatteType::Luma || + layer->matteType() == model::MatteType::LumaInv) { + srcBitmap.updateLuma(); } // 2.3 draw src buffer as mask - layerPainter.drawBitmap(VPoint(), src->bitmap()); + layerPainter.drawBitmap(VPoint(), srcBitmap); layerPainter.end(); // 3. draw the result buffer into painter - painter->drawBitmap(VPoint(), layer->bitmap()); + painter->drawBitmap(VPoint(), layerBitmap); + + cache.release_surface(srcBitmap); + cache.release_surface(layerBitmap); } -void LOTClipperItem::update(const VMatrix &matrix) +void renderer::Clipper::update(const VMatrix &matrix) { mPath.reset(); mPath.addRect(VRectF(0, 0, mSize.width(), mSize.height())); mPath.transform(matrix); - mRasterizer.rasterize(mPath); + mRasterRequest = true; } -VRle LOTClipperItem::rle() +void renderer::Clipper::preprocess(const VRect &clip) { - return mRasterizer.rle(); + if (mRasterRequest) mRasterizer.rasterize(mPath, FillRule::Winding, clip); + + mRasterRequest = false; +} + +VRle renderer::Clipper::rle(const VRle &mask) +{ + if (mask.empty()) return mRasterizer.rle(); + + mMaskedRle.clone(mask); + mMaskedRle &= mRasterizer.rle(); + return mMaskedRle; } -void LOTCompLayerItem::updateContent() +void renderer::CompLayer::updateContent() { if (mClipper && flag().testFlag(DirtyFlagBit::Matrix)) { mClipper->update(combinedMatrix()); @@ -739,23 +644,24 @@ void LOTCompLayerItem::updateContent() } } -void LOTCompLayerItem::renderList(std::vector &list) +void renderer::CompLayer::preprocessStage(const VRect &clip) { - if (!visible() || vIsZero(combinedAlpha())) return; + // if layer has clipper + if (mClipper) mClipper->preprocess(clip); - LOTLayerItem *matte = nullptr; + renderer::Layer *matte = nullptr; for (const auto &layer : mLayers) { if (layer->hasMatte()) { - matte = layer.get(); + matte = layer; } else { if (layer->visible()) { if (matte) { if (matte->visible()) { - layer->renderList(list); - matte->renderList(list); + layer->preprocess(clip); + matte->preprocess(clip); } } else { - layer->renderList(list); + layer->preprocess(clip); } } matte = nullptr; @@ -763,195 +669,138 @@ void LOTCompLayerItem::renderList(std::vector &list) } } -LOTSolidLayerItem::LOTSolidLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::SolidLayer::SolidLayer(model::Layer *layerData) + : renderer::Layer(layerData) { + mDrawableList = &mRenderNode; } -void LOTSolidLayerItem::updateContent() +void renderer::SolidLayer::updateContent() { if (flag() & DirtyFlagBit::Matrix) { - VPath path; - path.addRect( - VRectF(0, 0, - mLayerData->layerSize().width(), - mLayerData->layerSize().height())); - path.transform(combinedMatrix()); + mPath.reset(); + mPath.addRect(VRectF(0, 0, mLayerData->layerSize().width(), + mLayerData->layerSize().height())); + mPath.transform(combinedMatrix()); mRenderNode.mFlag |= VDrawable::DirtyState::Path; - mRenderNode.mPath = path; + mRenderNode.mPath = mPath; } if (flag() & DirtyFlagBit::Alpha) { - LottieColor color = mLayerData->solidColor(); - VBrush brush(color.toColor(combinedAlpha())); + model::Color color = mLayerData->solidColor(); + VBrush brush(color.toColor(combinedAlpha())); mRenderNode.setBrush(brush); mRenderNode.mFlag |= VDrawable::DirtyState::Brush; } } -void LOTSolidLayerItem::buildLayerNode() +void renderer::SolidLayer::preprocessStage(const VRect &clip) { - LOTLayerItem::buildLayerNode(); - - mDrawableList.clear(); - renderList(mDrawableList); - - mCNodeList.clear(); - for (auto &i : mDrawableList) { - LOTDrawable *lotDrawable = static_cast(i); - lotDrawable->sync(); - mCNodeList.push_back(lotDrawable->mCNode.get()); - } - layerNode()->mNodeList.ptr = mCNodeList.data(); - layerNode()->mNodeList.size = mCNodeList.size(); + mRenderNode.preprocess(clip); } -void LOTSolidLayerItem::renderList(std::vector &list) +renderer::DrawableList renderer::SolidLayer::renderList() { - if (!visible() || vIsZero(combinedAlpha())) return; + if (skipRendering()) return {}; - list.push_back(&mRenderNode); + return {&mDrawableList, 1}; } -LOTImageLayerItem::LOTImageLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::ImageLayer::ImageLayer(model::Layer *layerData) + : renderer::Layer(layerData) { + mDrawableList = &mRenderNode; + if (!mLayerData->asset()) return; - VBrush brush(mLayerData->asset()->bitmap()); + mTexture.mBitmap = mLayerData->asset()->bitmap(); + VBrush brush(&mTexture); mRenderNode.setBrush(brush); } -void LOTImageLayerItem::updateContent() +void renderer::ImageLayer::updateContent() { if (!mLayerData->asset()) return; if (flag() & DirtyFlagBit::Matrix) { - VPath path; - path.addRect(VRectF(0, 0, mLayerData->asset()->mWidth, + mPath.reset(); + mPath.addRect(VRectF(0, 0, mLayerData->asset()->mWidth, mLayerData->asset()->mHeight)); - path.transform(combinedMatrix()); + mPath.transform(combinedMatrix()); mRenderNode.mFlag |= VDrawable::DirtyState::Path; - mRenderNode.mPath = path; - mRenderNode.mBrush.setMatrix(combinedMatrix()); + mRenderNode.mPath = mPath; + mTexture.mMatrix = combinedMatrix(); } if (flag() & DirtyFlagBit::Alpha) { - //@TODO handle alpha with the image. + mTexture.mAlpha = int(combinedAlpha() * 255); } } -void LOTImageLayerItem::renderList(std::vector &list) +void renderer::ImageLayer::preprocessStage(const VRect &clip) { - if (!visible() || vIsZero(combinedAlpha())) return; - - list.push_back(&mRenderNode); + mRenderNode.preprocess(clip); } -void LOTImageLayerItem::buildLayerNode() +renderer::DrawableList renderer::ImageLayer::renderList() { - LOTLayerItem::buildLayerNode(); - - mDrawableList.clear(); - renderList(mDrawableList); - - mCNodeList.clear(); - for (auto &i : mDrawableList) { - LOTDrawable *lotDrawable = static_cast(i); - lotDrawable->sync(); + if (skipRendering()) return {}; - lotDrawable->mCNode->mImageInfo.data = - lotDrawable->mBrush.mTexture.data(); - lotDrawable->mCNode->mImageInfo.width = - lotDrawable->mBrush.mTexture.width(); - lotDrawable->mCNode->mImageInfo.height = - lotDrawable->mBrush.mTexture.height(); - - lotDrawable->mCNode->mImageInfo.mMatrix.m11 = combinedMatrix().m_11(); - lotDrawable->mCNode->mImageInfo.mMatrix.m12 = combinedMatrix().m_12(); - lotDrawable->mCNode->mImageInfo.mMatrix.m13 = combinedMatrix().m_13(); - - lotDrawable->mCNode->mImageInfo.mMatrix.m21 = combinedMatrix().m_21(); - lotDrawable->mCNode->mImageInfo.mMatrix.m22 = combinedMatrix().m_22(); - lotDrawable->mCNode->mImageInfo.mMatrix.m23 = combinedMatrix().m_23(); - - lotDrawable->mCNode->mImageInfo.mMatrix.m31 = combinedMatrix().m_tx(); - lotDrawable->mCNode->mImageInfo.mMatrix.m32 = combinedMatrix().m_ty(); - lotDrawable->mCNode->mImageInfo.mMatrix.m33 = combinedMatrix().m_33(); - - mCNodeList.push_back(lotDrawable->mCNode.get()); - } - layerNode()->mNodeList.ptr = mCNodeList.data(); - layerNode()->mNodeList.size = mCNodeList.size(); + return {&mDrawableList, 1}; } -LOTNullLayerItem::LOTNullLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData) +renderer::NullLayer::NullLayer(model::Layer *layerData) + : renderer::Layer(layerData) { } -void LOTNullLayerItem::updateContent() {} +void renderer::NullLayer::updateContent() {} -LOTShapeLayerItem::LOTShapeLayerItem(LOTLayerData *layerData) - : LOTLayerItem(layerData), - mRoot(std::make_unique(nullptr)) -{ - mRoot->addChildren(layerData); - - std::vector list; - mRoot->processPaintItems(list); - - if (layerData->hasPathOperator()) { - list.clear(); - mRoot->processTrimItems(list); - } -} - -std::unique_ptr LOTShapeLayerItem::createContentItem( - LOTData *contentData) +static renderer::Object *createContentItem(model::Object *contentData, + VArenaAlloc * allocator) { switch (contentData->type()) { - case LOTData::Type::ShapeGroup: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Group: { + return allocator->make( + static_cast(contentData), allocator); } - case LOTData::Type::Rect: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Rect: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Ellipse: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Ellipse: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Shape: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Path: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Polystar: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Polystar: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Fill: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Fill: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::GFill: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::GFill: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Stroke: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Stroke: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::GStroke: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::GStroke: { + return allocator->make( + static_cast(contentData)); } - case LOTData::Type::Repeater: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Repeater: { + return allocator->make( + static_cast(contentData), allocator); } - case LOTData::Type::Trim: { - return std::make_unique( - static_cast(contentData)); + case model::Object::Type::Trim: { + return allocator->make( + static_cast(contentData)); } default: return nullptr; @@ -959,7 +808,23 @@ std::unique_ptr LOTShapeLayerItem::createContentItem( } } -void LOTShapeLayerItem::updateContent() +renderer::ShapeLayer::ShapeLayer(model::Layer *layerData, + VArenaAlloc * allocator) + : renderer::Layer(layerData), + mRoot(allocator->make(nullptr, allocator)) +{ + mRoot->addChildren(layerData, allocator); + + std::vector list; + mRoot->processPaintItems(list); + + if (layerData->hasPathOperator()) { + list.clear(); + mRoot->processTrimItems(list); + } +} + +void renderer::ShapeLayer::updateContent() { mRoot->update(frameNo(), combinedMatrix(), combinedAlpha(), flag()); @@ -968,41 +833,39 @@ void LOTShapeLayerItem::updateContent() } } -void LOTShapeLayerItem::buildLayerNode() +void renderer::ShapeLayer::preprocessStage(const VRect &clip) { - LOTLayerItem::buildLayerNode(); - mDrawableList.clear(); - renderList(mDrawableList); + mRoot->renderList(mDrawableList); - mCNodeList.clear(); - for (auto &i : mDrawableList) { - LOTDrawable *lotDrawable = static_cast(i); - lotDrawable->sync(); - mCNodeList.push_back(lotDrawable->mCNode.get()); - } - layerNode()->mNodeList.ptr = mCNodeList.data(); - layerNode()->mNodeList.size = mCNodeList.size(); + for (auto &drawable : mDrawableList) drawable->preprocess(clip); } -void LOTShapeLayerItem::renderList(std::vector &list) +renderer::DrawableList renderer::ShapeLayer::renderList() { - if (!visible() || vIsZero(combinedAlpha())) return; - mRoot->renderList(list); + if (skipRendering()) return {}; + + mDrawableList.clear(); + mRoot->renderList(mDrawableList); + + if (mDrawableList.empty()) return {}; + + return {mDrawableList.data(), mDrawableList.size()}; } -bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Group::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { - if (!keyPath.matches(name(), depth)) { - return false; - } - if (!keyPath.skip(name())) { - if (keyPath.fullyResolvesTo(name(), depth) && - transformProp(value.property())) { + if (!keyPath.matches(mModel.name(), depth)) { + return false; + } - //@TODO handle property update + if (!keyPath.skip(mModel.name())) { + if (keyPath.fullyResolvesTo(mModel.name(), depth) && + transformProp(value.property())) { + mModel.filter()->addValue(value); + } } } @@ -1015,24 +878,23 @@ bool LOTContentGroupItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, return true; } -bool LOTFillItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Fill::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { return false; } if (keyPath.fullyResolvesTo(mModel.name(), depth) && - (fillProp(value.property()))) { - mModel.filter().addValue(value); + fillProp(value.property())) { + mModel.filter()->addValue(value); return true; } - return false; } -bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, - LOTVariant &value) +bool renderer::Stroke::resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) { if (!keyPath.matches(mModel.name(), depth)) { return false; @@ -1040,73 +902,77 @@ bool LOTStrokeItem::resolveKeyPath(LOTKeyPath &keyPath, uint depth, if (keyPath.fullyResolvesTo(mModel.name(), depth) && strokeProp(value.property())) { - mModel.filter().addValue(value); + mModel.filter()->addValue(value); return true; } return false; } -LOTContentGroupItem::LOTContentGroupItem(LOTGroupData *data) - : LOTContentItem(ContentType::Group), mData(data) +renderer::Group::Group(model::Group *data, VArenaAlloc *allocator) + : mModel(data) { - addChildren(mData); + addChildren(data, allocator); } -void LOTContentGroupItem::addChildren(LOTGroupData *data) +void renderer::Group::addChildren(model::Group *data, VArenaAlloc *allocator) { if (!data) return; - for (auto &i : data->mChildren) { - auto content = LOTShapeLayerItem::createContentItem(i.get()); + if (!data->mChildren.empty()) mContents.reserve(data->mChildren.size()); + + // keep the content in back-to-front order. + // as lottie model keeps it in front-to-back order. + for (auto it = data->mChildren.crbegin(); it != data->mChildren.rend(); + ++it) { + auto content = createContentItem(*it, allocator); if (content) { - content->setParent(this); - mContents.push_back(std::move(content)); + mContents.push_back(content); } } - - // keep the content in back-to-front order. - std::reverse(mContents.begin(), mContents.end()); } -void LOTContentGroupItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::Group::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { - VMatrix m = parentMatrix; - float alpha = parentAlpha; DirtyFlag newFlag = flag; + float alpha; - if (mData && mData->mTransform) { - // update the matrix and the flag - if ((flag & DirtyFlagBit::Matrix) || !mData->mTransform->isStatic()) { + if (mModel.hasModel() && mModel.transform()) { + VMatrix m = mModel.matrix(frameNo); + + m *= parentMatrix; + if (!(flag & DirtyFlagBit::Matrix) && !mModel.transform()->isStatic() && + (m != mMatrix)) { newFlag |= DirtyFlagBit::Matrix; } - m = mData->mTransform->matrix(frameNo); - m *= parentMatrix; - alpha *= mData->mTransform->opacity(frameNo); + mMatrix = m; + + alpha = parentAlpha * mModel.transform()->opacity(frameNo); if (!vCompare(alpha, parentAlpha)) { newFlag |= DirtyFlagBit::Alpha; } + } else { + mMatrix = parentMatrix; + alpha = parentAlpha; } - mMatrix = m; - for (const auto &content : mContents) { - content->update(frameNo, m, alpha, newFlag); + content->update(frameNo, matrix(), alpha, newFlag); } } -void LOTContentGroupItem::applyTrim() +void renderer::Group::applyTrim() { for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { - auto content = (*i).get(); + auto content = (*i); switch (content->type()) { - case ContentType::Trim: { - static_cast(content)->update(); + case renderer::Object::Type::Trim: { + static_cast(content)->update(); break; } - case ContentType::Group: { - static_cast(content)->applyTrim(); + case renderer::Object::Type::Group: { + static_cast(content)->applyTrim(); break; } default: @@ -1115,32 +981,32 @@ void LOTContentGroupItem::applyTrim() } } -void LOTContentGroupItem::renderList(std::vector &list) +void renderer::Group::renderList(std::vector &list) { for (const auto &content : mContents) { content->renderList(list); } } -void LOTContentGroupItem::processPaintItems( - std::vector &list) +void renderer::Group::processPaintItems(std::vector &list) { - int curOpCount = list.size(); + size_t curOpCount = list.size(); for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { - auto content = (*i).get(); + auto content = (*i); switch (content->type()) { - case ContentType::Path: { - list.push_back(static_cast(content)); + case renderer::Object::Type::Shape: { + auto pathItem = static_cast(content); + pathItem->setParent(this); + list.push_back(pathItem); break; } - case ContentType::Paint: { - static_cast(content)->addPathItems(list, - curOpCount); + case renderer::Object::Type::Paint: { + static_cast(content)->addPathItems(list, + curOpCount); break; } - case ContentType::Group: { - static_cast(content)->processPaintItems( - list); + case renderer::Object::Type::Group: { + static_cast(content)->processPaintItems(list); break; } default: @@ -1149,23 +1015,24 @@ void LOTContentGroupItem::processPaintItems( } } -void LOTContentGroupItem::processTrimItems(std::vector &list) +void renderer::Group::processTrimItems(std::vector &list) { - int curOpCount = list.size(); + size_t curOpCount = list.size(); for (auto i = mContents.rbegin(); i != mContents.rend(); ++i) { - auto content = (*i).get(); + auto content = (*i); switch (content->type()) { - case ContentType::Path: { - list.push_back(static_cast(content)); + case renderer::Object::Type::Shape: { + list.push_back(static_cast(content)); break; } - case ContentType::Trim: { - static_cast(content)->addPathItems(list, curOpCount); + case renderer::Object::Type::Trim: { + static_cast(content)->addPathItems(list, + curOpCount); break; } - case ContentType::Group: { - static_cast(content)->processTrimItems(list); + case renderer::Object::Type::Group: { + static_cast(content)->processTrimItems(list); break; } default: @@ -1175,21 +1042,26 @@ void LOTContentGroupItem::processTrimItems(std::vector &list) } /* - * LOTPathDataItem uses 3 path objects for path object reuse. + * renderer::Shape uses 2 path objects for path object reuse. * mLocalPath - keeps track of the local path of the item before * applying path operation and transformation. * mTemp - keeps a referece to the mLocalPath and can be updated by the * path operation objects(trim, merge path), - * mFinalPath - it takes a deep copy of the intermediate path(mTemp) each time - * when the path is dirty(so if path changes every frame we don't realloc just - * copy to the final path). NOTE: As path objects are COW objects we have to be + * We update the DirtyPath flag if the path needs to be updated again + * beacuse of local path or matrix or some path operation has changed which + * affects the final path. + * The PaintObject queries the dirty flag to check if it needs to compute the + * final path again and calls finalPath() api to do the same. + * finalPath() api passes a result Object so that we keep only one copy of + * the path object in the paintItem (for memory efficiency). + * NOTE: As path objects are COW objects we have to be * carefull about the refcount so that we don't generate deep copy while * modifying the path objects. */ -void LOTPathDataItem::update(int frameNo, const VMatrix &, float, +void renderer::Shape::update(int frameNo, const VMatrix &, float, const DirtyFlag &flag) { - mPathChanged = false; + mDirtyPath = false; // 1. update the local path if needed if (hasChanged(frameNo)) { @@ -1198,41 +1070,34 @@ void LOTPathDataItem::update(int frameNo, const VMatrix &, float, mTemp = VPath(); updatePath(mLocalPath, frameNo); - mPathChanged = true; - mNeedUpdate = true; + mDirtyPath = true; } // 2. keep a reference path in temp in case there is some // path operation like trim which will update the path. // we don't want to update the local path. mTemp = mLocalPath; - // 3. compute the final path with parentMatrix - if ((flag & DirtyFlagBit::Matrix) || mPathChanged) { - mPathChanged = true; + // 3. mark the path dirty if matrix has changed. + if (flag & DirtyFlagBit::Matrix) { + mDirtyPath = true; } } -const VPath &LOTPathDataItem::finalPath() +void renderer::Shape::finalPath(VPath &result) { - if (mPathChanged || mNeedUpdate) { - mFinalPath.clone(mTemp); - mFinalPath.transform( - static_cast(parent())->matrix()); - mNeedUpdate = false; - } - - return mFinalPath; + result.addPath(mTemp, static_cast(parent())->matrix()); } -LOTRectItem::LOTRectItem(LOTRectData *data) - : LOTPathDataItem(data->isStatic()), mData(data) + +renderer::Rect::Rect(model::Rect *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTRectItem::updatePath(VPath &path, int frameNo) +void renderer::Rect::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); VPointF size = mData->mSize.value(frameNo); - float roundness = mData->mRound.value(frameNo); + float roundness = mData->roundness(frameNo); VRectF r(pos.x() - size.x() / 2, pos.y() - size.y() / 2, size.x(), size.y()); @@ -1240,12 +1105,12 @@ void LOTRectItem::updatePath(VPath &path, int frameNo) path.addRoundRect(r, roundness, mData->direction()); } -LOTEllipseItem::LOTEllipseItem(LOTEllipseData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Ellipse::Ellipse(model::Ellipse *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTEllipseItem::updatePath(VPath &path, int frameNo) +void renderer::Ellipse::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); VPointF size = mData->mSize.value(frameNo); @@ -1256,22 +1121,22 @@ void LOTEllipseItem::updatePath(VPath &path, int frameNo) path.addOval(r, mData->direction()); } -LOTShapeItem::LOTShapeItem(LOTShapeData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Path::Path(model::Path *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTShapeItem::updatePath(VPath &path, int frameNo) +void renderer::Path::updatePath(VPath &path, int frameNo) { - mData->mShape.value(frameNo).toPath(path); + mData->mShape.value(frameNo, path); } -LOTPolystarItem::LOTPolystarItem(LOTPolystarData *data) - : LOTPathDataItem(data->isStatic()), mData(data) +renderer::Polystar::Polystar(model::Polystar *data) + : renderer::Shape(data->isStatic()), mData(data) { } -void LOTPolystarItem::updatePath(VPath &path, int frameNo) +void renderer::Polystar::updatePath(VPath &path, int frameNo) { VPointF pos = mData->mPos.value(frameNo); float points = mData->mPointCount.value(frameNo); @@ -1284,7 +1149,7 @@ void LOTPolystarItem::updatePath(VPath &path, int frameNo) path.reset(); VMatrix m; - if (mData->mType == LOTPolystarData::PolyType::Star) { + if (mData->mPolyType == model::Polystar::PolyType::Star) { path.addPolystar(points, innerRadius, outerRadius, innerRoundness, outerRoundness, 0.0, 0.0, 0.0, mData->direction()); } else { @@ -1301,23 +1166,16 @@ void LOTPolystarItem::updatePath(VPath &path, int frameNo) * PaintData Node handling * */ -LOTPaintDataItem::LOTPaintDataItem(bool staticContent) - : LOTContentItem(ContentType::Paint), mStaticContent(staticContent) -{ -} +renderer::Paint::Paint(bool staticContent) : mStaticContent(staticContent) {} -void LOTPaintDataItem::update(int frameNo, const VMatrix & /*parentMatrix*/, - float parentAlpha, const DirtyFlag &flag) +void renderer::Paint::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag & /*flag*/) { mRenderNodeUpdate = true; - mParentAlpha = parentAlpha; - mFlag = flag; - mFrameNo = frameNo; - - updateContent(frameNo); + mContentToRender = updateContent(frameNo, parentMatrix, parentAlpha); } -void LOTPaintDataItem::updateRenderNode() +void renderer::Paint::updateRenderNode() { bool dirty = false; for (auto &i : mPathItems) { @@ -1329,11 +1187,9 @@ void LOTPaintDataItem::updateRenderNode() if (dirty) { mPath.reset(); - - for (auto &i : mPathItems) { - mPath.addPath(i->finalPath()); + for (const auto &i : mPathItems) { + i->finalPath(mPath); } - mDrawable.setPath(mPath); } else { if (mDrawable.mFlag & VDrawable::DirtyState::Path) @@ -1341,160 +1197,151 @@ void LOTPaintDataItem::updateRenderNode() } } -void LOTPaintDataItem::renderList(std::vector &list) +void renderer::Paint::renderList(std::vector &list) { if (mRenderNodeUpdate) { updateRenderNode(); - LOTPaintDataItem::updateRenderNode(); mRenderNodeUpdate = false; } - list.push_back(&mDrawable); + + // Q: Why we even update the final path if we don't have content + // to render ? + // Ans: We update the render nodes because we will loose the + // dirty path information at end of this frame. + // so if we return early without updating the final path. + // in the subsequent frame when we have content to render but + // we may not able to update our final path properly as we + // don't know what paths got changed in between. + if (mContentToRender) list.push_back(&mDrawable); } -void LOTPaintDataItem::addPathItems(std::vector &list, - int startOffset) +void renderer::Paint::addPathItems(std::vector &list, + size_t startOffset) { std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems)); } -LOTFillItem::LOTFillItem(LOTFillData *data) - : LOTPaintDataItem(data->isStatic()), mModel(data) +renderer::Fill::Fill(model::Fill *data) + : renderer::Paint(data->isStatic()), mModel(data) { + mDrawable.setName(mModel.name()); } -void LOTFillItem::updateContent(int frameNo) +bool renderer::Fill::updateContent(int frameNo, const VMatrix &, float alpha) { - mColor = mModel.color(frameNo).toColor(mModel.opacity(frameNo)); - mMatrix = mModel.transform(frameNo); -} - -void LOTFillItem::updateRenderNode() -{ - VColor color = mColor; - VMatrix matrix = mMatrix; + auto combinedAlpha = alpha * mModel.opacity(frameNo); + auto color = mModel.color(frameNo).toColor(combinedAlpha); - color.setAlpha(color.a * parentAlpha()); VBrush brush(color); - brush.mMatrix = matrix; - mDrawable.setBrush(brush); mDrawable.setFillRule(mModel.fillRule()); -} -LOTGFillItem::LOTGFillItem(LOTGFillData *data) - : LOTPaintDataItem(data->isStatic()), mData(data) -{ + return !color.isTransparent(); } -void LOTGFillItem::updateContent(int frameNo) +renderer::GradientFill::GradientFill(model::GradientFill *data) + : renderer::Paint(data->isStatic()), mData(data) { - mAlpha = mData->opacity(frameNo); - mData->update(mGradient, frameNo); - mGradient->mMatrix = static_cast(parent())->matrix(); - mFillRule = mData->fillRule(); + mDrawable.setName(mData->name()); } -void LOTGFillItem::updateRenderNode() +bool renderer::GradientFill::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { - mGradient->setAlpha(mAlpha * parentAlpha()); + float combinedAlpha = alpha * mData->opacity(frameNo); + + mData->update(mGradient, frameNo); + mGradient->setAlpha(combinedAlpha); + mGradient->mMatrix = matrix; mDrawable.setBrush(VBrush(mGradient.get())); - mDrawable.setFillRule(mFillRule); -} + mDrawable.setFillRule(mData->fillRule()); -LOTStrokeItem::LOTStrokeItem(LOTStrokeData *data) - : LOTPaintDataItem(data->isStatic()), mModel(data) -{ - mDashArraySize = 0; + return !vIsZero(combinedAlpha); } -void LOTStrokeItem::updateContent(int frameNo) +renderer::Stroke::Stroke(model::Stroke *data) + : renderer::Paint(data->isStatic()), mModel(data) { - mColor = mModel.color(frameNo).toColor(mModel.opacity(frameNo)); - mWidth = mModel.strokeWidth(frameNo); + mDrawable.setName(mModel.name()); if (mModel.hasDashInfo()) { - mDashArraySize = mModel.getDashInfo(frameNo, mDashArray); + mDrawable.setType(VDrawable::Type::StrokeWithDash); + } else { + mDrawable.setType(VDrawable::Type::Stroke); } } -static float getScale(const VMatrix &matrix) -{ - constexpr float SQRT_2 = 1.41421; - VPointF p1(0, 0); - VPointF p2(SQRT_2, SQRT_2); - p1 = matrix.map(p1); - p2 = matrix.map(p2); - VPointF final = p2 - p1; - - return std::sqrt(final.x() * final.x() + final.y() * final.y()) / 2.0; -} +static vthread_local std::vector Dash_Vector; -void LOTStrokeItem::updateRenderNode() +bool renderer::Stroke::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { - VColor color = mColor; + auto combinedAlpha = alpha * mModel.opacity(frameNo); + auto color = mModel.color(frameNo).toColor(combinedAlpha); - color.setAlpha(color.a * parentAlpha()); VBrush brush(color); mDrawable.setBrush(brush); - float scale = - getScale(static_cast(parent())->matrix()); + float scale = matrix.scale(); mDrawable.setStrokeInfo(mModel.capStyle(), mModel.joinStyle(), - mModel.meterLimit(), mWidth * scale); - if (mDashArraySize) { - for (int i = 0; i < mDashArraySize; i++) mDashArray[i] *= scale; - - /* AE draw the dash even if dash value is 0 */ - if (vCompare(mDashArray[0], 0.0f)) mDashArray[0] = 0.1; + mModel.miterLimit(), + mModel.strokeWidth(frameNo) * scale); - mDrawable.setDashInfo(mDashArray, mDashArraySize); + if (mModel.hasDashInfo()) { + Dash_Vector.clear(); + mModel.getDashInfo(frameNo, Dash_Vector); + if (!Dash_Vector.empty()) { + for (auto &elm : Dash_Vector) elm *= scale; + mDrawable.setDashInfo(Dash_Vector); + } } -} -LOTGStrokeItem::LOTGStrokeItem(LOTGStrokeData *data) - : LOTPaintDataItem(data->isStatic()), mData(data) -{ - mDashArraySize = 0; + return !color.isTransparent(); } -void LOTGStrokeItem::updateContent(int frameNo) +renderer::GradientStroke::GradientStroke(model::GradientStroke *data) + : renderer::Paint(data->isStatic()), mData(data) { - mAlpha = mData->opacity(frameNo); - mData->update(mGradient, frameNo); - mGradient->mMatrix = static_cast(parent())->matrix(); - mCap = mData->capStyle(); - mJoin = mData->joinStyle(); - mMiterLimit = mData->meterLimit(); - mWidth = mData->width(frameNo); + mDrawable.setName(mData->name()); if (mData->hasDashInfo()) { - mDashArraySize = mData->getDashInfo(frameNo, mDashArray); + mDrawable.setType(VDrawable::Type::StrokeWithDash); + } else { + mDrawable.setType(VDrawable::Type::Stroke); } } -void LOTGStrokeItem::updateRenderNode() +bool renderer::GradientStroke::updateContent(int frameNo, const VMatrix &matrix, + float alpha) { - float scale = getScale(mGradient->mMatrix); - mGradient->setAlpha(mAlpha * parentAlpha()); + float combinedAlpha = alpha * mData->opacity(frameNo); + + mData->update(mGradient, frameNo); + mGradient->setAlpha(combinedAlpha); + mGradient->mMatrix = matrix; + auto scale = mGradient->mMatrix.scale(); mDrawable.setBrush(VBrush(mGradient.get())); - mDrawable.setStrokeInfo(mCap, mJoin, mMiterLimit, mWidth * scale); - if (mDashArraySize) { - for (int i = 0; i < mDashArraySize; i++) mDashArray[i] *= scale; - mDrawable.setDashInfo(mDashArray, mDashArraySize); + mDrawable.setStrokeInfo(mData->capStyle(), mData->joinStyle(), + mData->miterLimit(), mData->width(frameNo) * scale); + + if (mData->hasDashInfo()) { + Dash_Vector.clear(); + mData->getDashInfo(frameNo, Dash_Vector); + if (!Dash_Vector.empty()) { + for (auto &elm : Dash_Vector) elm *= scale; + mDrawable.setDashInfo(Dash_Vector); + } } -} -LOTTrimItem::LOTTrimItem(LOTTrimData *data) - : LOTContentItem(ContentType::Trim), mData(data) -{ + return !vIsZero(combinedAlpha); } -void LOTTrimItem::update(int frameNo, const VMatrix & /*parentMatrix*/, - float /*parentAlpha*/, const DirtyFlag & /*flag*/) +void renderer::Trim::update(int frameNo, const VMatrix & /*parentMatrix*/, + float /*parentAlpha*/, const DirtyFlag & /*flag*/) { mDirty = false; if (mCache.mFrameNo == frameNo) return; - LOTTrimData::Segment segment = mData->segment(frameNo); + model::Trim::Segment segment = mData->segment(frameNo); if (!(vCompare(mCache.mSegment.start, segment.start) && vCompare(mCache.mSegment.end, segment.end))) { @@ -1504,7 +1351,7 @@ void LOTTrimItem::update(int frameNo, const VMatrix & /*parentMatrix*/, mCache.mFrameNo = frameNo; } -void LOTTrimItem::update() +void renderer::Trim::update() { // when both path and trim are not dirty if (!(mDirty || pathDirty())) return; @@ -1523,14 +1370,12 @@ void LOTTrimItem::update() return; } - if (mData->type() == LOTTrimData::TrimType::Simultaneously) { + if (mData->type() == model::Trim::TrimType::Simultaneously) { for (auto &i : mPathItems) { - VPathMesure pm; - pm.setStart(mCache.mSegment.start); - pm.setEnd(mCache.mSegment.end); - i->updatePath(pm.trim(i->localPath())); + mPathMesure.setRange(mCache.mSegment.start, mCache.mSegment.end); + i->updatePath(mPathMesure.trim(i->localPath())); } - } else { // LOTTrimData::TrimType::Individually + } else { // model::Trim::TrimType::Individually float totalLength = 0.0; for (auto &i : mPathItems) { totalLength += i->localPath().length(); @@ -1562,11 +1407,8 @@ void LOTTrimItem::update() local_start /= len; float local_end = curLen + len < end ? len : end - curLen; local_end /= len; - VPathMesure pm; - pm.setStart(local_start); - pm.setEnd(local_end); - VPath p = pm.trim(i->localPath()); - i->updatePath(p); + mPathMesure.setRange(local_start, local_end); + i->updatePath(mPathMesure.trim(i->localPath())); curLen += len; } } @@ -1574,29 +1416,30 @@ void LOTTrimItem::update() } } -void LOTTrimItem::addPathItems(std::vector &list, - int startOffset) +void renderer::Trim::addPathItems(std::vector &list, + size_t startOffset) { std::copy(list.begin() + startOffset, list.end(), back_inserter(mPathItems)); } -LOTRepeaterItem::LOTRepeaterItem(LOTRepeaterData *data) : mRepeaterData(data) +renderer::Repeater::Repeater(model::Repeater *data, VArenaAlloc *allocator) + : mRepeaterData(data) { assert(mRepeaterData->content()); mCopies = mRepeaterData->maxCopies(); for (int i = 0; i < mCopies; i++) { - auto content = - std::make_unique(mRepeaterData->content()); - content->setParent(this); - mContents.push_back(std::move(content)); + auto content = allocator->make( + mRepeaterData->content(), allocator); + // content->setParent(this); + mContents.push_back(content); } } -void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, - float parentAlpha, const DirtyFlag &flag) +void renderer::Repeater::update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) { DirtyFlag newFlag = flag; @@ -1606,10 +1449,10 @@ void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, if (visibleCopies == 0) { mHidden = true; return; - } else { - mHidden = false; } + mHidden = false; + if (!mRepeaterData->isStatic()) newFlag |= DirtyFlagBit::Matrix; float offset = mRepeaterData->offset(frameNo); @@ -1631,144 +1474,8 @@ void LOTRepeaterItem::update(int frameNo, const VMatrix &parentMatrix, } } -void LOTRepeaterItem::renderList(std::vector &list) +void renderer::Repeater::renderList(std::vector &list) { if (mHidden) return; - return LOTContentGroupItem::renderList(list); -} - -static void updateGStops(LOTNode *n, const VGradient *grad) -{ - if (grad->mStops.size() != n->mGradient.stopCount) { - if (n->mGradient.stopCount) free(n->mGradient.stopPtr); - n->mGradient.stopCount = grad->mStops.size(); - n->mGradient.stopPtr = (LOTGradientStop *)malloc( - n->mGradient.stopCount * sizeof(LOTGradientStop)); - } - - LOTGradientStop *ptr = n->mGradient.stopPtr; - for (const auto &i : grad->mStops) { - ptr->pos = i.first; - ptr->a = i.second.alpha() * grad->alpha(); - ptr->r = i.second.red(); - ptr->g = i.second.green(); - ptr->b = i.second.blue(); - ptr++; - } -} - -void LOTDrawable::sync() -{ - if (!mCNode) { - mCNode = std::make_unique(); - mCNode->mGradient.stopPtr = nullptr; - mCNode->mGradient.stopCount = 0; - } - - mCNode->mFlag = ChangeFlagNone; - if (mFlag & DirtyState::None) return; - - if (mFlag & DirtyState::Path) { - if (mStroke.mDash.size()) { - VDasher dasher(mStroke.mDash.data(), mStroke.mDash.size()); - mPath = dasher.dashed(mPath); - } - const std::vector &elm = mPath.elements(); - const std::vector & pts = mPath.points(); - const float *ptPtr = reinterpret_cast(pts.data()); - const char * elmPtr = reinterpret_cast(elm.data()); - mCNode->mPath.elmPtr = elmPtr; - mCNode->mPath.elmCount = elm.size(); - mCNode->mPath.ptPtr = ptPtr; - mCNode->mPath.ptCount = 2 * pts.size(); - mCNode->mFlag |= ChangeFlagPath; - } - - if (mStroke.enable) { - mCNode->mStroke.width = mStroke.width; - mCNode->mStroke.meterLimit = mStroke.meterLimit; - mCNode->mStroke.enable = 1; - - switch (mStroke.cap) { - case CapStyle::Flat: - mCNode->mStroke.cap = LOTCapStyle::CapFlat; - break; - case CapStyle::Square: - mCNode->mStroke.cap = LOTCapStyle::CapSquare; - break; - case CapStyle::Round: - mCNode->mStroke.cap = LOTCapStyle::CapRound; - break; - } - - switch (mStroke.join) { - case JoinStyle::Miter: - mCNode->mStroke.join = LOTJoinStyle::JoinMiter; - break; - case JoinStyle::Bevel: - mCNode->mStroke.join = LOTJoinStyle::JoinBevel; - break; - case JoinStyle::Round: - mCNode->mStroke.join = LOTJoinStyle::JoinRound; - break; - default: - mCNode->mStroke.join = LOTJoinStyle::JoinMiter; - break; - } - } else { - mCNode->mStroke.enable = 0; - } - - switch (mFillRule) { - case FillRule::EvenOdd: - mCNode->mFillRule = LOTFillRule::FillEvenOdd; - break; - default: - mCNode->mFillRule = LOTFillRule::FillWinding; - break; - } - - switch (mBrush.type()) { - case VBrush::Type::Solid: - mCNode->mBrushType = LOTBrushType::BrushSolid; - mCNode->mColor.r = mBrush.mColor.r; - mCNode->mColor.g = mBrush.mColor.g; - mCNode->mColor.b = mBrush.mColor.b; - mCNode->mColor.a = mBrush.mColor.a; - break; - case VBrush::Type::LinearGradient: { - mCNode->mBrushType = LOTBrushType::BrushGradient; - mCNode->mGradient.type = LOTGradientType::GradientLinear; - VPointF s = mBrush.mGradient->mMatrix.map( - {mBrush.mGradient->linear.x1, mBrush.mGradient->linear.y1}); - VPointF e = mBrush.mGradient->mMatrix.map( - {mBrush.mGradient->linear.x2, mBrush.mGradient->linear.y2}); - mCNode->mGradient.start.x = s.x(); - mCNode->mGradient.start.y = s.y(); - mCNode->mGradient.end.x = e.x(); - mCNode->mGradient.end.y = e.y(); - updateGStops(mCNode.get(), mBrush.mGradient); - break; - } - case VBrush::Type::RadialGradient: { - mCNode->mBrushType = LOTBrushType::BrushGradient; - mCNode->mGradient.type = LOTGradientType::GradientRadial; - VPointF c = mBrush.mGradient->mMatrix.map( - {mBrush.mGradient->radial.cx, mBrush.mGradient->radial.cy}); - VPointF f = mBrush.mGradient->mMatrix.map( - {mBrush.mGradient->radial.fx, mBrush.mGradient->radial.fy}); - mCNode->mGradient.center.x = c.x(); - mCNode->mGradient.center.y = c.y(); - mCNode->mGradient.focal.x = f.x(); - mCNode->mGradient.focal.y = f.y(); - - float scale = getScale(mBrush.mGradient->mMatrix); - mCNode->mGradient.cradius = mBrush.mGradient->radial.cradius * scale; - mCNode->mGradient.fradius = mBrush.mGradient->radial.fradius * scale; - updateGStops(mCNode.get(), mBrush.mGradient); - break; - } - default: - break; - } + return renderer::Group::renderList(list); } diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieitem.h b/AXrLottie/src/main/cpp/src/lottie/lottieitem.h index 6f5d3a2..6f60254 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottieitem.h +++ b/AXrLottie/src/main/cpp/src/lottie/lottieitem.h @@ -1,528 +1,626 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef LOTTIEITEM_H #define LOTTIEITEM_H -#include -#include - -#include"lottieproxymodel.h" -#include"vmatrix.h" -#include"vpath.h" -#include"vpoint.h" -#include"vpathmesure.h" -#include"rlottiecommon.h" -#include"rlottie.h" -#include"vpainter.h" -#include"vdrawable.h" -#include"lottiekeypath.h" +#include +#include + +#include "lottiekeypath.h" +#include "lottiefiltermodel.h" +#include "rlottie.h" +#include "rlottiecommon.h" +#include "varenaalloc.h" +#include "vdrawable.h" +#include "vmatrix.h" +#include "vpainter.h" +#include "vpath.h" +#include "vpathmesure.h" +#include "vpoint.h" V_USE_NAMESPACE -enum class DirtyFlagBit : uchar -{ - None = 0x00, - Matrix = 0x01, - Alpha = 0x02, - All = (Matrix | Alpha) +namespace rlottie { + +namespace internal { + +template +class VSpan { +public: + using reference = T &; + using pointer = T *; + using const_pointer = T const *; + using const_reference = T const &; + using index_type = size_t; + + using iterator = pointer; + using const_iterator = const_pointer; + + VSpan() = default; + VSpan(pointer data, index_type size) : _data(data), _size(size) {} + + constexpr pointer data() const noexcept { return _data; } + constexpr index_type size() const noexcept { return _size; } + constexpr bool empty() const noexcept { return size() == 0; } + constexpr iterator begin() const noexcept { return data(); } + constexpr iterator end() const noexcept { return data() + size(); } + constexpr const_iterator cbegin() const noexcept { return data(); } + constexpr const_iterator cend() const noexcept { return data() + size(); } + constexpr reference operator[](index_type idx) const + { + return *(data() + idx); + } + +private: + pointer _data{nullptr}; + index_type _size{0}; +}; + +namespace renderer { + +using DrawableList = VSpan; + +enum class DirtyFlagBit : uchar { + None = 0x00, + Matrix = 0x01, + Alpha = 0x02, + All = (Matrix | Alpha) }; +typedef vFlag DirtyFlag; -class LOTLayerItem; -class LOTMaskItem; -class VDrawable; +class SurfaceCache { +public: + SurfaceCache() { mCache.reserve(10); } + + VBitmap make_surface( + size_t width, size_t height, + VBitmap::Format format = VBitmap::Format::ARGB32_Premultiplied) + { + if (mCache.empty()) return {width, height, format}; -class LOTDrawable : public VDrawable -{ + auto surface = mCache.back(); + surface.reset(width, height, format); + + mCache.pop_back(); + return surface; + } + + void release_surface(VBitmap &surface) { mCache.push_back(surface); } + +private: + std::vector mCache; +}; + +class Drawable final : public VDrawable { public: void sync(); + public: - std::unique_ptr mCNode{nullptr}; + std::unique_ptr mCNode{nullptr}; - ~LOTDrawable() { + ~Drawable() noexcept + { if (mCNode && mCNode->mGradient.stopPtr) - free(mCNode->mGradient.stopPtr); + free(mCNode->mGradient.stopPtr); } }; -class LOTCompItem -{ +struct CApiData { + CApiData(); + LOTLayerNode mLayer; + std::vector mMasks; + std::vector mLayers; + std::vector mCNodeList; +}; + +class Clipper { public: - explicit LOTCompItem(LOTModel *model); - static std::unique_ptr createLayerItem(LOTLayerData *layerData); - bool update(int frameNo); - void resize(const VSize &size); - VSize size() const; - void buildRenderTree(); - const LOTLayerNode * renderTree()const; - bool render(const rlottie::Surface &surface); - void setValue(const std::string &keypath, LOTVariant &value); - void resetCurrentFrame(); -private: - VMatrix mScaleMatrix; - VSize mViewSize; - LOTCompositionData *mCompData; - std::unique_ptr mRootLayer; - bool mUpdateViewBox; - int mCurFrameNo; - std::vector mRenderList; - std::vector mDrawableList; + explicit Clipper(VSize size) : mSize(size) {} + void update(const VMatrix &matrix); + void preprocess(const VRect &clip); + VRle rle(const VRle &mask); + +public: + VSize mSize; + VPath mPath; + VRle mMaskedRle; + VRasterizer mRasterizer; + bool mRasterRequest{false}; }; -class LOTLayerMaskItem; +class Mask { +public: + explicit Mask(model::Mask *data) : mData(data) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag); + model::Mask::Mode maskMode() const { return mData->mMode; } + VRle rle(); + void preprocess(const VRect &clip); + bool inverted() const { return mData->mInv; } +public: + model::Mask *mData{nullptr}; + VPath mLocalPath; + VPath mFinalPath; + VRasterizer mRasterizer; + float mCombinedAlpha{0}; + bool mRasterRequest{false}; +}; -class LOTClipperItem -{ +/* + * Handels mask property of a layer item + */ +class LayerMask { public: - explicit LOTClipperItem(VSize size): mSize(size){} - void update(const VMatrix &matrix); - VRle rle(); + explicit LayerMask(model::Layer *layerData); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag); + bool isStatic() const { return mStatic; } + VRle maskRle(const VRect &clipRect); + void preprocess(const VRect &clip); + public: - VSize mSize; - VPath mPath; - VRasterizer mRasterizer; + std::vector mMasks; + VRle mRle; + bool mStatic{true}; + bool mDirty{true}; }; -typedef vFlag DirtyFlag; +class Layer; -class LOTLayerItem -{ +class Composition { public: - virtual ~LOTLayerItem() = default; - LOTLayerItem& operator=(LOTLayerItem&&) noexcept = delete; - LOTLayerItem(LOTLayerData *layerData); - int id() const {return mLayerData->id();} - int parentId() const {return mLayerData->parentId();} - LOTLayerItem *resolvedParentLayer() const {return mParentLayer;} - void setParentLayer(LOTLayerItem *parent){mParentLayer = parent;} - void setComplexContent(bool value) { mComplexContent = value;} - bool complexContent() const {return mComplexContent;} - virtual void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha); - VMatrix matrix(int frameNo) const; - virtual void renderList(std::vector &){} - virtual void render(VPainter *painter, const VRle &mask, const VRle &matteRle); - bool hasMatte() { if (mLayerData->mMatteType == MatteType::None) return false; return true; } - MatteType matteType() const { return mLayerData->mMatteType;} - bool visible() const; - virtual void buildLayerNode(); - LOTLayerNode * layerNode() const {return mLayerCNode.get();} - const std::string & name() const {return mLayerData->name();} - virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value); - VBitmap& bitmap() {return mRenderBuffer;} + explicit Composition(std::shared_ptr composition); + bool update(int frameNo, const VSize &size, bool keepAspectRatio); + VSize size() const { return mViewSize; } + void buildRenderTree(); + const LOTLayerNode *renderTree() const; + bool render(const rlottie::Surface &surface); + void setValue(const std::string &keypath, LOTVariant &value); + +private: + SurfaceCache mSurfaceCache; + VBitmap mSurface; + VMatrix mScaleMatrix; + VSize mViewSize; + std::shared_ptr mModel; + Layer * mRootLayer{nullptr}; + VArenaAlloc mAllocator{2048}; + int mCurFrameNo; + bool mKeepAspectRatio{true}; +}; + +class Layer { +public: + virtual ~Layer() = default; + Layer &operator=(Layer &&) noexcept = delete; + Layer(model::Layer *layerData); + int id() const { return mLayerData->id(); } + int parentId() const { return mLayerData->parentId(); } + void setParentLayer(Layer *parent) { mParentLayer = parent; } + void setComplexContent(bool value) { mComplexContent = value; } + bool complexContent() const { return mComplexContent; } + virtual void update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha); + VMatrix matrix(int frameNo) const; + void preprocess(const VRect &clip); + virtual DrawableList renderList() { return {}; } + virtual void render(VPainter *painter, const VRle &mask, + const VRle &matteRle, SurfaceCache &cache); + bool hasMatte() + { + if (mLayerData->mMatteType == model::MatteType::None) return false; + return true; + } + model::MatteType matteType() const { return mLayerData->mMatteType; } + bool visible() const; + virtual void buildLayerNode(); + LOTLayerNode & clayer() { return mCApiData->mLayer; } + std::vector &clayers() { return mCApiData->mLayers; } + std::vector & cmasks() { return mCApiData->mMasks; } + std::vector & cnodes() { return mCApiData->mCNodeList; } + const char * name() const { return mLayerData->name(); } + virtual bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value); + protected: - virtual void updateContent() = 0; - inline VMatrix combinedMatrix() const {return mCombinedMatrix;} - inline int frameNo() const {return mFrameNo;} - inline float combinedAlpha() const {return mCombinedAlpha;} - inline bool isStatic() const {return mLayerData->isStatic();} - float opacity(int frameNo) const {return mLayerData->opacity(frameNo);} - inline DirtyFlag flag() const {return mDirtyFlag;} + virtual void preprocessStage(const VRect &clip) = 0; + virtual void updateContent() = 0; + inline VMatrix combinedMatrix() const { return mCombinedMatrix; } + inline int frameNo() const { return mFrameNo; } + inline float combinedAlpha() const { return mCombinedAlpha; } + inline bool isStatic() const { return mLayerData->isStatic(); } + float opacity(int frameNo) const { return mLayerData->opacity(frameNo); } + inline DirtyFlag flag() const { return mDirtyFlag; } + bool skipRendering() const + { + return (!visible() || vIsZero(combinedAlpha())); + } + protected: - std::vector mMasksCNode; - std::unique_ptr mLayerCNode; - std::vector mDrawableList; - std::unique_ptr mLayerMask; - LOTLayerData *mLayerData{nullptr}; - LOTLayerItem *mParentLayer{nullptr}; - VMatrix mCombinedMatrix; - VBitmap mRenderBuffer; - float mCombinedAlpha{0.0}; - int mFrameNo{-1}; - DirtyFlag mDirtyFlag{DirtyFlagBit::All}; - bool mComplexContent{false}; + std::unique_ptr mLayerMask; + model::Layer * mLayerData{nullptr}; + Layer * mParentLayer{nullptr}; + VMatrix mCombinedMatrix; + float mCombinedAlpha{0.0}; + int mFrameNo{-1}; + DirtyFlag mDirtyFlag{DirtyFlagBit::All}; + bool mComplexContent{false}; + std::unique_ptr mCApiData; }; -class LOTCompLayerItem: public LOTLayerItem -{ +class CompLayer final : public Layer { public: - explicit LOTCompLayerItem(LOTLayerData *layerData); - void renderList(std::vector &list)final; - void render(VPainter *painter, const VRle &mask, const VRle &matteRle) final; - void buildLayerNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override; + explicit CompLayer(model::Layer *layerData, VArenaAlloc *allocator); + + void render(VPainter *painter, const VRle &mask, const VRle &matteRle, + SurfaceCache &cache) final; + void buildLayerNode() final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; + protected: - void updateContent() final; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + private: - void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle); - void renderMatteLayer(VPainter *painter, const VRle &inheritMask, const VRle &matteRle, - LOTLayerItem *layer, LOTLayerItem *src); + void renderHelper(VPainter *painter, const VRle &mask, const VRle &matteRle, + SurfaceCache &cache); + void renderMatteLayer(VPainter *painter, const VRle &inheritMask, + const VRle &matteRle, Layer *layer, Layer *src, + SurfaceCache &cache); + private: - std::vector mLayersCNode; - std::vector> mLayers; - std::unique_ptr mClipper; + std::vector mLayers; + std::unique_ptr mClipper; }; -class LOTSolidLayerItem: public LOTLayerItem -{ +class SolidLayer final : public Layer { public: - explicit LOTSolidLayerItem(LOTLayerData *layerData); - void buildLayerNode() final; + explicit SolidLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; + protected: - void updateContent() final; - void renderList(std::vector &list) final; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + private: - std::vector mCNodeList; - LOTDrawable mRenderNode; + Drawable mRenderNode; + VPath mPath; + VDrawable *mDrawableList{nullptr}; // to work with the Span api }; -class LOTContentItem; -class LOTContentGroupItem; -class LOTShapeLayerItem: public LOTLayerItem -{ +class Group; + +class ShapeLayer final : public Layer { public: - explicit LOTShapeLayerItem(LOTLayerData *layerData); - static std::unique_ptr createContentItem(LOTData *contentData); - void renderList(std::vector &list)final; - void buildLayerNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override; + explicit ShapeLayer(model::Layer *layerData, VArenaAlloc *allocator); + DrawableList renderList() final; + void buildLayerNode() final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; + protected: - void updateContent() final; - std::vector mCNodeList; - std::unique_ptr mRoot; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + std::vector mDrawableList; + Group * mRoot{nullptr}; }; -class LOTNullLayerItem: public LOTLayerItem -{ +class NullLayer final : public Layer { public: - explicit LOTNullLayerItem(LOTLayerData *layerData); + explicit NullLayer(model::Layer *layerData); + protected: - void updateContent() final; + void preprocessStage(const VRect &) final {} + void updateContent() final; }; -class LOTImageLayerItem: public LOTLayerItem -{ +class ImageLayer final : public Layer { public: - explicit LOTImageLayerItem(LOTLayerData *layerData); - void buildLayerNode() final; + explicit ImageLayer(model::Layer *layerData); + void buildLayerNode() final; + DrawableList renderList() final; + protected: - void updateContent() final; - void renderList(std::vector &list) final; + void preprocessStage(const VRect &clip) final; + void updateContent() final; + private: - std::vector mCNodeList; - LOTDrawable mRenderNode; + Drawable mRenderNode; + VTexture mTexture; + VPath mPath; + VDrawable *mDrawableList{nullptr}; // to work with the Span api }; -class LOTMaskItem -{ +class Object { public: - explicit LOTMaskItem(LOTMaskData *data): mData(data){} - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag); - LOTMaskData::Mode maskMode() const { return mData->mMode;} - VRle rle(); -public: - LOTMaskData *mData; - float mCombinedAlpha{0}; - VMatrix mCombinedMatrix; - VPath mLocalPath; - VPath mFinalPath; - VRasterizer mRasterizer; - bool mRasterRequest{false}; + enum class Type : uchar { Unknown, Group, Shape, Paint, Trim }; + virtual ~Object() = default; + Object & operator=(Object &&) noexcept = delete; + virtual void update(int frameNo, const VMatrix &parentMatrix, + float parentAlpha, const DirtyFlag &flag) = 0; + virtual void renderList(std::vector &) {} + virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &) + { + return false; + } + virtual Object::Type type() const { return Object::Type::Unknown; } }; -/* - * Handels mask property of a layer item - */ -class LOTLayerMaskItem -{ -public: - explicit LOTLayerMaskItem(LOTLayerData *layerData); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag); - bool isStatic() const {return mStatic;} - VRle maskRle(const VRect &clipRect); +class Shape; +class Group : public Object { public: - std::vector mMasks; - VRle mRle; - bool mStatic{true}; - bool mDirty{true}; -}; + Group() = default; + explicit Group(model::Group *data, VArenaAlloc *allocator); + void addChildren(model::Group *data, VArenaAlloc *allocator); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) override; + void applyTrim(); + void processTrimItems(std::vector &list); + void processPaintItems(std::vector &list); + void renderList(std::vector &list) override; + Object::Type type() const final { return Object::Type::Group; } + const VMatrix &matrix() const { return mMatrix; } + const char * name() const + { + static const char *TAG = "__"; + return mModel.hasModel() ? mModel.name() : TAG; + } + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) override; -class LOTPathDataItem; -class LOTPaintDataItem; -class LOTTrimItem; - -enum class ContentType -{ - Unknown, - Group, - Path, - Paint, - Trim -}; +protected: + std::vector mContents; + VMatrix mMatrix; -class LOTContentItem -{ -public: - virtual ~LOTContentItem() = default; - LOTContentItem& operator=(LOTContentItem&&) noexcept = delete; - LOTContentItem(ContentType type=ContentType::Unknown):mType(type) {} - virtual void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) = 0; - virtual void renderList(std::vector &){} - void setParent(LOTContentItem *parent) {mParent = parent;} - LOTContentItem *parent() const {return mParent;} - virtual bool resolveKeyPath(LOTKeyPath &, uint, LOTVariant &) {return false;} - ContentType type() const {return mType;} private: - ContentType mType{ContentType::Unknown}; - LOTContentItem *mParent{nullptr}; + model::Filter mModel; }; -class LOTContentGroupItem: public LOTContentItem -{ +class Shape : public Object { public: - explicit LOTContentGroupItem(LOTGroupData *data=nullptr); - void addChildren(LOTGroupData *data); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override; - void applyTrim(); - void processTrimItems(std::vector &list); - void processPaintItems(std::vector &list); - void renderList(std::vector &list) override; - const VMatrix & matrix() const { return mMatrix;} - const std::string & name() const - { - static const std::string TAG = "__"; - return mData ? mData->name() : TAG; - } - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) override; -protected: - LOTGroupData *mData{nullptr}; - std::vector> mContents; - VMatrix mMatrix; -}; + Shape(bool staticPath) : mStaticPath(staticPath) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + Object::Type type() const final { return Object::Type::Shape; } + bool dirty() const { return mDirtyPath; } + const VPath &localPath() const { return mTemp; } + void finalPath(VPath &result); + void updatePath(const VPath &path) + { + mTemp = path; + mDirtyPath = true; + } + bool staticPath() const { return mStaticPath; } + void setParent(Group *parent) { mParent = parent; } + Group *parent() const { return mParent; } -class LOTPathDataItem : public LOTContentItem -{ -public: - LOTPathDataItem(bool staticPath): LOTContentItem(ContentType::Path), mStaticPath(staticPath){} - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - bool dirty() const {return mPathChanged;} - const VPath &localPath() const {return mTemp;} - const VPath &finalPath(); - void updatePath(const VPath &path) {mTemp = path; mPathChanged = true; mNeedUpdate = true;} - bool staticPath() const { return mStaticPath; } protected: - virtual void updatePath(VPath& path, int frameNo) = 0; - virtual bool hasChanged(int prevFrame, int curFrame) = 0; + virtual void updatePath(VPath &path, int frameNo) = 0; + virtual bool hasChanged(int prevFrame, int curFrame) = 0; + private: - bool hasChanged(int frameNo) { - int prevFrame = mFrameNo; - mFrameNo = frameNo; - if (prevFrame == -1) return true; - if (mStaticPath || - (prevFrame == frameNo)) return false; - return hasChanged(prevFrame, frameNo); - } - VPath mLocalPath; - VPath mTemp; - VPath mFinalPath; - int mFrameNo{-1}; - bool mPathChanged{true}; - bool mNeedUpdate{true}; - bool mStaticPath; + bool hasChanged(int frameNo) + { + int prevFrame = mFrameNo; + mFrameNo = frameNo; + if (prevFrame == -1) return true; + if (mStaticPath || (prevFrame == frameNo)) return false; + return hasChanged(prevFrame, frameNo); + } + Group *mParent{nullptr}; + VPath mLocalPath; + VPath mTemp; + int mFrameNo{-1}; + bool mDirtyPath{true}; + bool mStaticPath; }; -class LOTRectItem: public LOTPathDataItem -{ +class Rect final : public Shape { public: - explicit LOTRectItem(LOTRectData *data); + explicit Rect(model::Rect *data); + protected: - void updatePath(VPath& path, int frameNo) final; - LOTRectData *mData; - - bool hasChanged(int prevFrame, int curFrame) final { - return (mData->mPos.changed(prevFrame, curFrame) || - mData->mSize.changed(prevFrame, curFrame) || - mData->mRound.changed(prevFrame, curFrame)) ? true : false; - } + void updatePath(VPath &path, int frameNo) final; + model::Rect *mData{nullptr}; + + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mSize.changed(prevFrame, curFrame) || + mData->roundnessChanged(prevFrame, curFrame)); + } }; -class LOTEllipseItem: public LOTPathDataItem -{ +class Ellipse final : public Shape { public: - explicit LOTEllipseItem(LOTEllipseData *data); + explicit Ellipse(model::Ellipse *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTEllipseData *mData; - bool hasChanged(int prevFrame, int curFrame) final { - return (mData->mPos.changed(prevFrame, curFrame) || - mData->mSize.changed(prevFrame, curFrame)) ? true : false; - } + void updatePath(VPath &path, int frameNo) final; + model::Ellipse *mData{nullptr}; + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mSize.changed(prevFrame, curFrame)); + } }; -class LOTShapeItem: public LOTPathDataItem -{ +class Path final : public Shape { public: - explicit LOTShapeItem(LOTShapeData *data); + explicit Path(model::Path *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTShapeData *mData; - bool hasChanged(int prevFrame, int curFrame) final { - return mData->mShape.changed(prevFrame, curFrame); - } + void updatePath(VPath &path, int frameNo) final; + model::Path *mData{nullptr}; + bool hasChanged(int prevFrame, int curFrame) final + { + return mData->mShape.changed(prevFrame, curFrame); + } }; -class LOTPolystarItem: public LOTPathDataItem -{ +class Polystar final : public Shape { public: - explicit LOTPolystarItem(LOTPolystarData *data); + explicit Polystar(model::Polystar *data); + private: - void updatePath(VPath& path, int frameNo) final; - LOTPolystarData *mData; - - bool hasChanged(int prevFrame, int curFrame) final { - return (mData->mPos.changed(prevFrame, curFrame) || - mData->mPointCount.changed(prevFrame, curFrame) || - mData->mInnerRadius.changed(prevFrame, curFrame) || - mData->mOuterRadius.changed(prevFrame, curFrame) || - mData->mInnerRoundness.changed(prevFrame, curFrame) || - mData->mOuterRoundness.changed(prevFrame, curFrame) || - mData->mRotation.changed(prevFrame, curFrame)) ? true : false; - } + void updatePath(VPath &path, int frameNo) final; + model::Polystar *mData{nullptr}; + + bool hasChanged(int prevFrame, int curFrame) final + { + return (mData->mPos.changed(prevFrame, curFrame) || + mData->mPointCount.changed(prevFrame, curFrame) || + mData->mInnerRadius.changed(prevFrame, curFrame) || + mData->mOuterRadius.changed(prevFrame, curFrame) || + mData->mInnerRoundness.changed(prevFrame, curFrame) || + mData->mOuterRoundness.changed(prevFrame, curFrame) || + mData->mRotation.changed(prevFrame, curFrame)); + } }; - - -class LOTPaintDataItem : public LOTContentItem -{ +class Paint : public Object { public: - LOTPaintDataItem(bool staticContent); - void addPathItems(std::vector &list, int startOffset); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) override; - void renderList(std::vector &list) final; + Paint(bool staticContent); + void addPathItems(std::vector &list, size_t startOffset); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) override; + void renderList(std::vector &list) final; + Object::Type type() const final { return Object::Type::Paint; } + protected: - virtual void updateContent(int frameNo) = 0; - virtual void updateRenderNode(); - inline float parentAlpha() const {return mParentAlpha;} + virtual bool updateContent(int frameNo, const VMatrix &matrix, + float alpha) = 0; + +private: + void updateRenderNode(); + protected: - std::vector mPathItems; - LOTDrawable mDrawable; - VPath mPath; - float mParentAlpha{1.0f}; - int mFrameNo{-1}; - DirtyFlag mFlag; - bool mStaticContent; - bool mRenderNodeUpdate{true}; + std::vector mPathItems; + Drawable mDrawable; + VPath mPath; + DirtyFlag mFlag; + bool mStaticContent; + bool mRenderNodeUpdate{true}; + bool mContentToRender{true}; }; -class LOTFillItem : public LOTPaintDataItem -{ +class Fill final : public Paint { public: - explicit LOTFillItem(LOTFillData *data); + explicit Fill(model::Fill *data); + protected: - void updateContent(int frameNo) final; - void updateRenderNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + private: - LOTProxyModel mModel; - VColor mColor; - VMatrix mMatrix; + model::Filter mModel; }; -class LOTGFillItem : public LOTPaintDataItem -{ +class GradientFill final : public Paint { public: - explicit LOTGFillItem(LOTGFillData *data); + explicit GradientFill(model::GradientFill *data); + protected: - void updateContent(int frameNo) final; - void updateRenderNode() final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + private: - LOTGFillData *mData; - std::unique_ptr mGradient; - float mAlpha{1.0}; - FillRule mFillRule{FillRule::Winding}; + model::GradientFill * mData{nullptr}; + std::unique_ptr mGradient; }; -class LOTStrokeItem : public LOTPaintDataItem -{ +class Stroke : public Paint { public: - explicit LOTStrokeItem(LOTStrokeData *data); + explicit Stroke(model::Stroke *data); + protected: - void updateContent(int frameNo) final; - void updateRenderNode() final; - bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, LOTVariant &value) final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + bool resolveKeyPath(LOTKeyPath &keyPath, uint depth, + LOTVariant &value) final; + private: - LOTProxyModel mModel; - VColor mColor; - float mWidth{0}; - float mDashArray[6]; - int mDashArraySize{0}; + model::Filter mModel; }; -class LOTGStrokeItem : public LOTPaintDataItem -{ +class GradientStroke final : public Paint { public: - explicit LOTGStrokeItem(LOTGStrokeData *data); + explicit GradientStroke(model::GradientStroke *data); + protected: - void updateContent(int frameNo) final; - void updateRenderNode() final; + bool updateContent(int frameNo, const VMatrix &matrix, float alpha) final; + private: - LOTGStrokeData *mData; - std::unique_ptr mGradient; - CapStyle mCap{CapStyle::Flat}; - JoinStyle mJoin{JoinStyle::Miter}; - float mMiterLimit{0}; - VColor mColor; - float mAlpha{1.0}; - float mWidth{0}; - float mDashArray[6]; - int mDashArraySize{0}; + model::GradientStroke * mData{nullptr}; + std::unique_ptr mGradient; }; - -// Trim Item - -class LOTTrimItem : public LOTContentItem -{ +class Trim final : public Object { public: - LOTTrimItem(LOTTrimData *data); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - void update(); - void addPathItems(std::vector &list, int startOffset); + explicit Trim(model::Trim *data) : mData(data) {} + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + Object::Type type() const final { return Object::Type::Trim; } + void update(); + void addPathItems(std::vector &list, size_t startOffset); + private: - bool pathDirty() const { - for (auto &i : mPathItems) { - if (i->dirty()) - return true; - } - return false; - } - struct Cache { - int mFrameNo{-1}; - LOTTrimData::Segment mSegment{}; - }; - Cache mCache; - std::vector mPathItems; - LOTTrimData *mData; - bool mDirty{true}; + bool pathDirty() const + { + for (auto &i : mPathItems) { + if (i->dirty()) return true; + } + return false; + } + struct Cache { + int mFrameNo{-1}; + model::Trim::Segment mSegment{}; + }; + Cache mCache; + std::vector mPathItems; + model::Trim * mData{nullptr}; + VPathMesure mPathMesure; + bool mDirty{true}; }; -class LOTRepeaterItem : public LOTContentGroupItem -{ +class Repeater final : public Group { public: - explicit LOTRepeaterItem(LOTRepeaterData *data); - void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, const DirtyFlag &flag) final; - void renderList(std::vector &list) final; + explicit Repeater(model::Repeater *data, VArenaAlloc *allocator); + void update(int frameNo, const VMatrix &parentMatrix, float parentAlpha, + const DirtyFlag &flag) final; + void renderList(std::vector &list) final; + private: - LOTRepeaterData *mRepeaterData; - bool mHidden{false}; - int mCopies{0}; + model::Repeater *mRepeaterData{nullptr}; + bool mHidden{false}; + int mCopies{0}; }; +} // namespace renderer -#endif // LOTTIEITEM_H +} // namespace internal +} // namespace rlottie +#endif // LOTTIEITEM_H diff --git a/AXrLottie/src/main/cpp/src/lottie/lottiekeypath.h b/AXrLottie/src/main/cpp/src/lottie/lottiekeypath.h index 527788f..0b59b16 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottiekeypath.h +++ b/AXrLottie/src/main/cpp/src/lottie/lottiekeypath.h @@ -1,46 +1,53 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef LOTTIEKEYPATH_H #define LOTTIEKEYPATH_H -#include "vglobal.h" #include #include +#include "vglobal.h" -class LOTKeyPath{ +class LOTKeyPath { public: LOTKeyPath(const std::string &keyPath); bool matches(const std::string &key, uint depth); uint nextDepth(const std::string key, uint depth); bool fullyResolvesTo(const std::string key, uint depth); - bool propagate(const std::string key, uint depth) { + bool propagate(const std::string key, uint depth) + { return skip(key) ? true : (depth < size()) || (mKeys[depth] == "**"); } - bool skip(const std::string &key) const { return key == "__";} + bool skip(const std::string &key) const { return key == "__"; } + private: - bool isGlobstar(uint depth) const {return mKeys[depth] == "**";} - bool isGlob(uint depth) const {return mKeys[depth] == "*";} - bool endsWithGlobstar() const { return mKeys.back() == "**"; } - uint size() const {return mKeys.size() - 1;} + bool isGlobstar(uint depth) const { return mKeys[depth] == "**"; } + bool isGlob(uint depth) const { return mKeys[depth] == "*"; } + bool endsWithGlobstar() const { return mKeys.back() == "**"; } + size_t size() const { return mKeys.size() - 1; } + private: std::vector mKeys; }; -#endif //LOTTIEKEYPATH_H +#endif // LOTTIEKEYPATH_H diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieloader.cpp b/AXrLottie/src/main/cpp/src/lottie/lottieloader.cpp index 2d6dd6d..8a52949 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottieloader.cpp +++ b/AXrLottie/src/main/cpp/src/lottie/lottieloader.cpp @@ -1,69 +1,99 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ -#include "lottieloader.h" -#include "lottieparser.h" - #include #include -#include -using namespace std; +#include + +#include "lottiemodel.h" + +using namespace rlottie::internal; #ifdef LOTTIE_CACHE_SUPPORT -class LottieFileCache { +#include +#include + +class ModelCache { public: - static LottieFileCache &instance() + static ModelCache &instance() { - static LottieFileCache CACHE; - return CACHE; + static ModelCache singleton; + return singleton; } - std::shared_ptr find(const std::string &key) + std::shared_ptr find(const std::string &key) { + std::lock_guard guard(mMutex); + + if (!mcacheSize) return nullptr; + auto search = mHash.find(key); - if (search != mHash.end()) { - return search->second; - } else { - return nullptr; - } + + return (search != mHash.end()) ? search->second : nullptr; } - void add(const std::string &key, std::shared_ptr value) + void add(const std::string &key, std::shared_ptr value) { + std::lock_guard guard(mMutex); + + if (!mcacheSize) return; + + //@TODO just remove the 1st element + // not the best of LRU logic + if (mcacheSize == mHash.size()) mHash.erase(mHash.cbegin()); + mHash[key] = std::move(value); } + void configureCacheSize(size_t cacheSize) + { + std::lock_guard guard(mMutex); + mcacheSize = cacheSize; + + if (!mcacheSize) mHash.clear(); + } + private: - LottieFileCache() = default; + ModelCache() = default; - std::unordered_map> mHash; + std::unordered_map> mHash; + std::mutex mMutex; + size_t mcacheSize{10}; }; #else -class LottieFileCache { +class ModelCache { public: - static LottieFileCache &instance() + static ModelCache &instance() { - static LottieFileCache CACHE; - return CACHE; + static ModelCache singleton; + return singleton; } - std::shared_ptr find(const std::string &) { return nullptr; } - void add(const std::string &, std::shared_ptr) {} + std::shared_ptr find(const std::string &) + { + return nullptr; + } + void add(const std::string &, std::shared_ptr) {} + void configureCacheSize(size_t) {} }; #endif @@ -71,62 +101,69 @@ class LottieFileCache { static std::string dirname(const std::string &path) { const char *ptr = strrchr(path.c_str(), '/'); - int len = int(ptr + 1 - path.c_str()); // +1 to include '/' +#ifdef _WIN32 + if (ptr) ptr = strrchr(ptr + 1, '\\'); +#endif + int len = int(ptr + 1 - path.c_str()); // +1 to include '/' return std::string(path, 0, len); } -bool LottieLoader::load(const std::string &path, std::map *colorReplacement) +void model::configureModelCacheSize(size_t cacheSize) { - mModel = LottieFileCache::instance().find(path); - if (mModel) return true; + ModelCache::instance().configureCacheSize(cacheSize); +} + +std::shared_ptr model::loadFromFile(const std::string &path, + bool cachePolicy) +{ + if (cachePolicy) { + auto obj = ModelCache::instance().find(path); + if (obj) return obj; + } std::ifstream f; f.open(path); if (!f.is_open()) { vCritical << "failed to open file = " << path.c_str(); - return false; + return {}; } else { std::string content; - std::getline(f, content, '\0') ; + std::getline(f, content, '\0'); f.close(); - if (content.empty()) return false; + if (content.empty()) return {}; - const char *str = content.c_str(); - LottieParser parser(const_cast(str), dirname(path).c_str(), colorReplacement); - if (parser.hasParsingError()) { - return false; - } - mModel = parser.model(); + auto obj = internal::model::parse(const_cast(content.c_str()), + dirname(path)); - if (!mModel) return false; + if (obj && cachePolicy) ModelCache::instance().add(path, obj); - LottieFileCache::instance().add(path, mModel); + return obj; } - - return true; } -bool LottieLoader::loadFromData(std::string &&jsonData, const std::string &key, - std::map *colorReplacement, - const std::string &resourcePath) +std::shared_ptr model::loadFromData( + std::string jsonData, const std::string &key, std::string resourcePath, + bool cachePolicy) { - mModel = LottieFileCache::instance().find(key); - if (mModel) return true; - - LottieParser parser(const_cast(jsonData.c_str()), resourcePath.c_str(), colorReplacement); - mModel = parser.model(); + if (cachePolicy) { + auto obj = ModelCache::instance().find(key); + if (obj) return obj; + } - if (!mModel) return false; + auto obj = internal::model::parse(const_cast(jsonData.c_str()), + std::move(resourcePath)); - LottieFileCache::instance().add(key, mModel); + if (obj && cachePolicy) ModelCache::instance().add(key, obj); - return true; + return obj; } -std::shared_ptr LottieLoader::model() +std::shared_ptr model::loadFromData( + std::string jsonData, std::string resourcePath, model::ColorFilter filter) { - return mModel; + return internal::model::parse(const_cast(jsonData.c_str()), + std::move(resourcePath), std::move(filter)); } diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieloader.h b/AXrLottie/src/main/cpp/src/lottie/lottieloader.h deleted file mode 100755 index ffbbce3..0000000 --- a/AXrLottie/src/main/cpp/src/lottie/lottieloader.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOTTIELOADER_H -#define LOTTIELOADER_H - -#include -#include -#include - -class LOTModel; -class LottieLoader -{ -public: - bool load(const std::string &filePath, std::map *colorReplacement); - bool loadFromData(std::string &&jsonData, const std::string &key, std::map *colorReplacement, const std::string &resourcePath); - std::shared_ptr model(); -private: - std::shared_ptr mModel; -}; - -#endif // LOTTIELOADER_H - - diff --git a/AXrLottie/src/main/cpp/src/lottie/lottiemodel.cpp b/AXrLottie/src/main/cpp/src/lottie/lottiemodel.cpp index 65b1d73..b86e706 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottiemodel.cpp +++ b/AXrLottie/src/main/cpp/src/lottie/lottiemodel.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "lottiemodel.h" @@ -23,6 +27,8 @@ #include "vimageloader.h" #include "vline.h" +using namespace rlottie::internal; + /* * We process the iterator objects in the children list * by iterating from back to front. when we find a repeater object @@ -36,21 +42,22 @@ */ class LottieRepeaterProcesser { public: - void visitChildren(LOTGroupData *obj) + void visitChildren(model::Group *obj) { for (auto i = obj->mChildren.rbegin(); i != obj->mChildren.rend(); ++i) { - auto child = (*i).get(); - if (child->type() == LOTData::Type::Repeater) { - LOTRepeaterData *repeater = - static_cast(child); + auto child = (*i); + if (child->type() == model::Object::Type::Repeater) { + model::Repeater *repeater = + static_cast(child); // check if this repeater is already processed // can happen if the layer is an asset and referenced by // multiple layer. - if (repeater->content()) continue; + if (repeater->processed()) continue; + + repeater->markProcessed(); - repeater->setContent(std::make_shared()); - LOTShapeGroupData *content = repeater->content(); + auto content = repeater->content(); // 1. increment the reverse iterator to point to the // object before the repeater ++i; @@ -65,19 +72,17 @@ class LottieRepeaterProcesser { visitChildren(content); // 6. exit the loop as the current iterators are invalid break; - } else { - visit(child); } + visit(child); } } - void visit(LOTData *obj) + void visit(model::Object *obj) { switch (obj->type()) { - case LOTData::Type::Repeater: - case LOTData::Type::ShapeGroup: - case LOTData::Type::Layer: { - visitChildren(static_cast(obj)); + case model::Object::Type::Group: + case model::Object::Type::Layer: { + visitChildren(static_cast(obj)); break; } default: @@ -86,13 +91,74 @@ class LottieRepeaterProcesser { } }; -void LOTCompositionData::processRepeaterObjects() +class LottieUpdateStatVisitor { + model::Composition::Stats *stat; + +public: + explicit LottieUpdateStatVisitor(model::Composition::Stats *s) : stat(s) {} + void visitChildren(model::Group *obj) + { + for (const auto &child : obj->mChildren) { + if (child) visit(child); + } + } + void visitLayer(model::Layer *layer) + { + switch (layer->mLayerType) { + case model::Layer::Type::Precomp: + stat->precompLayerCount++; + break; + case model::Layer::Type::Null: + stat->nullLayerCount++; + break; + case model::Layer::Type::Shape: + stat->shapeLayerCount++; + break; + case model::Layer::Type::Solid: + stat->solidLayerCount++; + break; + case model::Layer::Type::Image: + stat->imageLayerCount++; + break; + default: + break; + } + visitChildren(layer); + } + void visit(model::Object *obj) + { + switch (obj->type()) { + case model::Object::Type::Layer: { + visitLayer(static_cast(obj)); + break; + } + case model::Object::Type::Repeater: { + visitChildren(static_cast(obj)->content()); + break; + } + case model::Object::Type::Group: { + visitChildren(static_cast(obj)); + break; + } + default: + break; + } + } +}; + +void model::Composition::processRepeaterObjects() { LottieRepeaterProcesser visitor; - visitor.visit(mRootLayer.get()); + visitor.visit(mRootLayer); } -VMatrix LOTRepeaterTransform::matrix(int frameNo, float multiplier) const +void model::Composition::updateStats() +{ + LottieUpdateStatVisitor visitor(&mStats); + visitor.visit(mRootLayer); +} + +VMatrix model::Repeater::Transform::matrix(int frameNo, float multiplier) const { VPointF scale = mScale.value(frameNo) / 100.f; scale.setX(std::pow(scale.x(), multiplier)); @@ -107,23 +173,23 @@ VMatrix LOTRepeaterTransform::matrix(int frameNo, float multiplier) const return m; } -VMatrix TransformData::matrix(int frameNo, bool autoOrient) const +VMatrix model::Transform::Data::matrix(int frameNo, bool autoOrient) const { VMatrix m; VPointF position; - if (mSeparate) { - position.setX(mX.value(frameNo)); - position.setY(mY.value(frameNo)); + if (mExtra && mExtra->mSeparate) { + position.setX(mExtra->mSeparateX.value(frameNo)); + position.setY(mExtra->mSeparateY.value(frameNo)); } else { position = mPosition.value(frameNo); } float angle = autoOrient ? mPosition.angle(frameNo) : 0; - if (m3D) { + if (mExtra && mExtra->m3DData) { m.translate(position) - .rotate(m3D->mRz.value(frameNo) + angle) - .rotate(m3D->mRy.value(frameNo), VMatrix::Axis::Y) - .rotate(m3D->mRx.value(frameNo), VMatrix::Axis::X) + .rotate(mExtra->m3DRz.value(frameNo) + angle) + .rotate(mExtra->m3DRy.value(frameNo), VMatrix::Axis::Y) + .rotate(mExtra->m3DRx.value(frameNo), VMatrix::Axis::X) .scale(mScale.value(frameNo) / 100.f) .translate(-mAnchor.value(frameNo)); } else { @@ -135,43 +201,26 @@ VMatrix TransformData::matrix(int frameNo, bool autoOrient) const return m; } -int LOTStrokeData::getDashInfo(int frameNo, float *array) const +void model::Dash::getDashInfo(int frameNo, std::vector &result) const { - if (!mDash.mDashCount) return 0; - // odd case - if (mDash.mDashCount % 2) { - for (int i = 0; i < mDash.mDashCount; i++) { - array[i] = mDash.mDashArray[i].value(frameNo); - } - return mDash.mDashCount; - } else { // even case when last gap info is not provided. - int i; - for (i = 0; i < mDash.mDashCount - 1; i++) { - array[i] = mDash.mDashArray[i].value(frameNo); - } - array[i] = array[i - 1]; - array[i + 1] = mDash.mDashArray[i].value(frameNo); - return mDash.mDashCount + 1; - } -} + result.clear(); -int LOTGStrokeData::getDashInfo(int frameNo, float *array) const -{ - if (!mDash.mDashCount) return 0; - // odd case - if (mDash.mDashCount % 2) { - for (int i = 0; i < mDash.mDashCount; i++) { - array[i] = mDash.mDashArray[i].value(frameNo); - } - return mDash.mDashCount; - } else { // even case when last gap info is not provided. - int i; - for (i = 0; i < mDash.mDashCount - 1; i++) { - array[i] = mDash.mDashArray[i].value(frameNo); - } - array[i] = array[i - 1]; - array[i + 1] = mDash.mDashArray[i].value(frameNo); - return mDash.mDashCount + 1; + if (mData.empty()) return; + + if (result.capacity() < mData.size()) result.reserve(mData.size() + 1); + + for (const auto &elm : mData) result.push_back(elm.value(frameNo)); + + // if the size is even then we are missing last + // gap information which is same as the last dash value + // copy it from the last dash value. + // NOTE: last value is the offset and last-1 is the last dash value. + auto size = result.size(); + if ((size % 2) == 0) { + // copy offset value to end. + result.push_back(result.back()); + // copy dash value to gap. + result[size - 1] = result[size - 2]; } } @@ -195,25 +244,22 @@ int LOTGStrokeData::getDashInfo(int frameNo, float *array) const * ... * ] */ -void LOTGradient::populate(VGradientStops &stops, int frameNo) +void model::Gradient::populate(VGradientStops &stops, int frameNo) { - LottieGradient gradData = mGradient.value(frameNo); - int size = gradData.mGradient.size(); - float * ptr = gradData.mGradient.data(); - int colorPoints = mColorPoints; - if (colorPoints < 0 || colorPoints * 4 > size) { // for legacy bodymovin (ref: lottie-android) - colorPoints = size / 4; - } - int opacityArraySize = size - colorPoints * 4; - if (opacityArraySize % 2 != 0 || colorPoints > opacityArraySize / 2 && opacityArraySize < 4) { - opacityArraySize = 0; + model::Gradient::Data gradData = mGradient.value(frameNo); + auto size = gradData.mGradient.size(); + float * ptr = gradData.mGradient.data(); + int colorPoints = mColorPoints; + if (colorPoints == -1) { // for legacy bodymovin (ref: lottie-android) + colorPoints = int(size / 4); } + auto opacityArraySize = size - colorPoints * 4; float *opacityPtr = ptr + (colorPoints * 4); stops.clear(); - int j = 0; + size_t j = 0; for (int i = 0; i < colorPoints; i++) { - float colorStop = ptr[0]; - LottieColor color = LottieColor(ptr[3], ptr[2], ptr[1], nullptr); + float colorStop = ptr[0]; + model::Color color = model::Color(ptr[1], ptr[2], ptr[3]); if (opacityArraySize) { if (j == opacityArraySize) { // already reached the end @@ -260,20 +306,17 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) stops.push_back(std::make_pair(colorStop, color.toColor())); } ptr += 4; - if (stops.empty()) { - stops.push_back(std::make_pair(0.0f, VColor(255, 255, 255, 255))); - } } } -void LOTGradient::update(std::unique_ptr &grad, int frameNo) +void model::Gradient::update(std::unique_ptr &grad, int frameNo) { bool init = false; if (!grad) { if (mGradientType == 1) - grad = std::make_unique(0, 0, 0, 0); + grad = std::make_unique(VGradient::Type::Linear); else - grad = std::make_unique(0, 0, 0, 0, 0, 0); + grad = std::make_unique(VGradient::Type::Radial); grad->mSpread = VGradient::Spread::Pad; init = true; } @@ -306,9 +349,10 @@ void LOTGradient::update(std::unique_ptr &grad, int frameNo) */ float progress = mHighlightLength.value(frameNo) / 100.0f; if (vCompare(progress, 1.0f)) progress = 0.99f; - float startAngle = VLine(start, end).angle(); - float highlightAngle = mHighlightAngle.value(frameNo); - float angle = ((startAngle + highlightAngle) * M_PI) / 180.0f; + float startAngle = VLine(start, end).angle(); + float highlightAngle = mHighlightAngle.value(frameNo); + static constexpr float K_PI = 3.1415926f; + float angle = (startAngle + highlightAngle) * (K_PI / 180.0f); grad->radial.fx = grad->radial.cx + std::cos(angle) * progress * grad->radial.cradius; grad->radial.fy = @@ -318,13 +362,30 @@ void LOTGradient::update(std::unique_ptr &grad, int frameNo) } } -void LOTAsset::loadImageData(std::string data) +void model::Asset::loadImageData(std::string data) { if (!data.empty()) mBitmap = VImageLoader::instance().load(data.c_str(), data.length()); } -void LOTAsset::loadImagePath(std::string path) +void model::Asset::loadImagePath(std::string path) { if (!path.empty()) mBitmap = VImageLoader::instance().load(path.c_str()); } + +std::vector model::Composition::layerInfoList() const +{ + if (!mRootLayer || mRootLayer->mChildren.empty()) return {}; + + std::vector result; + + result.reserve(mRootLayer->mChildren.size()); + + for (auto it : mRootLayer->mChildren) { + auto layer = static_cast(it); + result.emplace_back(layer->name(), layer->mInFrame, layer->mOutFrame, static_cast::type>(layer->mLayerType) ); + } + + return result; +} + diff --git a/AXrLottie/src/main/cpp/src/lottie/lottiemodel.h b/AXrLottie/src/main/cpp/src/lottie/lottiemodel.h index 9111dd3..bf26598 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottiemodel.h +++ b/AXrLottie/src/main/cpp/src/lottie/lottiemodel.h @@ -1,402 +1,435 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef LOTModel_H #define LOTModel_H -#include -#include -#include -#include #include -#include"vpoint.h" -#include"vrect.h" -#include"vinterpolator.h" -#include"vmatrix.h" -#include"vbezier.h" -#include"vbrush.h" -#include"vpath.h" +#include +#include +#include +#include +#include +#include +#include "varenaalloc.h" +#include "vbezier.h" +#include "vbrush.h" +#include "vinterpolator.h" +#include "vmatrix.h" +#include "vpath.h" +#include "vpoint.h" +#include "vrect.h" V_USE_NAMESPACE -class LOTCompositionData; -class LOTLayerData; -class LOTTransformData; -class LOTShapeGroupData; -class LOTShapeData; -class LOTRectData; -class LOTEllipseData; -class LOTTrimData; -class LOTRepeaterData; -class LOTFillData; -class LOTStrokeData; -class LOTGroupData; -class LOTGFillData; -class LOTGStrokeData; -class LottieShapeData; -class LOTPolystarData; -class LOTMaskData; - -enum class MatteType: uchar -{ - None = 0, - Alpha = 1, - AlphaInv, - Luma, - LumaInv -}; +namespace rlottie { + +namespace internal { -enum class LayerType: uchar +using Marker = std::tuple; + +using LayerInfo = std::tuple; + +template +inline T lerp(const T &start, const T &end, float t) { - Precomp = 0, - Solid = 1, - Image = 2, - Null = 3, - Shape = 4, - Text = 5 + return start + t * (end - start); +} + +namespace model { + +enum class MatteType : uchar { None = 0, Alpha = 1, AlphaInv, Luma, LumaInv }; + +enum class BlendMode : uchar { + Normal = 0, + Multiply = 1, + Screen = 2, + OverLay = 3 }; -class LottieColor -{ +class Color { public: - LottieColor() = default; - LottieColor(float red, float green, float blue, std::map *colorReplacement) { - r = red; - g = green; - b = blue; - colorMap = colorReplacement; - }; - VColor toColor(float a=1) { - float r1, g1, b1; - getColorReplacement(colorMap, *this, r1, g1, b1); - return VColor((255 * r1), (255 * g1), (255 * b1), (255 * a)); - }; - friend inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2); - friend inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2); - friend inline void getColorReplacement(std::map *colorMap, const LottieColor &c, float &r, float &g, float &b); + Color() = default; + Color(float red, float green, float blue) : r(red), g(green), b(blue) {} + VColor toColor(float a = 1) + { + return VColor(uchar(255 * r), uchar(255 * g), uchar(255 * b), + uchar(255 * a)); + } + friend inline Color operator+(const Color &c1, const Color &c2); + friend inline Color operator-(const Color &c1, const Color &c2); + public: - std::map *colorMap{nullptr}; float r{1}; float g{1}; float b{1}; }; -inline void getColorReplacement(std::map *colorMap, const LottieColor &c, float &r, float &g, float &b) { - if (colorMap != nullptr && !colorMap->empty()) { - int32_t rr = (int32_t) (c.r * 255); - int32_t gg = (int32_t) (c.g * 255); - int32_t bb = (int32_t) (c.b * 255); - int32_t cc = (int32_t) (((bb & 0xff) << 16) | ((gg & 0xff) << 8) | (rr & 0xff)); - std::map::iterator iter = colorMap->find(cc); - if (iter != colorMap->end()) { - cc = iter->second; - r = ((cc) & 0xff) / 255.0f; - g = ((cc >> 8) & 0xff) / 255.0f; - b = ((cc >> 16) & 0xff) / 255.0f; - return; - } - } - r = c.r; - g = c.g; - b = c.b; -} - -inline LottieColor operator-(const LottieColor &c1, const LottieColor &c2) +inline Color operator-(const Color &c1, const Color &c2) { - float r1, g1, b1; - float r2, g2, b2; - getColorReplacement(c1.colorMap, c1, r1, g1, b1); - getColorReplacement(c2.colorMap, c2, r2, g2, b2); - return LottieColor(r1 - r2, g1 - g2, b1 - b2, nullptr); + return Color(c1.r - c2.r, c1.g - c2.g, c1.b - c2.b); } -inline LottieColor operator+(const LottieColor &c1, const LottieColor &c2) +inline Color operator+(const Color &c1, const Color &c2) { - float r1, g1, b1; - float r2, g2, b2; - getColorReplacement(c1.colorMap, c1, r1, g1, b1); - getColorReplacement(c2.colorMap, c2, r2, g2, b2); - return LottieColor(r1 + r2, g1 + g2, b1 + b2, nullptr); + return Color(c1.r + c2.r, c1.g + c2.g, c1.b + c2.b); } -inline const LottieColor operator*(const LottieColor &c, float m) +inline const Color operator*(const Color &c, float m) { - float r1, g1, b1; - getColorReplacement(c.colorMap, c, r1, g1, b1); - return LottieColor(r1 * m, g1 * m, b1 * m, nullptr); + return Color(c.r * m, c.g * m, c.b * m); } -inline const LottieColor operator*(float m, const LottieColor &c) +inline const Color operator*(float m, const Color &c) { - float r1, g1, b1; - getColorReplacement(c.colorMap, c, r1, g1, b1); - return LottieColor(r1 * m, g1 * m, b1 * m, nullptr); + return Color(c.r * m, c.g * m, c.b * m); } -class LottieShapeData -{ -public: - void reserve(int size) { - mPoints.reserve(mPoints.size() + size); +struct PathData { + std::vector mPoints; + bool mClosed = false; /* "c" */ + void reserve(size_t size) { mPoints.reserve(mPoints.size() + size); } + static void lerp(const PathData &start, const PathData &end, float t, + VPath &result) + { + result.reset(); + auto size = std::min(start.mPoints.size(), end.mPoints.size()); + /* reserve exact memory requirement at once + * ptSize = size + 1(size + close) + * elmSize = size/3 cubic + 1 move + 1 close + */ + result.reserve(size + 1, size / 3 + 2); + result.moveTo(start.mPoints[0] + + t * (end.mPoints[0] - start.mPoints[0])); + for (size_t i = 1; i < size; i += 3) { + result.cubicTo( + start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i]), + start.mPoints[i + 1] + + t * (end.mPoints[i + 1] - start.mPoints[i + 1]), + start.mPoints[i + 2] + + t * (end.mPoints[i + 2] - start.mPoints[i + 2])); + } + if (start.mClosed) result.close(); } - void toPath(VPath& path) { + void toPath(VPath &path) const + { path.reset(); if (mPoints.empty()) return; - int size = mPoints.size(); - const VPointF *points = mPoints.data(); + auto size = mPoints.size(); + auto points = mPoints.data(); /* reserve exact memory requirement at once * ptSize = size + 1(size + close) * elmSize = size/3 cubic + 1 move + 1 close */ - path.reserve(size + 1 , size/3 + 2); + path.reserve(size + 1, size / 3 + 2); path.moveTo(points[0]); - for (int i = 1 ; i < size; i+=3) { - path.cubicTo(points[i], points[i+1], points[i+2]); + for (size_t i = 1; i < size; i += 3) { + path.cubicTo(points[i], points[i + 1], points[i + 2]); } - if (mClosed) - path.close(); + if (mClosed) path.close(); } -public: - std::vector mPoints; - bool mClosed = false; /* "c" */ }; +template +struct Value { + T start_; + T end_; + T at(float t) const { return lerp(start_, end_, t); } + float angle(float) const { return 0; } + void cache() {} +}; - -template -inline T lerp(const T& start, const T& end, float t) -{ - return start + t * (end - start); -} - -inline LottieShapeData lerp(const LottieShapeData& start, const LottieShapeData& end, float t) -{ - // Usal case both start and end path has same size - // In case its different then truncate the larger path and do the interpolation. - LottieShapeData result; - auto size = std::min(start.mPoints.size(), end.mPoints.size()); - result.reserve(size); - for (unsigned int i = 0 ; i < size; i++) { - result.mPoints.push_back(start.mPoints[i] + t * (end.mPoints[i] - start.mPoints[i])); - } - return result; -} +struct Position; template -struct LOTKeyFrameValue -{ - T mStartValue; - T mEndValue; - T value(float t) const { - return lerp(mStartValue, mEndValue, t); +struct Value { + T start_; + T end_; + T inTangent_; + T outTangent_; + float length_{0}; + bool hasTangent_{false}; + + void cache() + { + if (hasTangent_) { + inTangent_ = end_ + inTangent_; + outTangent_ = start_ + outTangent_; + length_ = VBezier::fromPoints(start_, outTangent_, inTangent_, end_) + .length(); + if (vIsZero(length_)) { + // this segment has zero length. + // so disable expensive path computaion. + hasTangent_ = false; + } + } } - float angle(float ) const { return 0;} -}; -template <> -struct LOTKeyFrameValue -{ - VPointF mStartValue; - VPointF mEndValue; - VPointF mInTangent; - VPointF mOutTangent; - bool mPathKeyFrame = false; - - VPointF value(float t) const { - if (mPathKeyFrame) { + T at(float t) const + { + if (hasTangent_) { /* * position along the path calcualated * using bezier at progress length (t * bezlen) */ - VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, - mEndValue + mInTangent, mEndValue); - return b.pointAt(b.tAtLength(t * b.length())); - - } else { - return lerp(mStartValue, mEndValue, t); + VBezier b = + VBezier::fromPoints(start_, outTangent_, inTangent_, end_); + return b.pointAt(b.tAtLength(t * length_, length_)); } + return lerp(start_, end_, t); } - float angle(float t) const { - if (mPathKeyFrame) { - VBezier b = VBezier::fromPoints(mStartValue, mStartValue + mOutTangent, - mEndValue + mInTangent, mEndValue); - return b.angleAt(b.tAtLength(t * b.length())); + float angle(float t) const + { + if (hasTangent_) { + VBezier b = + VBezier::fromPoints(start_, outTangent_, inTangent_, end_); + return b.angleAt(b.tAtLength(t * length_, length_)); } return 0; } }; - -template -class LOTKeyFrame -{ +template +class KeyFrames { public: - float progress(int frameNo) const { - return mInterpolator ? mInterpolator->value((frameNo - mStartFrame) / (mEndFrame - mStartFrame)) : 0; - } - T value(int frameNo) const { - return mValue.value(progress(frameNo)); - } - float angle(int frameNo) const { - return mValue.angle(progress(frameNo)); - } + struct Frame { + float progress(int frameNo) const + { + return interpolator_ ? interpolator_->value((frameNo - start_) / + (end_ - start_)) + : 0; + } + T value(int frameNo) const { return value_.at(progress(frameNo)); } + float angle(int frameNo) const + { + return value_.angle(progress(frameNo)); + } -public: - float mStartFrame{0}; - float mEndFrame{0}; - std::shared_ptr mInterpolator; - LOTKeyFrameValue mValue; -}; + float start_{0}; + float end_{0}; + VInterpolator *interpolator_{nullptr}; + Value value_; + }; -template -class LOTAnimInfo -{ -public: - T value(int frameNo) const { - if (mKeyFrames.front().mStartFrame >= frameNo) - return mKeyFrames.front().mValue.mStartValue; - if(mKeyFrames.back().mEndFrame <= frameNo) - return mKeyFrames.back().mValue.mEndValue; - - for(const auto &keyFrame : mKeyFrames) { - if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) + T value(int frameNo) const + { + if (frames_.front().start_ >= frameNo) + return frames_.front().value_.start_; + if (frames_.back().end_ <= frameNo) return frames_.back().value_.end_; + + for (const auto &keyFrame : frames_) { + if (frameNo >= keyFrame.start_ && frameNo < keyFrame.end_) return keyFrame.value(frameNo); } - return T(); + return {}; } - float angle(int frameNo) const { - if ((mKeyFrames.front().mStartFrame >= frameNo) || - (mKeyFrames.back().mEndFrame <= frameNo) ) + float angle(int frameNo) const + { + if ((frames_.front().start_ >= frameNo) || + (frames_.back().end_ <= frameNo)) return 0; - for(const auto &keyFrame : mKeyFrames) { - if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) - return keyFrame.angle(frameNo); + for (const auto &frame : frames_) { + if (frameNo >= frame.start_ && frameNo < frame.end_) + return frame.angle(frameNo); } return 0; } - bool changed(int prevFrame, int curFrame) const { - int first = mKeyFrames.front().mStartFrame; - int last = mKeyFrames.back().mEndFrame; - - if ((first > prevFrame && first > curFrame) || - (last < prevFrame && last < curFrame)) { - return false; - } + bool changed(int prevFrame, int curFrame) const + { + auto first = frames_.front().start_; + auto last = frames_.back().end_; - return true; + return !((first > prevFrame && first > curFrame) || + (last < prevFrame && last < curFrame)); + } + void cache() + { + for (auto &e : frames_) e.value_.cache(); } public: - std::vector> mKeyFrames; + std::vector frames_; }; -template -class LOTAnimatable -{ +template +class Property { public: - LOTAnimatable() { construct(impl.mValue, {}); } - explicit LOTAnimatable(T value) { construct(impl.mValue, std::move(value)); } + using Animation = KeyFrames; - const LOTAnimInfo& animation() const {return *(impl.mAnimInfo.get());} - const T& value() const {return impl.mValue;} + Property() { construct(impl_.value_, {}); } + explicit Property(T value) { construct(impl_.value_, std::move(value)); } - LOTAnimInfo& animation() + const Animation &animation() const { return *(impl_.animation_.get()); } + const T & value() const { return impl_.value_; } + + Animation &animation() { - if (mStatic) { + if (isValue_) { destroy(); - construct(impl.mAnimInfo, std::make_unique>()); - mStatic = false; + construct(impl_.animation_, std::make_unique()); + isValue_ = false; } - return *(impl.mAnimInfo.get()); + return *(impl_.animation_.get()); } - T& value() + T &value() { - assert(mStatic); - return impl.mValue; + assert(isValue_); + return impl_.value_; } + Property(Property &&other) noexcept + { + if (!other.isValue_) { + construct(impl_.animation_, std::move(other.impl_.animation_)); + isValue_ = false; + } else { + construct(impl_.value_, std::move(other.impl_.value_)); + isValue_ = true; + } + } // delete special member functions - LOTAnimatable(const LOTAnimatable &) = delete; - LOTAnimatable(LOTAnimatable &&) = delete; - LOTAnimatable& operator=(const LOTAnimatable&) = delete; - LOTAnimatable& operator=(LOTAnimatable&&) = delete; + Property(const Property &) = delete; + Property &operator=(const Property &) = delete; + Property &operator=(Property &&) = delete; - ~LOTAnimatable() {destroy();} + ~Property() { destroy(); } - bool isStatic() const {return mStatic;} + bool isStatic() const { return isValue_; } - T value(int frameNo) const { + T value(int frameNo) const + { return isStatic() ? value() : animation().value(frameNo); } - float angle(int frameNo) const { + // special function only for type T=PathData + template + auto value(int frameNo, VPath &path) const -> + typename std::enable_if_t::value, void> + { + if (isStatic()) { + value().toPath(path); + } else { + const auto &vec = animation().frames_; + if (vec.front().start_ >= frameNo) + return vec.front().value_.start_.toPath(path); + if (vec.back().end_ <= frameNo) + return vec.back().value_.end_.toPath(path); + + for (const auto &keyFrame : vec) { + if (frameNo >= keyFrame.start_ && frameNo < keyFrame.end_) { + T::lerp(keyFrame.value_.start_, keyFrame.value_.end_, + keyFrame.progress(frameNo), path); + } + } + } + } + + float angle(int frameNo) const + { return isStatic() ? 0 : animation().angle(frameNo); } - bool changed(int prevFrame, int curFrame) const { + bool changed(int prevFrame, int curFrame) const + { return isStatic() ? false : animation().changed(prevFrame, curFrame); } + void cache() + { + if (!isStatic()) animation().cache(); + } + private: template - void construct(Tp& member, Tp&& val) + void construct(Tp &member, Tp &&val) { new (&member) Tp(std::move(val)); } - void destroy() { - if (mStatic) { - impl.mValue.~T(); + void destroy() + { + if (isValue_) { + impl_.value_.~T(); } else { using std::unique_ptr; - impl.mAnimInfo.~unique_ptr>(); + impl_.animation_.~unique_ptr(); } } union details { - std::unique_ptr> mAnimInfo; - T mValue; - details(){} - ~details(){} - }impl; - bool mStatic{true}; + std::unique_ptr animation_; + T value_; + details(){}; + details(const details &) = delete; + details(details &&) = delete; + details &operator=(details &&) = delete; + details &operator=(const details &) = delete; + ~details() noexcept {}; + } impl_; + bool isValue_{true}; }; -enum class LottieBlendMode: uchar -{ - Normal = 0, - Multiply = 1, - Screen = 2, - OverLay = 3 +class Path; +struct PathData; +struct Dash { + std::vector> mData; + bool empty() const { return mData.empty(); } + size_t size() const { return mData.size(); } + bool isStatic() const + { + for (const auto &elm : mData) + if (!elm.isStatic()) return false; + return true; + } + void getDashInfo(int frameNo, std::vector &result) const; }; -class LOTDataVisitor; -class LOTData -{ +class Mask { +public: + enum class Mode { None, Add, Substarct, Intersect, Difference }; + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + bool isStatic() const { return mIsStatic; } + +public: + Property mShape; + Property mOpacity{100}; + bool mInv{false}; + bool mIsStatic{true}; + Mask::Mode mMode; +}; + +class Object { public: - enum class Type :short { + enum class Type : unsigned char { Composition = 1, Layer, - ShapeGroup, + Group, Transform, Fill, Stroke, @@ -404,99 +437,175 @@ class LOTData GStroke, Rect, Ellipse, - Shape, + Path, Polystar, Trim, - Repeater + Repeater, + RoundedCorner }; - explicit LOTData(LOTData::Type type): mType(type){} - inline LOTData::Type type() const {return mType;} - bool isStatic() const{return mStatic;} - void setStatic(bool value) {mStatic = value;} - bool hidden() const {return mHidden;} - void setHidden(bool value) {mHidden = value;} - void setName(const char *str) {mName = str;} - const std::string& name() const{ return mName;} + + explicit Object(Object::Type type) : mPtr(nullptr) + { + mData._type = type; + mData._static = true; + mData._shortString = true; + mData._hidden = false; + } + ~Object() noexcept + { + if (!shortString() && mPtr) free(mPtr); + } + Object(const Object &) = delete; + Object &operator=(const Object &) = delete; + + void setStatic(bool value) { mData._static = value; } + bool isStatic() const { return mData._static; } + bool hidden() const { return mData._hidden; } + void setHidden(bool value) { mData._hidden = value; } + void setType(Object::Type type) { mData._type = type; } + Object::Type type() const { return mData._type; } + void setName(const char *name) + { + if (name) { + auto len = strlen(name); + if (len < maxShortStringLength) { + setShortString(true); + strncpy(mData._buffer, name, len + 1); + } else { + setShortString(false); + mPtr = strdup(name); + } + } + } + const char *name() const { return shortString() ? mData._buffer : mPtr; } + private: - std::string mName; - bool mStatic{true}; - bool mHidden{false}; - LOTData::Type mType; + static constexpr unsigned char maxShortStringLength = 14; + void setShortString(bool value) { mData._shortString = value; } + bool shortString() const { return mData._shortString; } + struct Data { + char _buffer[maxShortStringLength]; + Object::Type _type; + bool _static : 1; + bool _hidden : 1; + bool _shortString : 1; + }; + union { + Data mData; + char *mPtr{nullptr}; + }; }; -class LOTGroupData: public LOTData -{ -public: - explicit LOTGroupData(LOTData::Type type):LOTData(type){} -public: - std::vector> mChildren; - std::shared_ptr mTransform; +struct Asset { + enum class Type : unsigned char { Precomp, Image, Char }; + bool isStatic() const { return mStatic; } + void setStatic(bool value) { mStatic = value; } + VBitmap bitmap() const { return mBitmap; } + void loadImageData(std::string data); + void loadImagePath(std::string Path); + Type mAssetType{Type::Precomp}; + bool mStatic{true}; + std::string mRefId; // ref id + std::vector mLayers; + // image asset data + int mWidth{0}; + int mHeight{0}; + VBitmap mBitmap; }; -class LOTShapeGroupData : public LOTGroupData -{ +class Layer; + +class Composition : public Object { public: - LOTShapeGroupData():LOTGroupData(LOTData::Type::ShapeGroup){} -}; + Composition() : Object(Object::Type::Composition) {} + std::vector layerInfoList() const; + model::Layer* layerInfo(const char * name) const; + const std::vector &markers() const { return mMarkers; } + double duration() const + { + return frameDuration() / frameRate(); // in second + } + size_t frameAtPos(double pos) const + { + if (pos < 0) pos = 0; + if (pos > 1) pos = 1; + return size_t(round(pos * frameDuration())); + } + long frameAtTime(double timeInSec) const + { + return long(frameAtPos(timeInSec / duration())); + } + size_t totalFrame() const { return mEndFrame - mStartFrame; } + long frameDuration() const { return mEndFrame - mStartFrame - 1; } + float frameRate() const { return mFrameRate; } + size_t startFrame() const { return mStartFrame; } + size_t endFrame() const { return mEndFrame; } + VSize size() const { return mSize; } + void processRepeaterObjects(); + void updateStats(); -class LOTLayerData; -struct LOTAsset -{ - enum class Type : unsigned char{ - Precomp, - Image, - Char +public: + struct Stats { + uint16_t precompLayerCount{0}; + uint16_t solidLayerCount{0}; + uint16_t shapeLayerCount{0}; + uint16_t imageLayerCount{0}; + uint16_t nullLayerCount{0}; }; - bool isStatic() const {return mStatic;} - void setStatic(bool value) {mStatic = value;} - VBitmap bitmap() const {return mBitmap;} - void loadImageData(std::string data); - void loadImagePath(std::string Path); - Type mAssetType{Type::Precomp}; - bool mStatic{true}; - std::string mRefId; // ref id - std::vector> mLayers; - // image asset data - int mWidth{0}; - int mHeight{0}; - VBitmap mBitmap; -}; - -struct LOT3DData -{ - LOTAnimatable mRx{0}; - LOTAnimatable mRy{0}; - LOTAnimatable mRz{0}; -}; -struct TransformData -{ - VMatrix matrix(int frameNo, bool autoOrient = false) const; - float opacity(int frameNo) const { return mOpacity.value(frameNo)/100.0f; } - bool isStatic() const { return mStatic;} - std::unique_ptr m3D; - LOTAnimatable mRotation{0}; /* "r" */ - LOTAnimatable mScale{{100, 100}}; /* "s" */ - LOTAnimatable mPosition; /* "p" */ - LOTAnimatable mX{0}; - LOTAnimatable mY{0}; - LOTAnimatable mAnchor; /* "a" */ - LOTAnimatable mOpacity{100}; /* "o" */ - bool mSeparate{false}; - bool mStatic{false}; +public: + std::string mVersion; + VSize mSize; + long mStartFrame{0}; + long mEndFrame{0}; + float mFrameRate{60}; + BlendMode mBlendMode{BlendMode::Normal}; + Layer * mRootLayer{nullptr}; + std::unordered_map mAssets; + + std::vector mMarkers; + VArenaAlloc mArenaAlloc{2048}; + Stats mStats; }; -class LOTTransformData : public LOTData -{ +class Transform : public Object { public: - LOTTransformData():LOTData(LOTData::Type::Transform){} - void set(std::unique_ptr data) + struct Data { + struct Extra { + Property m3DRx{0}; + Property m3DRy{0}; + Property m3DRz{0}; + Property mSeparateX{0}; + Property mSeparateY{0}; + bool mSeparate{false}; + bool m3DData{false}; + }; + VMatrix matrix(int frameNo, bool autoOrient = false) const; + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + void createExtraData() + { + if (!mExtra) mExtra = std::make_unique(); + } + Property mRotation{0}; /* "r" */ + Property mScale{{100, 100}}; /* "s" */ + Property mPosition; /* "p" */ + Property mAnchor; /* "a" */ + Property mOpacity{100}; /* "o" */ + std::unique_ptr mExtra; + }; + + Transform() : Object(Object::Type::Transform) {} + void set(Transform::Data *data, bool staticFlag) { - setStatic(data->isStatic()); + setStatic(staticFlag); if (isStatic()) { - new (&impl.mStaticData) static_data(data->matrix(0), data->opacity(0)); + new (&impl.mStaticData) + StaticData(data->matrix(0), data->opacity(0)); } else { - new (&impl.mData) std::unique_ptr(std::move(data)); + impl.mData = data; } } VMatrix matrix(int frameNo, bool autoOrient = false) const @@ -509,146 +618,136 @@ class LOTTransformData : public LOTData if (isStatic()) return impl.mStaticData.mOpacity; return impl.mData->opacity(frameNo); } - - LOTTransformData& operator=(LOTTransformData&&) = delete; - ~LOTTransformData() {destroy();} + Transform(const Transform &) = delete; + Transform(Transform &&) = delete; + Transform &operator=(Transform &) = delete; + Transform &operator=(Transform &&) = delete; + ~Transform() noexcept { destroy(); } private: - void destroy() { + void destroy() + { if (isStatic()) { - impl.mStaticData.~static_data(); - } else { - using std::unique_ptr; - impl.mData.~unique_ptr(); + impl.mStaticData.~StaticData(); } } - struct static_data { - static_data(VMatrix &&m, float opacity): - mOpacity(opacity), mMatrix(std::move(m)){} - float mOpacity; - VMatrix mMatrix; + struct StaticData { + StaticData(VMatrix &&m, float opacity) + : mOpacity(opacity), mMatrix(std::move(m)) + { + } + float mOpacity; + VMatrix mMatrix; }; union details { - std::unique_ptr mData; - static_data mStaticData; - details(){} - ~details(){} - }impl; + Data * mData{nullptr}; + StaticData mStaticData; + details(){}; + details(const details &) = delete; + details(details &&) = delete; + details &operator=(details &&) = delete; + details &operator=(const details &) = delete; + ~details() noexcept {}; + } impl; }; -struct ExtraLayerData -{ - LottieColor mSolidColor; - std::string mPreCompRefId; - LOTAnimatable mTimeRemap; /* "tm" */ - LOTCompositionData *mCompRef{nullptr}; - std::shared_ptr mAsset; - std::vector> mMasks; -}; +class Group : public Object { + public: + Group() : Object(Object::Type::Group) {} + explicit Group(Object::Type type) : Object(type) {} -class LOTLayerData : public LOTGroupData -{ -public: - LOTLayerData():LOTGroupData(LOTData::Type::Layer){} - bool hasPathOperator() const noexcept {return mHasPathOperator;} - bool hasGradient() const noexcept {return mHasGradient;} - bool hasMask() const noexcept {return mHasMask;} - bool hasRepeater() const noexcept {return mHasRepeater;} - int id() const noexcept{ return mId;} - int parentId() const noexcept{ return mParentId;} - bool hasParent() const noexcept {return mParentId != -1;} - int inFrame() const noexcept{return mInFrame;} - int outFrame() const noexcept{return mOutFrame;} - int startFrame() const noexcept{return mStartFrame;} - LottieColor solidColor() const noexcept{return mExtra->mSolidColor;} - bool autoOrient() const noexcept{return mAutoOrient;} - int timeRemap(int frameNo) const; - VSize layerSize() const {return mLayerSize;} - bool precompLayer() const {return mLayerType == LayerType::Precomp;} - VMatrix matrix(int frameNo) const - { - return mTransform ? mTransform->matrix(frameNo, autoOrient()) : VMatrix{}; - } - float opacity(int frameNo) const - { - return mTransform ? mTransform->opacity(frameNo) : 1.0f; - } - LOTAsset* asset() const - { - return (mExtra && mExtra->mAsset) ? mExtra->mAsset.get() : nullptr; - } -public: - ExtraLayerData* extra() - { - if (!mExtra) mExtra = std::make_unique(); - return mExtra.get(); - } - MatteType mMatteType{MatteType::None}; - LayerType mLayerType{LayerType::Null}; - LottieBlendMode mBlendMode{LottieBlendMode::Normal}; - bool mHasPathOperator{false}; - bool mHasMask{false}; - bool mHasRepeater{false}; - bool mHasGradient{false}; - bool mAutoOrient{false}; - VSize mLayerSize; - int mParentId{-1}; // Lottie the id of the parent in the composition - int mId{-1}; // Lottie the group id used for parenting. - float mTimeStreatch{1.0f}; - int mInFrame{0}; - int mOutFrame{0}; - int mStartFrame{0}; - std::unique_ptr mExtra{nullptr}; + public: + std::vector mChildren; + Transform * mTransform{nullptr}; }; -using LayerInfo = std::tuple; - -class LOTCompositionData : public LOTData -{ -public: - LOTCompositionData():LOTData(LOTData::Type::Composition){} - const std::vector &layerInfoList() const { return mLayerInfoList;} - double duration() const { - return frameDuration() / frameRate(); // in second - } - size_t frameAtPos(double pos) const { - if (pos < 0) pos = 0; - if (pos > 1) pos = 1; - return pos * frameDuration(); - } - long frameAtTime(double timeInSec) const { - return frameAtPos(timeInSec / duration()); - } - size_t totalFrame() const {return mEndFrame - mStartFrame;} - long frameDuration() const {return mEndFrame - mStartFrame -1;} - float frameRate() const {return mFrameRate;} - long startFrame() const {return mStartFrame;} - long endFrame() const {return mEndFrame;} - VSize size() const {return mSize;} - void processRepeaterObjects(); -public: - std::string mVersion; - VSize mSize; - long mStartFrame{0}; - long mEndFrame{0}; - float mFrameRate{60}; - LottieBlendMode mBlendMode{LottieBlendMode::Normal}; - std::shared_ptr mRootLayer; - std::unordered_map> mAssets; - - std::vector mLayerInfoList; +class Layer : public Group { + public: + enum class Type : uchar { + Precomp = 0, + Solid = 1, + Image = 2, + Null = 3, + Shape = 4, + Text = 5 + }; + Layer() : Group(Object::Type::Layer) {} + bool hasRoundedCorner() const noexcept { return mHasRoundedCorner; } + bool hasPathOperator() const noexcept { return mHasPathOperator; } + bool hasGradient() const noexcept { return mHasGradient; } + bool hasMask() const noexcept { return mHasMask; } + bool hasRepeater() const noexcept { return mHasRepeater; } + int id() const noexcept { return mId; } + int parentId() const noexcept { return mParentId; } + bool hasParent() const noexcept { return mParentId != -1; } + int inFrame() const noexcept { return mInFrame; } + int outFrame() const noexcept { return mOutFrame; } + int startFrame() const noexcept { return mStartFrame; } + Color solidColor() const noexcept { return mExtra->mSolidColor; } + bool autoOrient() const noexcept { return mAutoOrient; } + int timeRemap(int frameNo) const; + VSize layerSize() const { return mLayerSize; } + bool precompLayer() const { + return true; + //return mLayerType == Type::Precomp; + } + VMatrix matrix(int frameNo) const + { + return mTransform ? mTransform->matrix(frameNo, autoOrient()) + : VMatrix{}; + } + float opacity(int frameNo) const + { + return mTransform ? mTransform->opacity(frameNo) : 1.0f; + } + Asset *asset() const + { + return (mExtra && mExtra->mAsset) ? mExtra->mAsset : nullptr; + } + struct Extra { + Color mSolidColor; + std::string mPreCompRefId; + Property mTimeRemap; /* "tm" */ + Composition * mCompRef{nullptr}; + Asset * mAsset{nullptr}; + std::vector mMasks; + }; + + Layer::Extra *extra() + { + if (!mExtra) mExtra = std::make_unique(); + return mExtra.get(); + } + public: + MatteType mMatteType{MatteType::None}; + Type mLayerType{Layer::Type::Null}; + BlendMode mBlendMode{BlendMode::Normal}; + bool mHasRoundedCorner{false}; + bool mHasPathOperator{false}; + bool mHasMask{false}; + bool mHasRepeater{false}; + bool mHasGradient{false}; + bool mAutoOrient{false}; + VSize mLayerSize; + int mParentId{-1}; // Lottie the id of the parent in the composition + int mId{-1}; // Lottie the group id used for parenting. + float mTimeStreatch{1.0f}; + int mInFrame{0}; + int mOutFrame{0}; + int mStartFrame{0}; + std::unique_ptr mExtra{nullptr}; }; /** * TimeRemap has the value in time domain(in sec) - * To get the proper mapping first we get the mapped time at the current frame Number - * then we need to convert mapped time to frame number using the composition time line - * Ex: at frame 10 the mappend time is 0.5(500 ms) which will be convert to frame number - * 30 if the frame rate is 60. or will result to frame number 15 if the frame rate is 30. + * To get the proper mapping first we get the mapped time at the current frame + * Number then we need to convert mapped time to frame number using the + * composition time line Ex: at frame 10 the mappend time is 0.5(500 ms) which + * will be convert to frame number 30 if the frame rate is 60. or will result to + * frame number 15 if the frame rate is 30. */ -inline int LOTLayerData::timeRemap(int frameNo) const +inline int Layer::timeRemap(int frameNo) const { /* * only consider startFrame() when there is no timeRemap. @@ -658,296 +757,300 @@ inline int LOTLayerData::timeRemap(int frameNo) const if (!mExtra || mExtra->mTimeRemap.isStatic()) frameNo = frameNo - startFrame(); else - frameNo = mExtra->mCompRef->frameAtTime(mExtra->mTimeRemap.value(frameNo)); + frameNo = + mExtra->mCompRef->frameAtTime(mExtra->mTimeRemap.value(frameNo)); /* Apply time streatch if it has any. - * Time streatch is just a factor by which the animation will speedup or slow - * down with respect to the overal animation. - * Time streach factor is already applied to the layers inFrame and outFrame. - * @TODO need to find out if timestreatch also affects the in and out frame of the - * child layers or not. */ - return frameNo / mTimeStreatch; + * Time streatch is just a factor by which the animation will speedup or + * slow down with respect to the overal animation. Time streach factor is + * already applied to the layers inFrame and outFrame. + * @TODO need to find out if timestreatch also affects the in and out frame + * of the child layers or not. */ + return int(frameNo / mTimeStreatch); } -class LOTFillData : public LOTData -{ +class Stroke : public Object { public: - LOTFillData():LOTData(LOTData::Type::Fill){} - LottieColor color(int frameNo) const {return mColor.value(frameNo);} - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - FillRule fillRule() const {return mFillRule;} -public: - FillRule mFillRule{FillRule::Winding}; /* "r" */ - LOTAnimatable mColor; /* "c" */ - LOTAnimatable mOpacity{100}; /* "o" */ - bool mEnabled{true}; /* "fillEnabled" */ -}; - -struct LOTDashProperty -{ - LOTAnimatable mDashArray[5]; /* "d" "g" "o"*/ - int mDashCount{0}; - bool mStatic{true}; -}; + Stroke() : Object(Object::Type::Stroke) {} + Color color(int frameNo) const { return mColor.value(frameNo); } + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + float strokeWidth(int frameNo) const { return mWidth.value(frameNo); } + CapStyle capStyle() const { return mCapStyle; } + JoinStyle joinStyle() const { return mJoinStyle; } + float miterLimit() const { return mMiterLimit; } + bool hasDashInfo() const { return !mDash.empty(); } + void getDashInfo(int frameNo, std::vector &result) const + { + return mDash.getDashInfo(frameNo, result); + } -class LOTStrokeData : public LOTData -{ -public: - LOTStrokeData():LOTData(LOTData::Type::Stroke){} - LottieColor color(int frameNo) const {return mColor.value(frameNo);} - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - float strokeWidth(int frameNo) const {return mWidth.value(frameNo);} - CapStyle capStyle() const {return mCapStyle;} - JoinStyle joinStyle() const {return mJoinStyle;} - float meterLimit() const{return mMeterLimit;} - bool hasDashInfo() const { return !(mDash.mDashCount == 0);} - int getDashInfo(int frameNo, float *array) const; public: - LOTAnimatable mColor; /* "c" */ - LOTAnimatable mOpacity{100}; /* "o" */ - LOTAnimatable mWidth{0}; /* "w" */ - CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ - JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ - float mMeterLimit{0}; /* "ml" */ - LOTDashProperty mDash; - bool mEnabled{true}; /* "fillEnabled" */ + Property mColor; /* "c" */ + Property mOpacity{100}; /* "o" */ + Property mWidth{0}; /* "w" */ + CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ + JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ + float mMiterLimit{0}; /* "ml" */ + Dash mDash; + bool mEnabled{true}; /* "fillEnabled" */ }; -class LottieGradient -{ +class Gradient : public Object { public: - friend inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2); - friend inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2); - friend inline LottieGradient operator*(float m, const LottieGradient &g); -public: - std::vector mGradient; -}; - -inline LottieGradient operator+(const LottieGradient &g1, const LottieGradient &g2) -{ - if (g1.mGradient.size() != g2.mGradient.size()) - return g1; - - LottieGradient newG; - newG.mGradient = g1.mGradient; - - auto g2It = g2.mGradient.begin(); - for(auto &i : newG.mGradient) { - i = i + *g2It; - g2It++; - } - - return newG; -} - -inline LottieGradient operator-(const LottieGradient &g1, const LottieGradient &g2) -{ - if (g1.mGradient.size() != g2.mGradient.size()) - return g1; - LottieGradient newG; - newG.mGradient = g1.mGradient; - - auto g2It = g2.mGradient.begin(); - for(auto &i : newG.mGradient) { - i = i - *g2It; - g2It++; + class Data { + public: + friend inline Gradient::Data operator+(const Gradient::Data &g1, + const Gradient::Data &g2); + friend inline Gradient::Data operator-(const Gradient::Data &g1, + const Gradient::Data &g2); + friend inline Gradient::Data operator*(float m, + const Gradient::Data &g); + + public: + std::vector mGradient; + }; + explicit Gradient(Object::Type type) : Object(type) {} + inline float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; } + void update(std::unique_ptr &grad, int frameNo); - return newG; -} +private: + void populate(VGradientStops &stops, int frameNo); -inline LottieGradient operator*(float m, const LottieGradient &g) -{ - LottieGradient newG; - newG.mGradient = g.mGradient; +public: + int mGradientType{1}; /* "t" Linear=1 , Radial = 2*/ + Property mStartPoint; /* "s" */ + Property mEndPoint; /* "e" */ + Property mHighlightLength{0}; /* "h" */ + Property mHighlightAngle{0}; /* "a" */ + Property mOpacity{100}; /* "o" */ + Property mGradient; /* "g" */ + int mColorPoints{-1}; + bool mEnabled{true}; /* "fillEnabled" */ +}; - for(auto &i : newG.mGradient) { - i = i * m; +class GradientStroke : public Gradient { +public: + GradientStroke() : Gradient(Object::Type::GStroke) {} + float width(int frameNo) const { return mWidth.value(frameNo); } + CapStyle capStyle() const { return mCapStyle; } + JoinStyle joinStyle() const { return mJoinStyle; } + float miterLimit() const { return mMiterLimit; } + bool hasDashInfo() const { return !mDash.empty(); } + void getDashInfo(int frameNo, std::vector &result) const + { + return mDash.getDashInfo(frameNo, result); } - return newG; -} - +public: + Property mWidth; /* "w" */ + CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ + JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ + float mMiterLimit{0}; /* "ml" */ + Dash mDash; +}; -class LOTGradient : public LOTData -{ +class GradientFill : public Gradient { public: - explicit LOTGradient(LOTData::Type type):LOTData(type){} - inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;} - void update(std::unique_ptr &grad, int frameNo); + GradientFill() : Gradient(Object::Type::GFill) {} + FillRule fillRule() const { return mFillRule; } -private: - void populate(VGradientStops &stops, int frameNo); public: - int mGradientType{1}; /* "t" Linear=1 , Radial = 2*/ - LOTAnimatable mStartPoint; /* "s" */ - LOTAnimatable mEndPoint; /* "e" */ - LOTAnimatable mHighlightLength{0}; /* "h" */ - LOTAnimatable mHighlightAngle{0}; /* "a" */ - LOTAnimatable mOpacity{100}; /* "o" */ - LOTAnimatable mGradient; /* "g" */ - int mColorPoints{-1}; - bool mEnabled{true}; /* "fillEnabled" */ + FillRule mFillRule{FillRule::Winding}; /* "r" */ }; -class LOTGFillData : public LOTGradient -{ +class Fill : public Object { public: - LOTGFillData():LOTGradient(LOTData::Type::GFill){} - FillRule fillRule() const {return mFillRule;} + Fill() : Object(Object::Type::Fill) {} + Color color(int frameNo) const { return mColor.value(frameNo); } + float opacity(int frameNo) const + { + return mOpacity.value(frameNo) / 100.0f; + } + FillRule fillRule() const { return mFillRule; } + public: - FillRule mFillRule{FillRule::Winding}; /* "r" */ + FillRule mFillRule{FillRule::Winding}; /* "r" */ + bool mEnabled{true}; /* "fillEnabled" */ + Property mColor; /* "c" */ + Property mOpacity{100}; /* "o" */ }; -class LOTGStrokeData : public LOTGradient -{ +class Shape : public Object { public: - LOTGStrokeData():LOTGradient(LOTData::Type::GStroke){} - float width(int frameNo) const {return mWidth.value(frameNo);} - CapStyle capStyle() const {return mCapStyle;} - JoinStyle joinStyle() const {return mJoinStyle;} - float meterLimit() const{return mMeterLimit;} - bool hasDashInfo() const { return !(mDash.mDashCount == 0);} - int getDashInfo(int frameNo, float *array) const; + explicit Shape(Object::Type type) : Object(type) {} + VPath::Direction direction() + { + return (mDirection == 3) ? VPath::Direction::CCW : VPath::Direction::CW; + } + public: - LOTAnimatable mWidth; /* "w" */ - CapStyle mCapStyle{CapStyle::Flat}; /* "lc" */ - JoinStyle mJoinStyle{JoinStyle::Miter}; /* "lj" */ - float mMeterLimit{0}; /* "ml" */ - LOTDashProperty mDash; + int mDirection{1}; }; -class LOTPath : public LOTData -{ +class Path : public Shape { public: - explicit LOTPath(LOTData::Type type):LOTData(type){} - VPath::Direction direction() { if (mDirection == 3) return VPath::Direction::CCW; - else return VPath::Direction::CW;} + Path() : Shape(Object::Type::Path) {} + public: - int mDirection{1}; + Property mShape; }; -class LOTShapeData : public LOTPath -{ +class RoundedCorner : public Object { public: - LOTShapeData():LOTPath(LOTData::Type::Shape){} - void process(); + RoundedCorner() : Object(Object::Type::RoundedCorner) {} + float radius(int frameNo) const { return mRadius.value(frameNo);} public: - LOTAnimatable mShape; + Property mRadius{0}; }; -class LOTMaskData -{ +class Rect : public Shape { public: - enum class Mode { - None, - Add, - Substarct, - Intersect, - Difference - }; - float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0f;} - bool isStatic() const {return mIsStatic;} + Rect() : Shape(Object::Type::Rect) {} + float roundness(int frameNo) + { + return mRoundedCorner ? mRoundedCorner->radius(frameNo) : + mRound.value(frameNo); + } + + bool roundnessChanged(int prevFrame, int curFrame) + { + return mRoundedCorner ? mRoundedCorner->mRadius.changed(prevFrame, curFrame) : + mRound.changed(prevFrame, curFrame); + } public: - LOTAnimatable mShape; - LOTAnimatable mOpacity{100}; - bool mInv{false}; - bool mIsStatic{true}; - LOTMaskData::Mode mMode; + RoundedCorner* mRoundedCorner{nullptr}; + Property mPos; + Property mSize; + Property mRound{0}; }; -class LOTRectData : public LOTPath -{ +class Ellipse : public Shape { public: - LOTRectData():LOTPath(LOTData::Type::Rect){} + Ellipse() : Shape(Object::Type::Ellipse) {} + public: - LOTAnimatable mPos; - LOTAnimatable mSize; - LOTAnimatable mRound{0}; + Property mPos; + Property mSize; }; -class LOTEllipseData : public LOTPath -{ +class Polystar : public Shape { public: - LOTEllipseData():LOTPath(LOTData::Type::Ellipse){} + enum class PolyType { Star = 1, Polygon = 2 }; + Polystar() : Shape(Object::Type::Polystar) {} + public: - LOTAnimatable mPos; - LOTAnimatable mSize; + Polystar::PolyType mPolyType{PolyType::Polygon}; + Property mPos; + Property mPointCount{0}; + Property mInnerRadius{0}; + Property mOuterRadius{0}; + Property mInnerRoundness{0}; + Property mOuterRoundness{0}; + Property mRotation{0}; }; -class LOTPolystarData : public LOTPath -{ +class Repeater : public Object { public: - enum class PolyType { - Star = 1, - Polygon = 2 + struct Transform { + VMatrix matrix(int frameNo, float multiplier) const; + float startOpacity(int frameNo) const + { + return mStartOpacity.value(frameNo) / 100; + } + float endOpacity(int frameNo) const + { + return mEndOpacity.value(frameNo) / 100; + } + bool isStatic() const + { + return mRotation.isStatic() && mScale.isStatic() && + mPosition.isStatic() && mAnchor.isStatic() && + mStartOpacity.isStatic() && mEndOpacity.isStatic(); + } + Property mRotation{0}; /* "r" */ + Property mScale{{100, 100}}; /* "s" */ + Property mPosition; /* "p" */ + Property mAnchor; /* "a" */ + Property mStartOpacity{100}; /* "so" */ + Property mEndOpacity{100}; /* "eo" */ }; - LOTPolystarData():LOTPath(LOTData::Type::Polystar){} + Repeater() : Object(Object::Type::Repeater) {} + Group *content() const { return mContent ? mContent : nullptr; } + void setContent(Group *content) { mContent = content; } + int maxCopies() const { return int(mMaxCopies); } + float copies(int frameNo) const { return mCopies.value(frameNo); } + float offset(int frameNo) const { return mOffset.value(frameNo); } + bool processed() const { return mProcessed; } + void markProcessed() { mProcessed = true; } + public: - LOTPolystarData::PolyType mType{PolyType::Polygon}; - LOTAnimatable mPos; - LOTAnimatable mPointCount{0}; - LOTAnimatable mInnerRadius{0}; - LOTAnimatable mOuterRadius{0}; - LOTAnimatable mInnerRoundness{0}; - LOTAnimatable mOuterRoundness{0}; - LOTAnimatable mRotation{0}; + Group * mContent{nullptr}; + Transform mTransform; + Property mCopies{0}; + Property mOffset{0}; + float mMaxCopies{0.0}; + bool mProcessed{false}; }; -class LOTTrimData : public LOTData -{ +class Trim : public Object { public: struct Segment { float start{0}; float end{0}; - Segment() {} - Segment(float s, float e):start(s), end(e) {} + Segment() = default; + explicit Segment(float s, float e) : start(s), end(e) {} }; - enum class TrimType { - Simultaneously, - Individually - }; - LOTTrimData():LOTData(LOTData::Type::Trim){} + enum class TrimType { Simultaneously, Individually }; + Trim() : Object(Object::Type::Trim) {} /* * if start > end vector trims the path as a loop ( 2 segment) * if start < end vector trims the path without loop ( 1 segment). * if no offset then there is no loop. */ - Segment segment(int frameNo) const { - float start = mStart.value(frameNo)/100.0f; - float end = mEnd.value(frameNo)/100.0f; - float offset = fmod(mOffset.value(frameNo), 360.0f)/ 360.0f; + Segment segment(int frameNo) const + { + float start = mStart.value(frameNo) / 100.0f; + float end = mEnd.value(frameNo) / 100.0f; + float offset = std::fmod(mOffset.value(frameNo), 360.0f) / 360.0f; - float diff = fabs(start - end); + float diff = std::abs(start - end); if (vCompare(diff, 0.0f)) return Segment(0, 0); if (vCompare(diff, 1.0f)) return Segment(0, 1); if (offset > 0) { start += offset; end += offset; - if (start <= 1 && end <=1) { + if (start <= 1 && end <= 1) { return noloop(start, end); } else if (start > 1 && end > 1) { return noloop(start - 1, end - 1); } else { - if (start > 1) return loop(start - 1 , end); - else return loop(start , end - 1); + return (start > 1) ? loop(start - 1, end) + : loop(start, end - 1); } } else { start += offset; - end += offset; + end += offset; if (start >= 0 && end >= 0) { return noloop(start, end); } else if (start < 0 && end < 0) { return noloop(1 + start, 1 + end); } else { - if (start < 0) return loop(1 + start, end); - else return loop(start , 1 + end); + return (start < 0) ? loop(1 + start, end) + : loop(start, 1 + end); } } } - LOTTrimData::TrimType type() const {return mTrimType;} + Trim::TrimType type() const { return mTrimType; } + private: - Segment noloop(float start, float end) const{ + Segment noloop(float start, float end) const + { assert(start >= 0); assert(end >= 0); Segment s; @@ -955,7 +1058,8 @@ class LOTTrimData : public LOTData s.end = std::max(start, end); return s; } - Segment loop(float start, float end) const{ + Segment loop(float start, float end) const + { assert(start >= 0); assert(end >= 0); Segment s; @@ -963,68 +1067,81 @@ class LOTTrimData : public LOTData s.end = std::min(start, end); return s; } + public: - LOTAnimatable mStart{0}; - LOTAnimatable mEnd{0}; - LOTAnimatable mOffset{0}; - LOTTrimData::TrimType mTrimType{TrimType::Simultaneously}; + Property mStart{0}; + Property mEnd{0}; + Property mOffset{0}; + Trim::TrimType mTrimType{TrimType::Simultaneously}; }; -class LOTRepeaterTransform +inline Gradient::Data operator+(const Gradient::Data &g1, + const Gradient::Data &g2) { -public: - VMatrix matrix(int frameNo, float multiplier) const; - float startOpacity(int frameNo) const { return mStartOpacity.value(frameNo)/100;} - float endOpacity(int frameNo) const { return mEndOpacity.value(frameNo)/100;} - bool isStatic() const - { - return mRotation.isStatic() && - mScale.isStatic() && - mPosition.isStatic() && - mAnchor.isStatic() && - mStartOpacity.isStatic() && - mEndOpacity.isStatic(); + if (g1.mGradient.size() != g2.mGradient.size()) return g1; + + Gradient::Data newG; + newG.mGradient = g1.mGradient; + + auto g2It = g2.mGradient.begin(); + for (auto &i : newG.mGradient) { + i = i + *g2It; + g2It++; } -public: - LOTAnimatable mRotation{0}; /* "r" */ - LOTAnimatable mScale{{100, 100}}; /* "s" */ - LOTAnimatable mPosition; /* "p" */ - LOTAnimatable mAnchor; /* "a" */ - LOTAnimatable mStartOpacity{100}; /* "so" */ - LOTAnimatable mEndOpacity{100}; /* "eo" */ -}; -class LOTRepeaterData : public LOTData + return newG; +} + +inline Gradient::Data operator-(const Gradient::Data &g1, + const Gradient::Data &g2) { -public: - LOTRepeaterData():LOTData(LOTData::Type::Repeater){} - LOTShapeGroupData *content() const { return mContent ? mContent.get() : nullptr; } - void setContent(std::shared_ptr content) {mContent = std::move(content);} - int maxCopies() const { return int(mMaxCopies);} - float copies(int frameNo) const {return mCopies.value(frameNo);} - float offset(int frameNo) const {return mOffset.value(frameNo);} -public: - std::shared_ptr mContent{nullptr}; - LOTRepeaterTransform mTransform; - LOTAnimatable mCopies{0}; - LOTAnimatable mOffset{0}; - float mMaxCopies{0.0}; -}; + if (g1.mGradient.size() != g2.mGradient.size()) return g1; + Gradient::Data newG; + newG.mGradient = g1.mGradient; + + auto g2It = g2.mGradient.begin(); + for (auto &i : newG.mGradient) { + i = i - *g2It; + g2It++; + } + + return newG; +} -class LOTModel +inline Gradient::Data operator*(float m, const Gradient::Data &g) { -public: - bool isStatic() const {return mRoot->isStatic();} - double duration() const {return mRoot->duration();} - size_t totalFrame() const {return mRoot->totalFrame();} - size_t frameDuration() const {return mRoot->frameDuration();} - size_t frameRate() const {return mRoot->frameRate();} - size_t startFrame() const {return mRoot->startFrame();} - size_t endFrame() const {return mRoot->endFrame();} - size_t frameAtPos(double pos) const {return mRoot->frameAtPos(pos);} - const std::vector &layerInfoList() const { return mRoot->layerInfoList();} -public: - std::shared_ptr mRoot; -}; + Gradient::Data newG; + newG.mGradient = g.mGradient; + + for (auto &i : newG.mGradient) { + i = i * m; + } + return newG; +} + +using ColorFilter = std::function; + +void configureModelCacheSize(size_t cacheSize); + +std::shared_ptr loadFromFile(const std::string &filePath, + bool cachePolicy); + +std::shared_ptr loadFromData(std::string jsonData, + const std::string &key, + std::string resourcePath, + bool cachePolicy); + +std::shared_ptr loadFromData(std::string jsonData, + std::string resourcePath, + ColorFilter filter); + +std::shared_ptr parse(char *str, std::string dir_path, + ColorFilter filter = {}); + +} // namespace model + +} // namespace internal + +} // namespace rlottie -#endif // LOTModel_H +#endif // LOTModel_H diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieparser.cpp b/AXrLottie/src/main/cpp/src/lottie/lottieparser.cpp index 18d0009..914507d 100644 --- a/AXrLottie/src/main/cpp/src/lottie/lottieparser.cpp +++ b/AXrLottie/src/main/cpp/src/lottie/lottieparser.cpp @@ -1,27 +1,27 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ -#include "lottieparser.h" - //#define DEBUG_PARSER -//#define DEBUG_PRINT_TREE - // This parser implements JSON token-by-token parsing with an API that is // more direct; we don't have to create handler object and // callbacks. Instead, we retrieve values from the JSON stream by calling @@ -54,7 +54,6 @@ // the parse. #include -#include #include "lottiemodel.h" #include "rapidjson/document.h" @@ -66,13 +65,7 @@ RAPIDJSON_DIAG_OFF(effc++) using namespace rapidjson; -template -std::string to_string(T value) -{ - std::ostringstream os ; - os << value ; - return os.str() ; -} +using namespace rlottie::internal; class LookaheadParserHandler { public: @@ -106,7 +99,7 @@ class LookaheadParserHandler { v_.SetInt64(i); return true; } - bool Uint64(uint64_t u) + bool Uint64(int64_t u) { st_ = kHasNumber; v_.SetUint64(u); @@ -154,7 +147,6 @@ class LookaheadParserHandler { protected: explicit LookaheadParserHandler(char *str); - void ParseNext(); protected: enum LookaheadParsingState { @@ -179,143 +171,235 @@ class LookaheadParserHandler { static const int parseFlags = kParseDefaultFlags | kParseInsituFlag; }; -class LottieParserImpl : protected LookaheadParserHandler { +class LottieParserImpl : public LookaheadParserHandler { public: - LottieParserImpl(char *str, const char *dir_path, std::map *colorReplacement) - : LookaheadParserHandler(str), mDirPath(dir_path), colorMap(colorReplacement) + LottieParserImpl(char *str, std::string dir_path, model::ColorFilter filter) + : LookaheadParserHandler(str), + mColorFilter(std::move(filter)), + mDirPath(std::move(dir_path)) { } + bool VerifyType(); + bool ParseNext(); public: - bool EnterObject(); - bool EnterArray(); - const char *NextObjectKey(); - bool NextArrayValue(); - int GetInt(); - double GetDouble(); - const char *GetString(); - bool GetBool(); - void GetNull(); + VArenaAlloc &allocator() { return compRef->mArenaAlloc; } + bool EnterObject(); + bool EnterArray(); + const char * NextObjectKey(); + bool NextArrayValue(); + int GetInt(); + double GetDouble(); + const char * GetString(); + bool GetBool(); + void GetNull(); void SkipObject(); void SkipArray(); void SkipValue(); Value *PeekValue(); - int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of - // object/array) - - bool IsValid() { return st_ != kError; } + int PeekType() const; + bool IsValid() { return st_ != kError; } void Skip(const char *key); - LottieBlendMode getBlendMode(); + model::BlendMode getBlendMode(); CapStyle getLineCap(); JoinStyle getLineJoin(); FillRule getFillRule(); - LOTTrimData::TrimType getTrimType(); - MatteType getMatteType(); - LayerType getLayerType(); + model::Trim::TrimType getTrimType(); + model::MatteType getMatteType(); + model::Layer::Type getLayerType(); - std::shared_ptr composition() const + std::shared_ptr composition() const { return mComposition; } - void parseComposition(); - void parseAssets(LOTCompositionData *comp); - std::shared_ptr parseAsset(); - void parseLayers(LOTCompositionData *comp); - std::shared_ptr parseLayer(bool record = false); - void parseMaskProperty(LOTLayerData *layer); - void parseShapesAttr(LOTLayerData *layer); - void parseObject(LOTGroupData *parent); - std::shared_ptr parseMaskObject(); - std::shared_ptr parseObjectTypeAttr(); - std::shared_ptr parseGroupObject(); - std::shared_ptr parseRectObject(); - std::shared_ptr parseEllipseObject(); - std::shared_ptr parseShapeObject(); - std::shared_ptr parsePolystarObject(); - - std::shared_ptr parseTransformObject(bool ddd = false); - std::shared_ptr parseFillObject(); - std::shared_ptr parseGFillObject(); - std::shared_ptr parseStrokeObject(); - std::shared_ptr parseGStrokeObject(); - std::shared_ptr parseTrimObject(); - std::shared_ptr parseReapeaterObject(); - - void parseGradientProperty(LOTGradient *gradient, const char *key); + void parseComposition(); + void parseMarkers(); + void parseMarker(); + void parseAssets(model::Composition *comp); + model::Asset * parseAsset(); + void parseLayers(model::Composition *comp); + model::Layer * parseLayer(); + void parseMaskProperty(model::Layer *layer); + void parseShapesAttr(model::Layer *layer); + void parseObject(model::Group *parent); + model::Mask * parseMaskObject(); + model::Object * parseObjectTypeAttr(); + model::Object * parseGroupObject(); + model::Rect * parseRectObject(); + model::RoundedCorner * parseRoundedCorner(); + void updateRoundedCorner(model::Group *parent, model::RoundedCorner *rc); + + model::Ellipse * parseEllipseObject(); + model::Path * parseShapeObject(); + model::Polystar *parsePolystarObject(); + + model::Transform * parseTransformObject(bool ddd = false); + model::Fill * parseFillObject(); + model::GradientFill * parseGFillObject(); + model::Stroke * parseStrokeObject(); + model::GradientStroke *parseGStrokeObject(); + model::Trim * parseTrimObject(); + model::Repeater * parseReapeaterObject(); + + void parseGradientProperty(model::Gradient *gradient, const char *key); VPointF parseInperpolatorPoint(); - void getValue(VPointF &val); - void getValue(float &val); - void getValue(LottieColor &val); - void getValue(int &val); - void getValue(LottieShapeData &shape); - void getValue(LottieGradient &gradient); + void getValue(VPointF &pt); + void getValue(float &fval); + void getValue(model::Color &color); + void getValue(int &ival); + void getValue(model::PathData &shape); + void getValue(model::Gradient::Data &gradient); void getValue(std::vector &v); - void getValue(LOTRepeaterTransform &); + void getValue(model::Repeater::Transform &); + + template + bool parseKeyFrameValue(const char *, model::Value &) + { + return false; + } template - bool parseKeyFrameValue(const char *key, LOTKeyFrameValue &value); - template - void parseKeyFrame(LOTAnimInfo &obj); - template - void parseProperty(LOTAnimatable &obj); + bool parseKeyFrameValue(const char * key, + model::Value &value); + template + void parseKeyFrame(model::KeyFrames &obj); template - void parsePropertyHelper(LOTAnimatable &obj); + void parseProperty(model::Property &obj); + template + void parsePropertyHelper(model::Property &obj); - void parseShapeKeyFrame(LOTAnimInfo &obj); - void parseShapeProperty(LOTAnimatable &obj); - void parseDashProperty(LOTDashProperty &dash); + void parseShapeProperty(model::Property &obj); + void parseDashProperty(model::Dash &dash); - std::shared_ptr interpolator(VPointF, VPointF, std::string); + VInterpolator *interpolator(VPointF, VPointF, std::string); - LottieColor toColor(const char *str); + model::Color toColor(const char *str); void resolveLayerRefs(); - - bool hasParsingError(); + void parsePathInfo(); + +private: + model::ColorFilter mColorFilter; + struct { + std::vector mInPoint; /* "i" */ + std::vector mOutPoint; /* "o" */ + std::vector mVertices; /* "v" */ + std::vector mResult; + bool mClosed{false}; + + void convert() + { + // shape data could be empty. + if (mInPoint.empty() || mOutPoint.empty() || mVertices.empty()) { + mResult.clear(); + return; + } + + /* + * Convert the AE shape format to + * list of bazier curves + * The final structure will be Move +size*Cubic + Cubic (if the path + * is closed one) + */ + if (mInPoint.size() != mOutPoint.size() || + mInPoint.size() != mVertices.size()) { + mResult.clear(); + } else { + auto size = mVertices.size(); + mResult.push_back(mVertices[0]); + for (size_t i = 1; i < size; i++) { + mResult.push_back( + mVertices[i - 1] + + mOutPoint[i - 1]); // CP1 = start + outTangent + mResult.push_back(mVertices[i] + + mInPoint[i]); // CP2 = end + inTangent + mResult.push_back(mVertices[i]); // end point + } + + if (mClosed) { + mResult.push_back( + mVertices[size - 1] + + mOutPoint[size - 1]); // CP1 = start + outTangent + mResult.push_back(mVertices[0] + + mInPoint[0]); // CP2 = end + inTangent + mResult.push_back(mVertices[0]); // end point + } + } + } + void reset() + { + mInPoint.clear(); + mOutPoint.clear(); + mVertices.clear(); + mResult.clear(); + mClosed = false; + } + void updatePath(VPath &out) + { + if (mResult.empty()) return; + + auto size = mResult.size(); + auto points = mResult.data(); + /* reserve exact memory requirement at once + * ptSize = size + 1(size + close) + * elmSize = size/3 cubic + 1 move + 1 close + */ + out.reserve(size + 1, size / 3 + 2); + out.moveTo(points[0]); + for (size_t i = 1; i < size; i += 3) { + out.cubicTo(points[i], points[i + 1], points[i + 2]); + } + if (mClosed) out.close(); + } + } mPathInfo; protected: - std::unordered_map> - mInterpolatorCache; - std::shared_ptr mComposition; - LOTCompositionData * compRef{nullptr}; - LOTLayerData * curLayerRef{nullptr}; - std::vector> mLayersToUpdate; - std::string mDirPath; - std::vector mLayerInfoList; - std::map *colorMap; - - void SkipOut(int depth); - bool parsingError{false}; + std::unordered_map mInterpolatorCache; + std::shared_ptr mComposition; + model::Composition * compRef{nullptr}; + model::Layer * curLayerRef{nullptr}; + std::vector mLayersToUpdate; + std::string mDirPath; + void SkipOut(int depth); }; LookaheadParserHandler::LookaheadParserHandler(char *str) - : v_(), st_(kInit), r_(), ss_(str) + : v_(), st_(kInit), ss_(str) { r_.IterativeParseInit(); - ParseNext(); } -void LookaheadParserHandler::ParseNext() +bool LottieParserImpl::VerifyType() +{ + /* Verify the media type is lottie json. + Could add more strict check. */ + return ParseNext(); +} + +bool LottieParserImpl::ParseNext() { if (r_.HasParseError()) { st_ = kError; - return; + return false; } if (!r_.IterativeParseNext(ss_, *this)) { vCritical << "Lottie file parsing error"; st_ = kError; + return false; } + return true; } bool LottieParserImpl::EnterObject() { if (st_ != kEnteringObject) { st_ = kError; + RAPIDJSON_ASSERT(false); return false; } @@ -327,6 +411,7 @@ bool LottieParserImpl::EnterArray() { if (st_ != kEnteringArray) { st_ = kError; + RAPIDJSON_ASSERT(false); return false; } @@ -352,16 +437,17 @@ const char *LottieParserImpl::NextObjectKey() // #ifdef DEBUG_PARSER // vDebug<<"Object: Exiting nested loop"; // #endif - return 0; + return nullptr; } if (st_ != kExitingObject) { + RAPIDJSON_ASSERT(false); st_ = kError; - return 0; + return nullptr; } ParseNext(); - return 0; + return nullptr; } bool LottieParserImpl::NextArrayValue() @@ -375,13 +461,11 @@ bool LottieParserImpl::NextArrayValue() * same as NextObjectKey() */ if (st_ == kExitingObject) { - // #ifdef DEBUG_PARSER - // vDebug<<"Array: Exiting nested loop"; - // #endif - return 0; + return false; } if (st_ == kError || st_ == kHasKey) { + RAPIDJSON_ASSERT(false); st_ = kError; return false; } @@ -393,6 +477,7 @@ int LottieParserImpl::GetInt() { if (st_ != kHasNumber || !v_.IsInt()) { st_ = kError; + RAPIDJSON_ASSERT(false); return 0; } @@ -405,6 +490,7 @@ double LottieParserImpl::GetDouble() { if (st_ != kHasNumber) { st_ = kError; + RAPIDJSON_ASSERT(false); return 0.; } @@ -417,6 +503,7 @@ bool LottieParserImpl::GetBool() { if (st_ != kHasBool) { st_ = kError; + RAPIDJSON_ASSERT(false); return false; } @@ -439,7 +526,8 @@ const char *LottieParserImpl::GetString() { if (st_ != kHasString) { st_ = kError; - return ""; + RAPIDJSON_ASSERT(false); + return nullptr; } const char *result = v_.GetString(); @@ -455,6 +543,7 @@ void LottieParserImpl::SkipOut(int depth) } else if (st_ == kExitingArray || st_ == kExitingObject) { --depth; } else if (st_ == kError) { + RAPIDJSON_ASSERT(false); return; } @@ -483,10 +572,12 @@ Value *LottieParserImpl::PeekValue() return &v_; } - return 0; + return nullptr; } -int LottieParserImpl::PeekType() +// returns a rapidjson::Type, or -1 for no value (at end of +// object/array) +int LottieParserImpl::PeekType() const { if (st_ >= kHasNull && st_ <= kHasKey) { return v_.GetType(); @@ -516,38 +607,35 @@ void LottieParserImpl::Skip(const char * /*key*/) } } -LottieBlendMode LottieParserImpl::getBlendMode() { - LottieBlendMode mode = LottieBlendMode::Normal; - if (PeekType() != kNumberType) { - parsingError = true; - return mode; - } +model::BlendMode LottieParserImpl::getBlendMode() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); + auto mode = model::BlendMode::Normal; switch (GetInt()) { - case 1: - mode = LottieBlendMode::Multiply; - break; - case 2: - mode = LottieBlendMode::Screen; - break; - case 3: - mode = LottieBlendMode::OverLay; - break; - default: - break; + case 1: + mode = model::BlendMode::Multiply; + break; + case 2: + mode = model::BlendMode::Screen; + break; + case 3: + mode = model::BlendMode::OverLay; + break; + default: + break; } return mode; } void LottieParserImpl::resolveLayerRefs() { - for (const auto &i : mLayersToUpdate) { - LOTLayerData *layer = i.get(); - auto search = compRef->mAssets.find(layer->extra()->mPreCompRefId); + for (const auto &layer : mLayersToUpdate) { + auto search = compRef->mAssets.find(layer->extra()->mPreCompRefId); if (search != compRef->mAssets.end()) { - if (layer->mLayerType == LayerType::Image) { + if (layer->mLayerType == model::Layer::Type::Image) { layer->extra()->mAsset = search->second; - } else if (layer->mLayerType == LayerType::Precomp) { + } else if (layer->mLayerType == model::Layer::Type::Precomp) { layer->mChildren = search->second->mLayers; layer->setStatic(layer->isStatic() && search->second->isStatic()); @@ -556,60 +644,39 @@ void LottieParserImpl::resolveLayerRefs() } } -bool LottieParserImpl::hasParsingError() { - return parsingError; -} - -void LottieParserImpl::parseComposition() { - if (PeekType() != kObjectType) { - parsingError = true; - return; - } +void LottieParserImpl::parseComposition() +{ + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); - std::shared_ptr sharedComposition = std::make_shared(); - LOTCompositionData *comp = sharedComposition.get(); + std::shared_ptr sharedComposition = + std::make_shared(); + model::Composition *comp = sharedComposition.get(); compRef = comp; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "v")) { - if (PeekType() != kStringType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kStringType); comp->mVersion = std::string(GetString()); } else if (0 == strcmp(key, "w")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); comp->mSize.setWidth(GetInt()); } else if (0 == strcmp(key, "h")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); comp->mSize.setHeight(GetInt()); } else if (0 == strcmp(key, "ip")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); comp->mStartFrame = GetDouble(); } else if (0 == strcmp(key, "op")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); comp->mEndFrame = GetDouble(); } else if (0 == strcmp(key, "fr")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); comp->mFrameRate = GetDouble(); } else if (0 == strcmp(key, "assets")) { parseAssets(comp); } else if (0 == strcmp(key, "layers")) { parseLayers(comp); + } else if (0 == strcmp(key, "markers")) { + parseMarkers(); } else { #ifdef DEBUG_PARSER vWarning << "Composition Attribute Skipped : " << key; @@ -617,43 +684,69 @@ void LottieParserImpl::parseComposition() { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return; - } + if (comp->mVersion.empty() || !comp->mRootLayer) { // don't have a valid bodymovin header return; } + if (!IsValid()) { + return; + } + resolveLayerRefs(); comp->setStatic(comp->mRootLayer->isStatic()); comp->mRootLayer->mInFrame = comp->mStartFrame; comp->mRootLayer->mOutFrame = comp->mEndFrame; - comp->mLayerInfoList = std::move(mLayerInfoList); - mComposition = sharedComposition; } -void LottieParserImpl::parseAssets(LOTCompositionData *composition) { - if (PeekType() != kArrayType) { - parsingError = true; - return; +void LottieParserImpl::parseMarker() +{ + RAPIDJSON_ASSERT(PeekType() == kObjectType); + EnterObject(); + std::string comment; + int timeframe{0}; + int duration{0}; + while (const char *key = NextObjectKey()) { + if (0 == strcmp(key, "cm")) { + RAPIDJSON_ASSERT(PeekType() == kStringType); + comment = std::string(GetString()); + } else if (0 == strcmp(key, "tm")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + timeframe = GetDouble(); + } else if (0 == strcmp(key, "dr")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + duration = GetDouble(); + + } else { +#ifdef DEBUG_PARSER + vWarning << "Marker Attribute Skipped : " << key; +#endif + Skip(key); + } } + compRef->mMarkers.emplace_back(std::move(comment), timeframe, + timeframe + duration); +} + +void LottieParserImpl::parseMarkers() +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - std::shared_ptr asset = parseAsset(); - if (asset == nullptr) { - return; - } - composition->mAssets[asset->mRefId] = asset; + parseMarker(); } - if (!IsValid()) { - parsingError = true; - return; + // update the precomp layers with the actual layer object +} + +void LottieParserImpl::parseAssets(model::Composition *composition) +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); + EnterArray(); + while (NextArrayValue()) { + auto asset = parseAsset(); + composition->mAssets[asset->mRefId] = asset; } // update the precomp layers with the actual layer object } @@ -667,12 +760,12 @@ static constexpr const unsigned char B64index[256] = { 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; -std::string b64decode(const void *data, const size_t len) +std::string b64decode(const char *data, const size_t len) { - unsigned char *p = (unsigned char *)data; - int pad = len > 0 && (len % 4 || p[len - 1] == '='); - const size_t L = ((len + 3) / 4 - pad) * 4; - std::string str(L / 4 * 3 + pad, '\0'); + auto p = reinterpret_cast(data); + int pad = len > 0 && (len % 4 || p[len - 1] == '='); + const size_t L = ((len + 3) / 4 - pad) * 4; + std::string str(L / 4 * 3 + pad, '\0'); for (size_t i = 0, j = 0; i < L; i += 4) { int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | @@ -697,55 +790,54 @@ static std::string convertFromBase64(const std::string &str) { // usual header look like "data:image/png;base64," // so need to skip till ','. - int startIndex = str.find(",", 0); + size_t startIndex = str.find(",", 0); startIndex += 1; // skip "," - int length = str.length() - startIndex; + size_t length = str.length() - startIndex; const char *b64Data = str.c_str() + startIndex; return b64decode(b64Data, length); } +/* + * std::to_string() function is missing in VS2017 + * so this is workaround for windows build + */ +#include +template +static std::string toString(const T &value) +{ + std::ostringstream os; + os << value; + return os.str(); +} + /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/layers/shape.json * */ -std::shared_ptr LottieParserImpl::parseAsset() { - std::shared_ptr sharedAsset = std::make_shared(); - if (PeekType() != kObjectType) { - parsingError = true; - return sharedAsset; - } - LOTAsset *asset = sharedAsset.get(); +model::Asset *LottieParserImpl::parseAsset() +{ + RAPIDJSON_ASSERT(PeekType() == kObjectType); + + auto asset = allocator().make(); std::string filename; std::string relativePath; - bool embededResource = false; + bool embededResource = false; EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "w")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedAsset; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); asset->mWidth = GetInt(); } else if (0 == strcmp(key, "h")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedAsset; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); asset->mHeight = GetInt(); } else if (0 == strcmp(key, "p")) { /* image name */ - asset->mAssetType = LOTAsset::Type::Image; - if (PeekType() != kStringType) { - parsingError = true; - return sharedAsset; - } + asset->mAssetType = model::Asset::Type::Image; + RAPIDJSON_ASSERT(PeekType() == kStringType); filename = std::string(GetString()); } else if (0 == strcmp(key, "u")) { /* relative image path */ - if (PeekType() != kStringType) { - parsingError = true; - return sharedAsset; - } + RAPIDJSON_ASSERT(PeekType() == kStringType); relativePath = std::string(GetString()); } else if (0 == strcmp(key, "e")) { /* relative image path */ embededResource = GetInt(); @@ -753,34 +845,21 @@ std::shared_ptr LottieParserImpl::parseAsset() { if (PeekType() == kStringType) { asset->mRefId = std::string(GetString()); } else { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedAsset; - } - asset->mRefId = to_string(GetInt()); + RAPIDJSON_ASSERT(PeekType() == kNumberType); + asset->mRefId = toString(GetInt()); } } else if (0 == strcmp(key, "layers")) { - asset->mAssetType = LOTAsset::Type::Precomp; - if (PeekType() != kArrayType) { - parsingError = true; - return sharedAsset; - } + asset->mAssetType = model::Asset::Type::Precomp; + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); bool staticFlag = true; while (NextArrayValue()) { - if (parsingError) { - return sharedAsset; - } - std::shared_ptr layer = parseLayer(); + auto layer = parseLayer(); if (layer) { staticFlag = staticFlag && layer->isStatic(); asset->mLayers.push_back(layer); } } - if (!IsValid()) { - parsingError = true; - return sharedAsset; - } asset->setStatic(staticFlag); } else { #ifdef DEBUG_PARSER @@ -789,12 +868,8 @@ std::shared_ptr LottieParserImpl::parseAsset() { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedAsset; - } - if (asset->mAssetType == LOTAsset::Type::Image) { + if (asset->mAssetType == model::Asset::Type::Image) { if (embededResource) { // embeder resource should start with "data:" if (filename.compare(0, 5, "data:") == 0) { @@ -805,121 +880,99 @@ std::shared_ptr LottieParserImpl::parseAsset() { } } - return sharedAsset; + return asset; } -void LottieParserImpl::parseLayers(LOTCompositionData *comp) { - comp->mRootLayer = std::make_shared(); - comp->mRootLayer->mLayerType = LayerType::Precomp; +void LottieParserImpl::parseLayers(model::Composition *comp) +{ + comp->mRootLayer = allocator().make(); + comp->mRootLayer->mLayerType = model::Layer::Type::Precomp; comp->mRootLayer->setName("__"); bool staticFlag = true; - if (PeekType() != kArrayType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - std::shared_ptr layer = parseLayer(true); + auto layer = parseLayer(); if (layer) { staticFlag = staticFlag && layer->isStatic(); comp->mRootLayer->mChildren.push_back(layer); } } - if (!IsValid()) { - parsingError = true; - return; - } comp->mRootLayer->setStatic(staticFlag); } -LottieColor LottieParserImpl::toColor(const char *str) +model::Color LottieParserImpl::toColor(const char *str) { - LottieColor color; - int len = strlen(str); + model::Color color; + auto len = strlen(str); // some resource has empty color string // return a default color for those cases. - if (!len) return color; - - if (len != 7 || str[0] != '#') { - parsingError = true; - return color; - } + if (len != 7 || str[0] != '#') return color; char tmp[3] = {'\0', '\0', '\0'}; - tmp[0] = str[1]; tmp[1] = str[2]; - long b = std::strtol(tmp, NULL, 16); + color.r = std::strtol(tmp, nullptr, 16) / 255.0f; + tmp[0] = str[3]; tmp[1] = str[4]; - long g = std::strtol(tmp, NULL, 16); + color.g = std::strtol(tmp, nullptr, 16) / 255.0f; + tmp[0] = str[5]; tmp[1] = str[6]; - long r = std::strtol(tmp, NULL, 16); - - color.r = r / 255.0f; - color.g = g / 255.0f; - color.b = b / 255.0f; - color.colorMap = colorMap; + color.b = std::strtol(tmp, nullptr, 16) / 255.0f; return color; } -MatteType LottieParserImpl::getMatteType() { - if (PeekType() != kNumberType) { - parsingError = true; - return MatteType::None; - } +model::MatteType LottieParserImpl::getMatteType() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 1: - return MatteType::Alpha; - break; - case 2: - return MatteType::AlphaInv; - break; - case 3: - return MatteType::Luma; - break; - case 4: - return MatteType::LumaInv; - break; - default: - return MatteType::None; - break; - } -} - -LayerType LottieParserImpl::getLayerType() { - if (PeekType() != kNumberType) { - parsingError = true; - return LayerType::Null; - } + case 1: + return model::MatteType::Alpha; + break; + case 2: + return model::MatteType::AlphaInv; + break; + case 3: + return model::MatteType::Luma; + break; + case 4: + return model::MatteType::LumaInv; + break; + default: + return model::MatteType::None; + break; + } +} + +model::Layer::Type LottieParserImpl::getLayerType() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 0: - return LayerType::Precomp; - break; - case 1: - return LayerType::Solid; - break; - case 2: - return LayerType::Image; - break; - case 3: - return LayerType::Null; - break; - case 4: - return LayerType::Shape; - break; - case 5: - return LayerType::Text; - break; - default: - return LayerType::Null; - break; + case 0: + return model::Layer::Type::Precomp; + break; + case 1: + return model::Layer::Type::Solid; + break; + case 2: + return model::Layer::Type::Image; + break; + case 3: + return model::Layer::Type::Null; + break; + case 4: + return model::Layer::Type::Shape; + break; + case 5: + return model::Layer::Type::Text; + break; + default: + return model::Layer::Type::Null; + break; } } @@ -927,14 +980,10 @@ LayerType LottieParserImpl::getLayerType() { * https://github.com/airbnb/lottie-web/blob/master/docs/json/layers/shape.json * */ -std::shared_ptr LottieParserImpl::parseLayer(bool record) { - std::shared_ptr sharedLayer = - std::make_shared(); - LOTLayerData *layer = sharedLayer.get(); - if (PeekType() != kObjectType) { - parsingError = true; - return sharedLayer; - } +model::Layer *LottieParserImpl::parseLayer() +{ + RAPIDJSON_ASSERT(PeekType() == kObjectType); + model::Layer *layer = allocator().make(); curLayerRef = layer; bool ddd = true; EnterObject(); @@ -942,73 +991,43 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) { if (0 == strcmp(key, "ty")) { /* Type of layer*/ layer->mLayerType = getLayerType(); } else if (0 == strcmp(key, "nm")) { /*Layer name*/ - if (PeekType() != kStringType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kStringType); layer->setName(GetString()); } else if (0 == strcmp(key, "ind")) { /*Layer index in AE. Used for parenting and expressions.*/ - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mId = GetInt(); } else if (0 == strcmp(key, "ddd")) { /*3d layer */ - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); ddd = GetInt(); } else if (0 == strcmp(key, "parent")) { /*Layer Parent. Uses "ind" of parent.*/ - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mParentId = GetInt(); } else if (0 == strcmp(key, "refId")) { /*preComp Layer reference id*/ - if (PeekType() != kStringType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kStringType); layer->extra()->mPreCompRefId = std::string(GetString()); layer->mHasGradient = true; - mLayersToUpdate.push_back(sharedLayer); + mLayersToUpdate.push_back(layer); } else if (0 == strcmp(key, "sr")) { // "Layer Time Stretching" - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mTimeStreatch = GetDouble(); } else if (0 == strcmp(key, "tm")) { // time remapping parseProperty(layer->extra()->mTimeRemap); } else if (0 == strcmp(key, "ip")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } - layer->mInFrame = round(GetDouble()); + RAPIDJSON_ASSERT(PeekType() == kNumberType); + layer->mInFrame = std::lround(GetDouble()); } else if (0 == strcmp(key, "op")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } - layer->mOutFrame = round(GetDouble()); + RAPIDJSON_ASSERT(PeekType() == kNumberType); + layer->mOutFrame = std::lround(GetDouble()); } else if (0 == strcmp(key, "st")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); layer->mStartFrame = GetDouble(); } else if (0 == strcmp(key, "bm")) { layer->mBlendMode = getBlendMode(); } else if (0 == strcmp(key, "ks")) { - if (PeekType() != kObjectType) { - parsingError = true; - return sharedLayer; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); layer->mTransform = parseTransformObject(ddd); } else if (0 == strcmp(key, "shapes")) { @@ -1040,13 +1059,15 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) { Skip(key); } } - if (!IsValid() || layer->mTransform == nullptr) { - parsingError = true; - return sharedLayer; + + if (!layer->mTransform) { + // not a valid layer + return nullptr; } // make sure layer data is not corrupted. - if (layer->hasParent() && (layer->id() == layer->parentId())) return nullptr; + if (layer->hasParent() && (layer->id() == layer->parentId())) + return nullptr; if (layer->mExtra) layer->mExtra->mCompRef = compRef; @@ -1055,15 +1076,15 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) { // transform matrix(when it is a parent of some other layer) // so force it to be a Null Layer and release all resource. layer->setStatic(layer->mTransform->isStatic()); - layer->mLayerType = LayerType::Null; + layer->mLayerType = model::Layer::Type::Null; layer->mChildren = {}; - return sharedLayer; + return layer; } // update the static property of layer bool staticFlag = true; for (const auto &child : layer->mChildren) { - staticFlag &= child.get()->isStatic(); + staticFlag &= child->isStatic(); } if (layer->hasMask()) { @@ -1074,68 +1095,51 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) { layer->setStatic(staticFlag && layer->mTransform->isStatic()); - if (record) { - mLayerInfoList.push_back( - LayerInfo(layer->name(), layer->mInFrame, layer->mOutFrame)); - } - return sharedLayer; + return layer; } -void LottieParserImpl::parseMaskProperty(LOTLayerData *layer) { - if (PeekType() != kArrayType) { - parsingError = true; - return; - } +void LottieParserImpl::parseMaskProperty(model::Layer *layer) +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } layer->extra()->mMasks.push_back(parseMaskObject()); } - if (!IsValid()) { - parsingError = true; - return; - } } -std::shared_ptr LottieParserImpl::parseMaskObject() +model::Mask *LottieParserImpl::parseMaskObject() { - std::shared_ptr sharedMask = std::make_shared(); - LOTMaskData * obj = sharedMask.get(); + auto obj = allocator().make(); - if (PeekType() != kObjectType) { - parsingError = true; - return sharedMask; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "inv")) { obj->mInv = GetBool(); } else if (0 == strcmp(key, "mode")) { const char *str = GetString(); - if (str == nullptr) { - parsingError = true; - return sharedMask; + if (!str) { + obj->mMode = model::Mask::Mode::None; + continue; } switch (str[0]) { case 'n': - obj->mMode = LOTMaskData::Mode::None; + obj->mMode = model::Mask::Mode::None; break; case 'a': - obj->mMode = LOTMaskData::Mode::Add; + obj->mMode = model::Mask::Mode::Add; break; case 's': - obj->mMode = LOTMaskData::Mode::Substarct; + obj->mMode = model::Mask::Mode::Substarct; break; case 'i': - obj->mMode = LOTMaskData::Mode::Intersect; + obj->mMode = model::Mask::Mode::Intersect; break; case 'f': - obj->mMode = LOTMaskData::Mode::Difference; + obj->mMode = model::Mask::Mode::Difference; break; default: - obj->mMode = LOTMaskData::Mode::None; + obj->mMode = model::Mask::Mode::None; break; } } else if (0 == strcmp(key, "pt")) { @@ -1146,43 +1150,31 @@ std::shared_ptr LottieParserImpl::parseMaskObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedMask; - } obj->mIsStatic = obj->mShape.isStatic() && obj->mOpacity.isStatic(); - return sharedMask; + return obj; } -void LottieParserImpl::parseShapesAttr(LOTLayerData *layer) { - if (PeekType() != kArrayType) { - parsingError = true; - return; - } +void LottieParserImpl::parseShapesAttr(model::Layer *layer) +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } parseObject(layer); } - if (!IsValid()) { - parsingError = true; - return; - } } -std::shared_ptr LottieParserImpl::parseObjectTypeAttr() { - if (PeekType() != kStringType) { - parsingError = true; - return nullptr; - } +model::Object *LottieParserImpl::parseObjectTypeAttr() +{ + RAPIDJSON_ASSERT(PeekType() == kStringType); const char *type = GetString(); if (0 == strcmp(type, "gr")) { return parseGroupObject(); } else if (0 == strcmp(type, "rc")) { return parseRectObject(); - } else if (0 == strcmp(type, "el")) { + } else if (0 == strcmp(type, "rd")) { + curLayerRef->mHasRoundedCorner = true; + return parseRoundedCorner(); + } else if (0 == strcmp(type, "el")) { return parseEllipseObject(); } else if (0 == strcmp(type, "tr")) { return parseTransformObject(); @@ -1217,86 +1209,84 @@ std::shared_ptr LottieParserImpl::parseObjectTypeAttr() { } } -void LottieParserImpl::parseObject(LOTGroupData *parent) +void LottieParserImpl::parseObject(model::Group *parent) { - if (PeekType() != kObjectType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "ty")) { auto child = parseObjectTypeAttr(); - if (child && !child->hidden()) parent->mChildren.push_back(child); + if (child && !child->hidden()) { + if (child->type() == model::Object::Type::RoundedCorner) { + updateRoundedCorner(parent, static_cast(child)); + } + parent->mChildren.push_back(child); + } } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; +} + +void LottieParserImpl::updateRoundedCorner(model::Group *group, model::RoundedCorner *rc) +{ + for(auto &e : group->mChildren) + { + if (e->type() == model::Object::Type::Rect) { + static_cast(e)->mRoundedCorner = rc; + if (!rc->isStatic()) { + e->setStatic(false); + group->setStatic(false); + //@TODO need to propagate. + } + } else if ( e->type() == model::Object::Type::Group) { + updateRoundedCorner(static_cast(e), rc); + } } } -std::shared_ptr LottieParserImpl::parseGroupObject() { - std::shared_ptr sharedGroup = - std::make_shared(); +model::Object *LottieParserImpl::parseGroupObject() +{ + auto group = allocator().make(); - LOTShapeGroupData *group = sharedGroup.get(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { group->setName(GetString()); } else if (0 == strcmp(key, "it")) { - if (PeekType() != kArrayType) { - parsingError = true; - return sharedGroup; - } + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return sharedGroup; - } - if (PeekType() != kObjectType) { - parsingError = true; - return sharedGroup; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); parseObject(group); } - if (!IsValid()) { - parsingError = true; - return sharedGroup; - } - if (!group->mChildren.empty() && group->mChildren.back()->type() == LOTData::Type::Transform) { - group->mTransform = std::static_pointer_cast( - group->mChildren.back()); + if (group->mChildren.back()->type() == + model::Object::Type::Transform) { + group->mTransform = + static_cast(group->mChildren.back()); group->mChildren.pop_back(); } } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedGroup; - } bool staticFlag = true; for (const auto &child : group->mChildren) { - staticFlag &= child.get()->isStatic(); + staticFlag &= child->isStatic(); } if (group->mTransform) { group->setStatic(staticFlag && group->mTransform->isStatic()); } - return sharedGroup; + return group; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/rect.json */ -std::shared_ptr LottieParserImpl::parseRectObject() +model::Rect *LottieParserImpl::parseRectObject() { - std::shared_ptr sharedRect = std::make_shared(); - LOTRectData * obj = sharedRect.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1315,23 +1305,39 @@ std::shared_ptr LottieParserImpl::parseRectObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedRect; - } obj->setStatic(obj->mPos.isStatic() && obj->mSize.isStatic() && obj->mRound.isStatic()); - return sharedRect; + return obj; +} + +/* + * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/rect.json + */ +model::RoundedCorner *LottieParserImpl::parseRoundedCorner() +{ + auto obj = allocator().make(); + + while (const char *key = NextObjectKey()) { + if (0 == strcmp(key, "nm")) { + obj->setName(GetString()); + } else if (0 == strcmp(key, "r")) { + parseProperty(obj->mRadius); + } else if (0 == strcmp(key, "hd")) { + obj->setHidden(GetBool()); + } else { + Skip(key); + } + } + obj->setStatic(obj->mRadius.isStatic()); + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/ellipse.json */ -std::shared_ptr LottieParserImpl::parseEllipseObject() +model::Ellipse *LottieParserImpl::parseEllipseObject() { - std::shared_ptr sharedEllipse = - std::make_shared(); - LOTEllipseData *obj = sharedEllipse.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1348,22 +1354,16 @@ std::shared_ptr LottieParserImpl::parseEllipseObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedEllipse; - } obj->setStatic(obj->mPos.isStatic() && obj->mSize.isStatic()); - return sharedEllipse; + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/shape.json */ -std::shared_ptr LottieParserImpl::parseShapeObject() +model::Path *LottieParserImpl::parseShapeObject() { - std::shared_ptr sharedShape = - std::make_shared(); - LOTShapeData *obj = sharedShape.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1381,23 +1381,17 @@ std::shared_ptr LottieParserImpl::parseShapeObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedShape; - } obj->setStatic(obj->mShape.isStatic()); - return sharedShape; + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/star.json */ -std::shared_ptr LottieParserImpl::parsePolystarObject() +model::Polystar *LottieParserImpl::parsePolystarObject() { - std::shared_ptr sharedPolystar = - std::make_shared(); - LOTPolystarData *obj = sharedPolystar.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1418,8 +1412,9 @@ std::shared_ptr LottieParserImpl::parsePolystarObject() parseProperty(obj->mRotation); } else if (0 == strcmp(key, "sy")) { int starType = GetInt(); - if (starType == 1) obj->mType = LOTPolystarData::PolyType::Star; - if (starType == 2) obj->mType = LOTPolystarData::PolyType::Polygon; + if (starType == 1) obj->mPolyType = model::Polystar::PolyType::Star; + if (starType == 2) + obj->mPolyType = model::Polystar::PolyType::Polygon; } else if (0 == strcmp(key, "d")) { obj->mDirection = GetInt(); } else if (0 == strcmp(key, "hd")) { @@ -1431,43 +1426,38 @@ std::shared_ptr LottieParserImpl::parsePolystarObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedPolystar; - } obj->setStatic( obj->mPos.isStatic() && obj->mPointCount.isStatic() && obj->mInnerRadius.isStatic() && obj->mInnerRoundness.isStatic() && obj->mOuterRadius.isStatic() && obj->mOuterRoundness.isStatic() && obj->mRotation.isStatic()); - return sharedPolystar; + return obj; } -LOTTrimData::TrimType LottieParserImpl::getTrimType() { - if (PeekType() != kNumberType) { - parsingError = true; - return LOTTrimData::TrimType::Individually; - } +model::Trim::TrimType LottieParserImpl::getTrimType() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 1: - return LOTTrimData::TrimType::Simultaneously; - case 2: - return LOTTrimData::TrimType::Individually; - default: - parsingError = true; - break; + case 1: + return model::Trim::TrimType::Simultaneously; + break; + case 2: + return model::Trim::TrimType::Individually; + break; + default: + RAPIDJSON_ASSERT(0); + return model::Trim::TrimType::Simultaneously; + break; } - return LOTTrimData::TrimType::Individually; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/trim.json */ -std::shared_ptr LottieParserImpl::parseTrimObject() +model::Trim *LottieParserImpl::parseTrimObject() { - std::shared_ptr sharedTrim = std::make_shared(); - LOTTrimData * obj = sharedTrim.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1489,16 +1479,12 @@ std::shared_ptr LottieParserImpl::parseTrimObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedTrim; - } obj->setStatic(obj->mStart.isStatic() && obj->mEnd.isStatic() && obj->mOffset.isStatic()); - return sharedTrim; + return obj; } -void LottieParserImpl::getValue(LOTRepeaterTransform &obj) +void LottieParserImpl::getValue(model::Repeater::Transform &obj) { EnterObject(); @@ -1519,16 +1505,13 @@ void LottieParserImpl::getValue(LOTRepeaterTransform &obj) Skip(key); } } - if (!IsValid()) { - parsingError = true; - } } -std::shared_ptr LottieParserImpl::parseReapeaterObject() +model::Repeater *LottieParserImpl::parseReapeaterObject() { - std::shared_ptr sharedRepeater = - std::make_shared(); - LOTRepeaterData *obj = sharedRepeater.get(); + auto obj = allocator().make(); + + obj->setContent(allocator().make()); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1537,11 +1520,11 @@ std::shared_ptr LottieParserImpl::parseReapeaterObject() parseProperty(obj->mCopies); float maxCopy = 0.0; if (!obj->mCopies.isStatic()) { - for (auto &keyFrame : obj->mCopies.animation().mKeyFrames) { - if (maxCopy < keyFrame.mValue.mStartValue) - maxCopy = keyFrame.mValue.mStartValue; - if (maxCopy < keyFrame.mValue.mEndValue) - maxCopy = keyFrame.mValue.mEndValue; + for (auto &keyFrame : obj->mCopies.animation().frames_) { + if (maxCopy < keyFrame.value_.start_) + maxCopy = keyFrame.value_.start_; + if (maxCopy < keyFrame.value_.end_) + maxCopy = keyFrame.value_.end_; } } else { maxCopy = obj->mCopies.value(); @@ -1560,52 +1543,48 @@ std::shared_ptr LottieParserImpl::parseReapeaterObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedRepeater; - } obj->setStatic(obj->mCopies.isStatic() && obj->mOffset.isStatic() && obj->mTransform.isStatic()); - return sharedRepeater; + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/transform.json */ -std::shared_ptr LottieParserImpl::parseTransformObject( - bool ddd) +model::Transform *LottieParserImpl::parseTransformObject(bool ddd) { - std::shared_ptr sharedTransform = - std::make_shared(); + auto objT = allocator().make(); - auto obj = std::make_unique(); - if (ddd) obj->m3D = std::make_unique(); + auto obj = allocator().make(); + if (ddd) { + obj->createExtraData(); + obj->mExtra->m3DData = true; + } while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { - sharedTransform->setName(GetString()); + objT->setName(GetString()); } else if (0 == strcmp(key, "a")) { parseProperty(obj->mAnchor); } else if (0 == strcmp(key, "p")) { EnterObject(); + bool separate = false; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "k")) { parsePropertyHelper(obj->mPosition); } else if (0 == strcmp(key, "s")) { - obj->mSeparate = GetBool(); - } else if (obj->mSeparate && (0 == strcmp(key, "x"))) { - parseProperty(obj->mX); - } else if (obj->mSeparate && (0 == strcmp(key, "y"))) { - parseProperty(obj->mY); + obj->createExtraData(); + obj->mExtra->mSeparate = GetBool(); + separate = true; + } else if (separate && (0 == strcmp(key, "x"))) { + parseProperty(obj->mExtra->mSeparateX); + } else if (separate && (0 == strcmp(key, "y"))) { + parseProperty(obj->mExtra->mSeparateY); } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedTransform; - } } else if (0 == strcmp(key, "r")) { parseProperty(obj->mRotation); } else if (0 == strcmp(key, "s")) { @@ -1613,42 +1592,39 @@ std::shared_ptr LottieParserImpl::parseTransformObject( } else if (0 == strcmp(key, "o")) { parseProperty(obj->mOpacity); } else if (0 == strcmp(key, "hd")) { - sharedTransform->setHidden(GetBool()); + objT->setHidden(GetBool()); } else if (0 == strcmp(key, "rx")) { - parseProperty(obj->m3D->mRx); + parseProperty(obj->mExtra->m3DRx); } else if (0 == strcmp(key, "ry")) { - parseProperty(obj->m3D->mRy); + parseProperty(obj->mExtra->m3DRy); } else if (0 == strcmp(key, "rz")) { - parseProperty(obj->m3D->mRz); + parseProperty(obj->mExtra->m3DRz); } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedTransform; - } - obj->mStatic = obj->mAnchor.isStatic() && obj->mPosition.isStatic() && - obj->mRotation.isStatic() && obj->mScale.isStatic() && - obj->mX.isStatic() && obj->mY.isStatic() && - obj->mOpacity.isStatic(); - if (obj->m3D) { - obj->mStatic = obj->mStatic && obj->m3D->mRx.isStatic() && - obj->m3D->mRy.isStatic() && obj->m3D->mRz.isStatic(); + bool isStatic = obj->mAnchor.isStatic() && obj->mPosition.isStatic() && + obj->mRotation.isStatic() && obj->mScale.isStatic() && + obj->mOpacity.isStatic(); + if (obj->mExtra) { + isStatic = isStatic && obj->mExtra->m3DRx.isStatic() && + obj->mExtra->m3DRy.isStatic() && + obj->mExtra->m3DRz.isStatic() && + obj->mExtra->mSeparateX.isStatic() && + obj->mExtra->mSeparateY.isStatic(); } - sharedTransform->set(std::move(obj)); + objT->set(obj, isStatic); - return sharedTransform; + return objT; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/fill.json */ -std::shared_ptr LottieParserImpl::parseFillObject() +model::Fill *LottieParserImpl::parseFillObject() { - std::shared_ptr sharedFill = std::make_shared(); - LOTFillData * obj = sharedFill.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1670,82 +1646,71 @@ std::shared_ptr LottieParserImpl::parseFillObject() Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedFill; - } obj->setStatic(obj->mColor.isStatic() && obj->mOpacity.isStatic()); - return sharedFill; + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/helpers/lineCap.json */ -CapStyle LottieParserImpl::getLineCap() { - if (PeekType() != kNumberType) { - parsingError = true; - return CapStyle::Square; - } +CapStyle LottieParserImpl::getLineCap() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 1: - return CapStyle::Flat; - break; - case 2: - return CapStyle::Round; - break; - default: - return CapStyle::Square; - break; + case 1: + return CapStyle::Flat; + break; + case 2: + return CapStyle::Round; + break; + default: + return CapStyle::Square; + break; } } -FillRule LottieParserImpl::getFillRule() { - if (PeekType() != kNumberType) { - parsingError = true; - return FillRule::Winding; - } +FillRule LottieParserImpl::getFillRule() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 1: - return FillRule::Winding; - break; - case 2: - return FillRule::EvenOdd; - break; - default: - return FillRule::Winding; - break; + case 1: + return FillRule::Winding; + break; + case 2: + return FillRule::EvenOdd; + break; + default: + return FillRule::Winding; + break; } } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/helpers/lineJoin.json */ -JoinStyle LottieParserImpl::getLineJoin() { - if (PeekType() != kNumberType) { - parsingError = true; - return JoinStyle::Bevel; - } +JoinStyle LottieParserImpl::getLineJoin() +{ + RAPIDJSON_ASSERT(PeekType() == kNumberType); switch (GetInt()) { - case 1: - return JoinStyle::Miter; - break; - case 2: - return JoinStyle::Round; - break; - default: - return JoinStyle::Bevel; - break; + case 1: + return JoinStyle::Miter; + break; + case 2: + return JoinStyle::Round; + break; + default: + return JoinStyle::Bevel; + break; } } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/stroke.json */ -std::shared_ptr LottieParserImpl::parseStrokeObject() { - std::shared_ptr sharedStroke = - std::make_shared(); - LOTStrokeData *obj = sharedStroke.get(); +model::Stroke *LottieParserImpl::parseStrokeObject() +{ + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1763,11 +1728,8 @@ std::shared_ptr LottieParserImpl::parseStrokeObject() { } else if (0 == strcmp(key, "lj")) { obj->mJoinStyle = getLineJoin(); } else if (0 == strcmp(key, "ml")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedStroke; - } - obj->mMeterLimit = GetDouble(); + RAPIDJSON_ASSERT(PeekType() == kNumberType); + obj->mMiterLimit = GetDouble(); } else if (0 == strcmp(key, "d")) { parseDashProperty(obj->mDash); } else if (0 == strcmp(key, "hd")) { @@ -1779,21 +1741,16 @@ std::shared_ptr LottieParserImpl::parseStrokeObject() { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return sharedStroke; - } obj->setStatic(obj->mColor.isStatic() && obj->mOpacity.isStatic() && - obj->mWidth.isStatic() && obj->mDash.mStatic); - return sharedStroke; + obj->mWidth.isStatic() && obj->mDash.isStatic()); + return obj; } -void LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key) { +void LottieParserImpl::parseGradientProperty(model::Gradient *obj, + const char * key) +{ if (0 == strcmp(key, "t")) { - if (PeekType() != kNumberType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kNumberType); obj->mGradientType = GetInt(); } else if (0 == strcmp(key, "o")) { parseProperty(obj->mOpacity); @@ -1816,10 +1773,6 @@ void LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key) Skip(nullptr); } } - if (!IsValid()) { - parsingError = true; - return; - } } else if (0 == strcmp(key, "hd")) { obj->setHidden(GetBool()); } else { @@ -1828,24 +1781,18 @@ void LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key) #endif Skip(key); } - if (!IsValid()) { - parsingError = true; - return; - } obj->setStatic( - obj->mOpacity.isStatic() && obj->mStartPoint.isStatic() && - obj->mEndPoint.isStatic() && obj->mHighlightAngle.isStatic() && - obj->mHighlightLength.isStatic() && obj->mGradient.isStatic()); + obj->mOpacity.isStatic() && obj->mStartPoint.isStatic() && + obj->mEndPoint.isStatic() && obj->mHighlightAngle.isStatic() && + obj->mHighlightLength.isStatic() && obj->mGradient.isStatic()); } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/gfill.json */ -std::shared_ptr LottieParserImpl::parseGFillObject() +model::GradientFill *LottieParserImpl::parseGFillObject() { - std::shared_ptr sharedGFill = - std::make_shared(); - LOTGFillData *obj = sharedGFill.get(); + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1856,62 +1803,33 @@ std::shared_ptr LottieParserImpl::parseGFillObject() parseGradientProperty(obj, key); } } - if (!IsValid()) { - parsingError = true; - } - return sharedGFill; + return obj; } -void LottieParserImpl::parseDashProperty(LOTDashProperty &dash) { - dash.mDashCount = 0; - dash.mStatic = true; - if (PeekType() != kArrayType) { - parsingError = true; - return; - } +void LottieParserImpl::parseDashProperty(model::Dash &dash) +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - if (PeekType() != kObjectType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "v")) { - parseProperty(dash.mDashArray[dash.mDashCount++]); + dash.mData.emplace_back(); + parseProperty(dash.mData.back()); } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return; - } - } - if (!IsValid()) { - parsingError = true; - return; - } - - // update the staic proprty - for (int i = 0; i < dash.mDashCount; i++) { - if (!dash.mDashArray[i].isStatic()) { - dash.mStatic = false; - break; - } } } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/shapes/gstroke.json */ -std::shared_ptr LottieParserImpl::parseGStrokeObject() { - std::shared_ptr sharedGStroke = - std::make_shared(); - LOTGStrokeData *obj = sharedGStroke.get(); +model::GradientStroke *LottieParserImpl::parseGStrokeObject() +{ + auto obj = allocator().make(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "nm")) { @@ -1923,50 +1841,31 @@ std::shared_ptr LottieParserImpl::parseGStrokeObject() { } else if (0 == strcmp(key, "lj")) { obj->mJoinStyle = getLineJoin(); } else if (0 == strcmp(key, "ml")) { - if (PeekType() != kNumberType) { - parsingError = true; - return sharedGStroke; - } - obj->mMeterLimit = GetDouble(); + RAPIDJSON_ASSERT(PeekType() == kNumberType); + obj->mMiterLimit = GetDouble(); } else if (0 == strcmp(key, "d")) { parseDashProperty(obj->mDash); } else { parseGradientProperty(obj, key); } } - if (!IsValid()) { - parsingError = true; - return sharedGStroke; - } obj->setStatic(obj->isStatic() && obj->mWidth.isStatic() && - obj->mDash.mStatic); - return sharedGStroke; + obj->mDash.isStatic()); + return obj; } -void LottieParserImpl::getValue(std::vector &v) { - if (PeekType() != kArrayType) { - parsingError = true; - return; - } +void LottieParserImpl::getValue(std::vector &v) +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - if (PeekType() != kArrayType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); VPointF pt; getValue(pt); v.push_back(pt); } - if (!IsValid()) { - parsingError = true; - return; - } } void LottieParserImpl::getValue(VPointF &pt) @@ -1977,19 +1876,11 @@ void LottieParserImpl::getValue(VPointF &pt) if (PeekType() == kArrayType) EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } const auto value = GetDouble(); if (i < 4) { val[i++] = value; } } - if (!IsValid()) { - parsingError = true; - return; - } - pt.setX(val[0]); pt.setY(val[1]); } @@ -2001,61 +1892,42 @@ void LottieParserImpl::getValue(float &val) if (NextArrayValue()) val = GetDouble(); // discard rest while (NextArrayValue()) { - if (parsingError) { - return; - } GetDouble(); } - if (!IsValid()) { - parsingError = true; - return; - } } else if (PeekType() == kNumberType) { val = GetDouble(); } else { - parsingError = true; + RAPIDJSON_ASSERT(0); } } -void LottieParserImpl::getValue(LottieColor &color) +void LottieParserImpl::getValue(model::Color &color) { float val[4] = {0.f}; int i = 0; if (PeekType() == kArrayType) EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } const auto value = GetDouble(); if (i < 4) { val[i++] = value; } } - if (!IsValid()) { - parsingError = true; - return; - } - color.r = val[2]; + + if (mColorFilter) mColorFilter(val[0], val[1], val[2]); + + color.r = val[0]; color.g = val[1]; - color.b = val[0]; - color.colorMap = colorMap; + color.b = val[2]; } -void LottieParserImpl::getValue(LottieGradient &grad) +void LottieParserImpl::getValue(model::Gradient::Data &grad) { if (PeekType() == kArrayType) EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } grad.mGradient.push_back(GetDouble()); } - if (!IsValid()) { - parsingError = true; - return; - } } void LottieParserImpl::getValue(int &val) @@ -2063,29 +1935,18 @@ void LottieParserImpl::getValue(int &val) if (PeekType() == kArrayType) { EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } val = GetInt(); } - if (!IsValid()) { - parsingError = true; - return; - } } else if (PeekType() == kNumberType) { val = GetInt(); } else { - parsingError = true; + RAPIDJSON_ASSERT(0); } } -void LottieParserImpl::getValue(LottieShapeData &obj) +void LottieParserImpl::parsePathInfo() { - std::vector inPoint; /* "i" */ - std::vector outPoint; /* "o" */ - std::vector vertices; /* "v" */ - std::vector points; - bool closed = false; + mPathInfo.reset(); /* * The shape object could be wrapped by a array @@ -2094,76 +1955,39 @@ void LottieParserImpl::getValue(LottieShapeData &obj) bool arrayWrapper = (PeekType() == kArrayType); if (arrayWrapper) EnterArray(); - if (PeekType() != kObjectType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "i")) { - getValue(inPoint); + getValue(mPathInfo.mInPoint); } else if (0 == strcmp(key, "o")) { - getValue(outPoint); + getValue(mPathInfo.mOutPoint); } else if (0 == strcmp(key, "v")) { - getValue(vertices); + getValue(mPathInfo.mVertices); } else if (0 == strcmp(key, "c")) { - closed = GetBool(); + mPathInfo.mClosed = GetBool(); } else { - parsingError = true; + RAPIDJSON_ASSERT(0); Skip(nullptr); } } - if (!IsValid()) { - parsingError = true; - return; - } // exit properly from the array if (arrayWrapper) NextArrayValue(); - // shape data could be empty. - if (inPoint.empty() || outPoint.empty() || vertices.empty()) return; - - /* - * Convert the AE shape format to - * list of bazier curves - * The final structure will be Move +size*Cubic + Cubic (if the path is - * closed one) - */ - if (inPoint.size() != outPoint.size() || - inPoint.size() != vertices.size()) { - vCritical << "The Shape data are corrupted"; - points = std::vector(); - } else { - int size = vertices.size(); - points.reserve(3 * size + 4); - points.push_back(vertices[0]); - for (int i = 1; i < size; i++) { - points.push_back(vertices[i - 1] + - outPoint[i - 1]); // CP1 = start + outTangent - points.push_back(vertices[i] + - inPoint[i]); // CP2 = end + inTangent - points.push_back(vertices[i]); // end point - } + mPathInfo.convert(); +} - if (closed) { - points.push_back(vertices[size - 1] + - outPoint[size - 1]); // CP1 = start + outTangent - points.push_back(vertices[0] + - inPoint[0]); // CP2 = end + inTangent - points.push_back(vertices[0]); // end point - } - } - obj.mPoints = std::move(points); - obj.mClosed = closed; +void LottieParserImpl::getValue(model::PathData &obj) +{ + parsePathInfo(); + obj.mPoints = mPathInfo.mResult; + obj.mClosed = mPathInfo.mClosed; } VPointF LottieParserImpl::parseInperpolatorPoint() { VPointF cp; - if (PeekType() != kObjectType) { - parsingError = true; - return cp; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "x")) { @@ -2173,36 +1997,28 @@ VPointF LottieParserImpl::parseInperpolatorPoint() getValue(cp.ry()); } } - if (!IsValid()) { - parsingError = true; - } return cp; } template -bool LottieParserImpl::parseKeyFrameValue(const char *, LOTKeyFrameValue &) -{ - return false; -} - -template <> -bool LottieParserImpl::parseKeyFrameValue(const char * key, - LOTKeyFrameValue &value) +bool LottieParserImpl::parseKeyFrameValue( + const char *key, model::Value &value) { if (0 == strcmp(key, "ti")) { - value.mPathKeyFrame = true; - getValue(value.mInTangent); + value.hasTangent_ = true; + getValue(value.inTangent_); } else if (0 == strcmp(key, "to")) { - value.mPathKeyFrame = true; - getValue(value.mOutTangent); + value.hasTangent_ = true; + getValue(value.outTangent_); } else { return false; } return true; } -std::shared_ptr LottieParserImpl::interpolator( - VPointF inTangent, VPointF outTangent, std::string key) +VInterpolator *LottieParserImpl::interpolator(VPointF inTangent, + VPointF outTangent, + std::string key) { if (key.empty()) { std::array temp; @@ -2212,34 +2028,35 @@ std::shared_ptr LottieParserImpl::interpolator( } auto search = mInterpolatorCache.find(key); + if (search != mInterpolatorCache.end()) { return search->second; - } else { - auto obj = std::make_shared( - VInterpolator(outTangent, inTangent)); - mInterpolatorCache[std::move(key)] = obj; - return obj; } + + auto obj = allocator().make(outTangent, inTangent); + mInterpolatorCache[std::move(key)] = obj; + return obj; } /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/properties/multiDimensionalKeyframed.json */ -template -void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) { +template +void LottieParserImpl::parseKeyFrame(model::KeyFrames &obj) +{ struct ParsedField { std::string interpolatorKey; - bool interpolator{false}; - bool value{false}; - bool hold{false}; - bool noEndValue{true}; + bool interpolator{false}; + bool value{false}; + bool hold{false}; + bool noEndValue{true}; }; EnterObject(); - ParsedField parsed; - LOTKeyFrame keyframe; - VPointF inTangent; - VPointF outTangent; + ParsedField parsed; + typename model::KeyFrames::Frame keyframe; + VPointF inTangent; + VPointF outTangent; while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "i")) { @@ -2248,32 +2065,23 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) { } else if (0 == strcmp(key, "o")) { outTangent = parseInperpolatorPoint(); } else if (0 == strcmp(key, "t")) { - keyframe.mStartFrame = GetDouble(); + keyframe.start_ = GetDouble(); } else if (0 == strcmp(key, "s")) { parsed.value = true; - getValue(keyframe.mValue.mStartValue); + getValue(keyframe.value_.start_); continue; } else if (0 == strcmp(key, "e")) { parsed.noEndValue = false; - getValue(keyframe.mValue.mEndValue); + getValue(keyframe.value_.end_); continue; } else if (0 == strcmp(key, "n")) { if (PeekType() == kStringType) { parsed.interpolatorKey = GetString(); } else { - if (PeekType() != kArrayType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - if (PeekType() != kStringType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kStringType); if (parsed.interpolatorKey.empty()) { parsed.interpolatorKey = GetString(); } else { @@ -2281,13 +2089,9 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) { GetString(); } } - if (!IsValid()) { - parsingError = true; - return; - } } continue; - } else if (parseKeyFrameValue(key, keyframe.mValue)) { + } else if (parseKeyFrameValue(key, keyframe.value_)) { continue; } else if (0 == strcmp(key, "h")) { parsed.hold = GetInt(); @@ -2299,29 +2103,25 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) { Skip(key); } } - if (!IsValid()) { - parsingError = true; - return; - } - if (!obj.mKeyFrames.empty()) { + auto &list = obj.frames_; + if (!list.empty()) { // update the endFrame value of current keyframe - obj.mKeyFrames.back().mEndFrame = keyframe.mStartFrame; + list.back().end_ = keyframe.start_; // if no end value provided, copy start value to previous frame if (parsed.value && parsed.noEndValue) { - obj.mKeyFrames.back().mValue.mEndValue = - keyframe.mValue.mStartValue; + list.back().value_.end_ = keyframe.value_.start_; } } if (parsed.hold) { - keyframe.mValue.mEndValue = keyframe.mValue.mStartValue; - keyframe.mEndFrame = keyframe.mStartFrame; - obj.mKeyFrames.push_back(keyframe); + keyframe.value_.end_ = keyframe.value_.start_; + keyframe.end_ = keyframe.start_; + list.push_back(std::move(keyframe)); } else if (parsed.interpolator) { - keyframe.mInterpolator = interpolator( - inTangent, outTangent, std::move(parsed.interpolatorKey)); - obj.mKeyFrames.push_back(keyframe); + keyframe.interpolator_ = interpolator( + inTangent, outTangent, std::move(parsed.interpolatorKey)); + list.push_back(std::move(keyframe)); } else { // its the last frame discard. } @@ -2334,29 +2134,20 @@ void LottieParserImpl::parseKeyFrame(LOTAnimInfo &obj) { /* * https://github.com/airbnb/lottie-web/blob/master/docs/json/properties/shape.json */ -void LottieParserImpl::parseShapeProperty(LOTAnimatable &obj) { +void LottieParserImpl::parseShapeProperty(model::Property &obj) +{ EnterObject(); while (const char *key = NextObjectKey()) { if (0 == strcmp(key, "k")) { if (PeekType() == kArrayType) { EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } - if (PeekType() != kObjectType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kObjectType); parseKeyFrame(obj.animation()); } - if (!IsValid()) { - parsingError = true; - return; - } } else { if (!obj.isStatic()) { - parsingError = true; + RAPIDJSON_ASSERT(false); st_ = kError; return; } @@ -2369,31 +2160,24 @@ void LottieParserImpl::parseShapeProperty(LOTAnimatable &obj) { Skip(nullptr); } } - if (!IsValid()) { - parsingError = true; - } + obj.cache(); } -template -void LottieParserImpl::parsePropertyHelper(LOTAnimatable &obj) { +template +void LottieParserImpl::parsePropertyHelper(model::Property &obj) +{ if (PeekType() == kNumberType) { if (!obj.isStatic()) { - parsingError = true; + RAPIDJSON_ASSERT(false); st_ = kError; return; } /*single value property with no animation*/ getValue(obj.value()); } else { - if (PeekType() != kArrayType) { - parsingError = true; - return; - } + RAPIDJSON_ASSERT(PeekType() == kArrayType); EnterArray(); while (NextArrayValue()) { - if (parsingError) { - return; - } /* property with keyframe info*/ if (PeekType() == kObjectType) { parseKeyFrame(obj.animation()); @@ -2404,25 +2188,19 @@ void LottieParserImpl::parsePropertyHelper(LOTAnimatable &obj) { * or array of object without entering the array * thats why this hack is there */ - if (PeekType() != kNumberType) { - parsingError = true; - return; - } - /*multi value property with no animation*/ + RAPIDJSON_ASSERT(PeekType() == kNumberType); if (!obj.isStatic()) { - parsingError = true; + RAPIDJSON_ASSERT(false); st_ = kError; return; } + /*multi value property with no animation*/ getValue(obj.value()); /*break here as we already reached end of array*/ break; } } - if (!IsValid()) { - parsingError = true; - return; - } + obj.cache(); } } @@ -2430,29 +2208,23 @@ void LottieParserImpl::parsePropertyHelper(LOTAnimatable &obj) { * https://github.com/airbnb/lottie-web/tree/master/docs/json/properties */ template -void LottieParserImpl::parseProperty(LOTAnimatable &obj) +void LottieParserImpl::parseProperty(model::Property &obj) { EnterObject(); while (const char *key = NextObjectKey()) { - if (parsingError) { - return; - } if (0 == strcmp(key, "k")) { parsePropertyHelper(obj); } else { Skip(key); } } - if (!IsValid()) { - parsingError = true; - } } -#ifdef DEBUG_PRINT_TREE +#ifdef LOTTIE_DUMP_TREE_SUPPORT -class LOTDataInspector { +class ObjectInspector { public: - void visit(LOTCompositionData *obj, std::string level) + void visit(model::Composition *obj, std::string level) { vDebug << " { " << level << "Composition:: a: " << !obj->isStatic() << ", v: " << obj->mVersion << ", stFm: " << obj->startFrame() @@ -2460,11 +2232,11 @@ class LOTDataInspector { << ", W: " << obj->size().width() << ", H: " << obj->size().height() << "\n"; level.append("\t"); - visit(obj->mRootLayer.get(), level); + visit(obj->mRootLayer, level); level.erase(level.end() - 1, level.end()); vDebug << " } " << level << "Composition End\n"; } - void visit(LOTLayerData *obj, std::string level) + void visit(model::Layer *obj, std::string level) { vDebug << level << "{ " << layerType(obj->mLayerType) << ", name: " << obj->name() << ", id:" << obj->mId @@ -2473,101 +2245,105 @@ class LOTDataInspector { << ", mask:" << obj->hasMask() << ", inFm:" << obj->mInFrame << ", outFm:" << obj->mOutFrame << ", stFm:" << obj->mStartFrame << ", ts:" << obj->mTimeStreatch << ", ao:" << obj->autoOrient() - << ", ddd:" << (obj->mTransform ? obj->mTransform->ddd() : false) << ", W:" << obj->layerSize().width() << ", H:" << obj->layerSize().height(); - if (obj->mLayerType == LayerType::Image) + if (obj->mLayerType == model::Layer::Type::Image) vDebug << level << "\t{ " << "ImageInfo:" - << " W :" << obj->mAsset->mWidth - << ", H :" << obj->mAsset->mHeight << " }" + << " W :" << obj->extra()->mAsset->mWidth + << ", H :" << obj->extra()->mAsset->mHeight << " }" << "\n"; else { vDebug << level; } - visitChildren(static_cast(obj), level); + visitChildren(static_cast(obj), level); vDebug << level << "} " << layerType(obj->mLayerType).c_str() << ", id: " << obj->mId << "\n"; } - void visitChildren(LOTGroupData *obj, std::string level) + void visitChildren(model::Group *obj, std::string level) { level.append("\t"); - for (const auto &child : obj->mChildren) visit(child.get(), level); - if (obj->mTransform) visit(obj->mTransform.get(), level); + for (const auto &child : obj->mChildren) visit(child, level); + if (obj->mTransform) visit(obj->mTransform, level); } - void visit(LOTData *obj, std::string level) + void visit(model::Object *obj, std::string level) { - switch (obj->mType) { - case LOTData::Type::Repeater: { - auto r = static_cast(obj); + switch (obj->type()) { + case model::Object::Type::Repeater: { + auto r = static_cast(obj); vDebug << level << "{ Repeater: name: " << obj->name() << " , a:" << !obj->isStatic() << ", copies:" << r->maxCopies() << ", offset:" << r->offset(0); - visitChildren(r->mContent.get(), level); + visitChildren(r->mContent, level); vDebug << level << "} Repeater"; break; } - case LOTData::Type::ShapeGroup: { - vDebug << level << "{ ShapeGroup: name: " << obj->name() + case model::Object::Type::Group: { + vDebug << level << "{ Group: name: " << obj->name() << " , a:" << !obj->isStatic(); - visitChildren(static_cast(obj), level); - vDebug << level << "} ShapeGroup"; + visitChildren(static_cast(obj), level); + vDebug << level << "} Group"; break; } - case LOTData::Type::Layer: { - visit(static_cast(obj), level); + case model::Object::Type::Layer: { + visit(static_cast(obj), level); break; } - case LOTData::Type::Trim: { + case model::Object::Type::Trim: { vDebug << level << "{ Trim: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Rect: { + case model::Object::Type::Rect: { vDebug << level << "{ Rect: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Ellipse: { + case model::Object::Type::RoundedCorner: { + vDebug << level << "{ RoundedCorner: name: " << obj->name() + << " , a:" << !obj->isStatic() << " }"; + break; + } + case model::Object::Type::Ellipse: { vDebug << level << "{ Ellipse: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Shape: { + case model::Object::Type::Path: { vDebug << level << "{ Shape: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Polystar: { + case model::Object::Type::Polystar: { vDebug << level << "{ Polystar: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Transform: { + case model::Object::Type::Transform: { vDebug << level << "{ Transform: name: " << obj->name() << " , a: " << !obj->isStatic() << " }"; break; } - case LOTData::Type::Stroke: { + case model::Object::Type::Stroke: { vDebug << level << "{ Stroke: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::GStroke: { + case model::Object::Type::GStroke: { vDebug << level << "{ GStroke: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::Fill: { + case model::Object::Type::Fill: { vDebug << level << "{ Fill: name: " << obj->name() << " , a:" << !obj->isStatic() << " }"; break; } - case LOTData::Type::GFill: { - auto f = static_cast(obj); + case model::Object::Type::GFill: { + auto f = static_cast(obj); vDebug << level << "{ GFill: name: " << obj->name() << " , a:" << !f->isStatic() << ", ty:" << f->mGradientType << ", s:" << f->mStartPoint.value(0) @@ -2579,22 +2355,22 @@ class LOTDataInspector { } } - std::string matteType(MatteType type) + std::string matteType(model::MatteType type) { switch (type) { - case MatteType::None: + case model::MatteType::None: return "Matte::None"; break; - case MatteType::Alpha: + case model::MatteType::Alpha: return "Matte::Alpha"; break; - case MatteType::AlphaInv: + case model::MatteType::AlphaInv: return "Matte::AlphaInv"; break; - case MatteType::Luma: + case model::MatteType::Luma: return "Matte::Luma"; break; - case MatteType::LumaInv: + case model::MatteType::LumaInv: return "Matte::LumaInv"; break; default: @@ -2602,25 +2378,25 @@ class LOTDataInspector { break; } } - std::string layerType(LayerType type) + std::string layerType(model::Layer::Type type) { switch (type) { - case LayerType::Precomp: + case model::Layer::Type::Precomp: return "Layer::Precomp"; break; - case LayerType::Null: + case model::Layer::Type::Null: return "Layer::Null"; break; - case LayerType::Shape: + case model::Layer::Type::Shape: return "Layer::Shape"; break; - case LayerType::Solid: + case model::Layer::Type::Solid: return "Layer::Solid"; break; - case LayerType::Image: + case model::Layer::Type::Image: return "Layer::Image"; break; - case LayerType::Text: + case model::Layer::Type::Text: return "Layer::Text"; break; default: @@ -2632,38 +2408,30 @@ class LOTDataInspector { #endif -LottieParser::~LottieParser() -{ - delete d; -} - -LottieParser::LottieParser(char *str, const char *dir_path, std::map *colorReplacement) - : d(new LottieParserImpl(str, dir_path, colorReplacement)) +std::shared_ptr model::parse(char * str, + std::string dir_path, + model::ColorFilter filter) { - d->parseComposition(); - if (d->hasParsingError()) { - parsingError = true; - } -} - -std::shared_ptr LottieParser::model() -{ - if (!d->composition()) return nullptr; - - std::shared_ptr model = std::make_shared(); - model->mRoot = d->composition(); - model->mRoot->processRepeaterObjects(); - -#ifdef DEBUG_PRINT_TREE - LOTDataInspector inspector; - inspector.visit(model->mRoot.get(), ""); + LottieParserImpl obj(str, std::move(dir_path), std::move(filter)); + + if (obj.VerifyType()) { + obj.parseComposition(); + auto composition = obj.composition(); + if (composition) { + composition->processRepeaterObjects(); + composition->updateStats(); + +#ifdef LOTTIE_DUMP_TREE_SUPPORT + ObjectInspector inspector; + inspector.visit(composition.get(), ""); #endif - return model; -} + return composition; + } + } -bool LottieParser::hasParsingError() { - return parsingError; + vWarning << "Input data is not Lottie format!"; + return {}; } RAPIDJSON_DIAG_POP diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieparser.h b/AXrLottie/src/main/cpp/src/lottie/lottieparser.h deleted file mode 100755 index 3e24981..0000000 --- a/AXrLottie/src/main/cpp/src/lottie/lottieparser.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOTTIEPARSER_H -#define LOTTIEPARSER_H - -#include "lottiemodel.h" -#include - -class LottieParserImpl; -class LottieParser { -public: - ~LottieParser(); - LottieParser(char* str, const char *dir_path, std::map *colorReplacement); - std::shared_ptr model(); - bool hasParsingError(); -private: - LottieParserImpl *d; - bool parsingError = false; -}; - -#endif // LOTTIEPARSER_H diff --git a/AXrLottie/src/main/cpp/src/lottie/lottieproxymodel.h b/AXrLottie/src/main/cpp/src/lottie/lottieproxymodel.h deleted file mode 100755 index 6dbe75d..0000000 --- a/AXrLottie/src/main/cpp/src/lottie/lottieproxymodel.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef LOTTIEPROXYMODEL_H -#define LOTTIEPROXYMODEL_H - -#include -#include -#include -#include "lottiemodel.h" -#include "rlottie.h" - -// Naive way to implement std::variant -// refactor it when we move to c++17 -// users should make sure proper combination -// of id and value are passed while creating the object. -class LOTVariant -{ -public: - using ValueFunc = std::function; - using ColorFunc = std::function; - using PointFunc = std::function; - using SizeFunc = std::function; - - LOTVariant(rlottie::Property prop, const ValueFunc &v):mPropery(prop), mTag(Value) - { - construct(impl.valueFunc, v); - } - - LOTVariant(rlottie::Property prop, ValueFunc &&v):mPropery(prop), mTag(Value) - { - moveConstruct(impl.valueFunc, std::move(v)); - } - - LOTVariant(rlottie::Property prop, const ColorFunc &v):mPropery(prop), mTag(Color) - { - construct(impl.colorFunc, v); - } - - LOTVariant(rlottie::Property prop, ColorFunc &&v):mPropery(prop), mTag(Color) - { - moveConstruct(impl.colorFunc, std::move(v)); - } - - LOTVariant(rlottie::Property prop, const PointFunc &v):mPropery(prop), mTag(Point) - { - construct(impl.pointFunc, v); - } - - LOTVariant(rlottie::Property prop, PointFunc &&v):mPropery(prop), mTag(Point) - { - moveConstruct(impl.pointFunc, std::move(v)); - } - - LOTVariant(rlottie::Property prop, const SizeFunc &v):mPropery(prop), mTag(Size) - { - construct(impl.sizeFunc, v); - } - - LOTVariant(rlottie::Property prop, SizeFunc &&v):mPropery(prop), mTag(Size) - { - moveConstruct(impl.sizeFunc, std::move(v)); - } - - rlottie::Property property() const { return mPropery; } - - const ColorFunc& color() const - { - assert(mTag == Color); - return impl.colorFunc; - } - - const ValueFunc& value() const - { - assert(mTag == Value); - return impl.valueFunc; - } - - const PointFunc& point() const - { - assert(mTag == Point); - return impl.pointFunc; - } - - const SizeFunc& size() const - { - assert(mTag == Size); - return impl.sizeFunc; - } - - LOTVariant() = default; - ~LOTVariant() noexcept {Destroy();} - LOTVariant(const LOTVariant& other) { Copy(other);} - LOTVariant(LOTVariant&& other) noexcept { Move(std::move(other));} - LOTVariant& operator=(LOTVariant&& other) { Destroy(); Move(std::move(other)); return *this;} - LOTVariant& operator=(const LOTVariant& other) { Destroy(); Copy(other); return *this;} -private: - template - void construct(T& member, const T& val) - { - new (&member) T(val); - } - - template - void moveConstruct(T& member, T&& val) - { - new (&member) T(std::move(val)); - } - - void Move(LOTVariant&& other) - { - switch (other.mTag) { - case Type::Value: - moveConstruct(impl.valueFunc, std::move(other.impl.valueFunc)); - break; - case Type::Color: - moveConstruct(impl.colorFunc, std::move(other.impl.colorFunc)); - break; - case Type::Point: - moveConstruct(impl.pointFunc, std::move(other.impl.pointFunc)); - break; - case Type::Size: - moveConstruct(impl.sizeFunc, std::move(other.impl.sizeFunc)); - break; - default: - break; - } - mTag = other.mTag; - mPropery = other.mPropery; - other.mTag = MonoState; - } - - void Copy(const LOTVariant& other) - { - switch (other.mTag) { - case Type::Value: - construct(impl.valueFunc, other.impl.valueFunc); - break; - case Type::Color: - construct(impl.colorFunc, other.impl.colorFunc); - break; - case Type::Point: - construct(impl.pointFunc, other.impl.pointFunc); - break; - case Type::Size: - construct(impl.sizeFunc, other.impl.sizeFunc); - break; - default: - break; - } - mTag = other.mTag; - mPropery = other.mPropery; - } - - void Destroy() - { - switch(mTag) { - case MonoState: { - break; - } - case Value: { - impl.valueFunc.~ValueFunc(); - break; - } - case Color: { - impl.colorFunc.~ColorFunc(); - break; - } - case Point: { - impl.pointFunc.~PointFunc(); - break; - } - case Size: { - impl.sizeFunc.~SizeFunc(); - break; - } - } - } - - enum Type {MonoState, Value, Color, Point , Size}; - rlottie::Property mPropery; - Type mTag{MonoState}; - union details{ - ColorFunc colorFunc; - ValueFunc valueFunc; - PointFunc pointFunc; - SizeFunc sizeFunc; - details(){} - ~details(){} - }impl; -}; - -class LOTFilter -{ -public: - void addValue(LOTVariant &value) - { - uint index = static_cast(value.property()); - if (mBitset.test(index)) { - std::replace_if(mFilters.begin(), - mFilters.end(), - [&value](const LOTVariant &e) {return e.property() == value.property();}, - value); - } else { - mBitset.set(index); - mFilters.push_back(value); - } - } - - void removeValue(LOTVariant &value) - { - uint index = static_cast(value.property()); - if (mBitset.test(index)) { - mBitset.reset(index); - mFilters.erase(std::remove_if(mFilters.begin(), - mFilters.end(), - [&value](const LOTVariant &e) {return e.property() == value.property();}), - mFilters.end()); - } - } - bool hasFilter(rlottie::Property prop) const - { - return mBitset.test(static_cast(prop)); - } - LottieColor color(rlottie::Property prop, int frame) const - { - rlottie::FrameInfo info(frame); - rlottie::Color col = data(prop).color()(info); - return LottieColor(col.r(), col.g(), col.b(), nullptr); - } - float opacity(rlottie::Property prop, int frame) const - { - rlottie::FrameInfo info(frame); - float val = data(prop).value()(info); - return val/100; - } - float value(rlottie::Property prop, int frame) const - { - rlottie::FrameInfo info(frame); - return data(prop).value()(info); - } - VPointF point(rlottie::Property prop, int frame) const - { - rlottie::FrameInfo info(frame); - rlottie::Point pt = data(prop).point()(info); - return VPointF(pt.x(), pt.y()); - } - VSize scale(rlottie::Property prop, int frame) const - { - rlottie::FrameInfo info(frame); - rlottie::Size sz = data(prop).size()(info); - return VSize(sz.w(), sz.h()); - } -private: - const LOTVariant& data(rlottie::Property prop) const - { - auto result = std::find_if(mFilters.begin(), - mFilters.end(), - [prop](const LOTVariant &e){return e.property() == prop;}); - return *result; - } - std::bitset<32> mBitset{0}; - std::vector mFilters; -}; - -template -class LOTProxyModel -{ -public: - LOTProxyModel(T *model): _modelData(model) {} - LOTFilter& filter() {return mFilter;} - const std::string & name() const {return _modelData->name();} - LottieColor color(int frame) const - { - if (mFilter.hasFilter(rlottie::Property::Color)) { - return mFilter.color(rlottie::Property::Color, frame); - } - return _modelData->color(frame); - } - float opacity(int frame) const - { - if (mFilter.hasFilter(rlottie::Property::StrokeOpacity)) { - return mFilter.opacity(rlottie::Property::StrokeOpacity, frame); - } - return _modelData->opacity(frame); - } - float strokeWidth(int frame) const - { - if (mFilter.hasFilter(rlottie::Property::StrokeWidth)) { - return mFilter.value(rlottie::Property::StrokeWidth, frame); - } - return _modelData->strokeWidth(frame); - } - VMatrix transform(int frame) const { - VMatrix mS, mR, mT; - if (this->hasFilter(rlottie::Property::TrScale)) { - VSize s = this->filter()->scale(rlottie::Property::TrScale, frame); - mS.scale(s.width() / 100.0, s.height() / 100.0); - } - if (this->hasFilter(rlottie::Property::TrRotation)) { - mR.rotate(this->filter()->value(rlottie::Property::TrRotation, frame)); - } - if (this->hasFilter(rlottie::Property::TrPosition)) { - mT.translate(this->filter()->point(rlottie::Property::TrPosition, frame)); - } - return mS * mR * mT; - } - - float meterLimit() const {return _modelData->meterLimit();} - CapStyle capStyle() const {return _modelData->capStyle();} - JoinStyle joinStyle() const {return _modelData->joinStyle();} - bool hasDashInfo() const { return _modelData->hasDashInfo();} - int getDashInfo(int frameNo, float *array) const {return _modelData->getDashInfo(frameNo, array);} - -private: - T *_modelData; - LOTFilter mFilter; -}; - -template <> -class LOTProxyModel -{ -public: - LOTProxyModel(LOTFillData *model): _modelData(model) {} - LOTFilter& filter() {return mFilter;} - const std::string & name() const {return _modelData->name();} - LottieColor color(int frame) const - { - if (mFilter.hasFilter(rlottie::Property::Color)) { - return mFilter.color(rlottie::Property::Color, frame); - } - return _modelData->color(frame); - } - float opacity(int frame) const - { - if (mFilter.hasFilter(rlottie::Property::FillOpacity)) { - return mFilter.opacity(rlottie::Property::FillOpacity, frame); - } - return _modelData->opacity(frame); - } - FillRule fillRule() const {return _modelData->fillRule();} - - VMatrix transform(int frame) const { - VMatrix mS= VMatrix(), mR = VMatrix(), mT= VMatrix(); - if (mFilter.hasFilter(rlottie::Property::TrScale)) { - VSize s = mFilter.scale(rlottie::Property::TrScale, frame); - mS.scale(s.width() / 100.0, s.height() / 100.0); - } - if (mFilter.hasFilter(rlottie::Property::TrRotation)) { - mR.rotate(mFilter.value(rlottie::Property::TrRotation, frame)); - }else{ - mR.rotate(98); - } - if (mFilter.hasFilter(rlottie::Property::TrPosition)) { - mT.translate(mFilter.point(rlottie::Property::TrPosition, frame)); - } - return mR; - //return mS * mR * mT; - } - -private: - LOTFillData *_modelData; - LOTFilter mFilter; -}; - -#endif // LOTTIEITEM_H diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/allocators.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/allocators.h old mode 100755 new mode 100644 index cc67c89..0b8f5e1 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/allocators.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/allocators.h @@ -77,19 +77,19 @@ class CrtAllocator { static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. - return std::malloc(size); + return RAPIDJSON_MALLOC(size); else return NULL; // standardize to returning NULL. } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; if (newSize == 0) { - std::free(originalPtr); + RAPIDJSON_FREE(originalPtr); return NULL; } - return std::realloc(originalPtr, newSize); + return RAPIDJSON_REALLOC(originalPtr, newSize); } - static void Free(void *ptr) { std::free(ptr); } + static void Free(void *ptr) { RAPIDJSON_FREE(ptr); } }; /////////////////////////////////////////////////////////////////////////////// diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/cursorstreamwrapper.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/cursorstreamwrapper.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/document.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/document.h old mode 100755 new mode 100644 index d1b90eb..68aaae7 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/document.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/document.h @@ -24,6 +24,9 @@ #include "encodedstream.h" #include // placement new #include +#ifdef __cpp_lib_three_way_comparison +#include +#endif RAPIDJSON_DIAG_PUSH #ifdef __clang__ @@ -56,6 +59,48 @@ class GenericValue; template class GenericDocument; +/*! \def RAPIDJSON_DEFAULT_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default allocator. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_ALLOCATOR +#define RAPIDJSON_DEFAULT_ALLOCATOR MemoryPoolAllocator +#endif + +/*! \def RAPIDJSON_DEFAULT_STACK_ALLOCATOR + \ingroup RAPIDJSON_CONFIG + \brief Allows to choose default stack allocator for Document. + + User can define this to use CrtAllocator or MemoryPoolAllocator. +*/ +#ifndef RAPIDJSON_DEFAULT_STACK_ALLOCATOR +#define RAPIDJSON_DEFAULT_STACK_ALLOCATOR CrtAllocator +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultObjectCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY +// number of objects that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY 16 +#endif + +/*! \def RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User defined kDefaultArrayCapacity value. + + User can define this as any natural number. +*/ +#ifndef RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY +// number of array elements that rapidjson::Value allocates memory for by default +#define RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY 16 +#endif + //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. @@ -63,15 +108,45 @@ class GenericDocument; https://code.google.com/p/rapidjson/issues/detail?id=64 */ template -struct GenericMember { +class GenericMember { +public: GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericMember(GenericMember&& rhs) RAPIDJSON_NOEXCEPT + : name(std::move(rhs.name)), + value(std::move(rhs.value)) + { + } + + //! Move assignment in C++11 + GenericMember& operator=(GenericMember&& rhs) RAPIDJSON_NOEXCEPT { + return *this = static_cast(rhs); + } +#endif + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. Its name and value will become a null value after assignment. + */ + GenericMember& operator=(GenericMember& rhs) RAPIDJSON_NOEXCEPT { + if (RAPIDJSON_LIKELY(this != &rhs)) { + name = rhs.name; + value = rhs.value; + } + return *this; + } + // swap() for std::sort() and other potential use in STL. friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { a.name.Swap(b.name); a.value.Swap(b.value); } + +private: + //! Copy constructor is not permitted. + GenericMember(const GenericMember& rhs); }; /////////////////////////////////////////////////////////////////////////////// @@ -175,12 +250,16 @@ class GenericMemberIterator { //! @name relations //@{ - bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } - bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } - bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } - bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } - bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } - bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } + template bool operator==(const GenericMemberIterator& that) const { return ptr_ == that.ptr_; } + template bool operator!=(const GenericMemberIterator& that) const { return ptr_ != that.ptr_; } + template bool operator<=(const GenericMemberIterator& that) const { return ptr_ <= that.ptr_; } + template bool operator>=(const GenericMemberIterator& that) const { return ptr_ >= that.ptr_; } + template bool operator< (const GenericMemberIterator& that) const { return ptr_ < that.ptr_; } + template bool operator> (const GenericMemberIterator& that) const { return ptr_ > that.ptr_; } + +#ifdef __cpp_lib_three_way_comparison + template std::strong_ordering operator<=>(const GenericMemberIterator& that) const { return ptr_ <=> that.ptr_; } +#endif //@} //! @name dereference @@ -205,17 +284,17 @@ class GenericMemberIterator { // class-based member iterator implementation disabled, use plain pointers template -struct GenericMemberIterator; +class GenericMemberIterator; //! non-const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template -struct GenericMemberIterator { +class GenericMemberIterator { //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; @@ -574,7 +653,7 @@ template class GenericObject; \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ -template > +template class GenericValue { public: //! Name-value pair in an object. @@ -1939,8 +2018,8 @@ class GenericValue { kTypeMask = 0x07 }; - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; + static const SizeType kDefaultArrayCapacity = RAPIDJSON_VALUE_DEFAULT_ARRAY_CAPACITY; + static const SizeType kDefaultObjectCapacity = RAPIDJSON_VALUE_DEFAULT_OBJECT_CAPACITY; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION @@ -2120,7 +2199,7 @@ typedef GenericValue > Value; \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ -template , typename StackAllocator = CrtAllocator> +template class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. @@ -2505,6 +2584,7 @@ class GenericDocument : public GenericValue { //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; + //! Helper class for accessing Value of array type. /*! Instance of this helper class is obtained by \c GenericValue::GetArray(). diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/encodedstream.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/encodedstream.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/encodings.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/encodings.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/error/en.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/error/en.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/error/error.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/error/error.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/filereadstream.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/filereadstream.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/filewritestream.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/filewritestream.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/fwd.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/fwd.h old mode 100755 new mode 100644 index e8104e8..b74a2b8 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/fwd.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/fwd.h @@ -102,7 +102,7 @@ class PrettyWriter; // document.h template -struct GenericMember; +class GenericMember; template class GenericMemberIterator; diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/biginteger.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/biginteger.h old mode 100755 new mode 100644 index a31c8a8..8eb87c7 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/biginteger.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/biginteger.h @@ -17,7 +17,7 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64) #include // for _umul128 #pragma intrinsic(_umul128) #endif diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/clzll.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/clzll.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/diyfp.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/diyfp.h old mode 100755 new mode 100644 index b6c2cf5..8f7d853 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/diyfp.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/diyfp.h @@ -20,11 +20,11 @@ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include "clzll.h" #include #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include -#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) #endif @@ -100,22 +100,8 @@ struct DiyFp { } DiyFp Normalize() const { - RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737 -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) && __GNUC__ >= 4 - int s = __builtin_clzll(f); + int s = static_cast(clzll(f)); return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & (static_cast(1) << 63))) { - res.f <<= 1; - res.e--; - } - return res; -#endif } DiyFp NormalizeBoundary() const { diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/dtoa.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/dtoa.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/ieee754.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/ieee754.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/itoa.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/itoa.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/meta.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/meta.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/pow10.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/pow10.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/regex.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/regex.h old mode 100755 new mode 100644 index 16e3559..af7e06d --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/regex.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/regex.h @@ -23,7 +23,6 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) -RAPIDJSON_DIAG_OFF(implicit-fallthrough) #elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated @@ -32,9 +31,6 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 7 -RAPIDJSON_DIAG_OFF(implicit-fallthrough) -#endif #endif #ifndef RAPIDJSON_REGEX_VERBOSE @@ -291,6 +287,7 @@ class GenericRegex { if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: // Pattern character PushOperand(operandStack, codepoint); @@ -520,6 +517,7 @@ class GenericRegex { else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default + RAPIDJSON_DELIBERATE_FALLTHROUGH; default: switch (step) { @@ -529,6 +527,7 @@ class GenericRegex { break; } // fall through to step 0 for other characters + RAPIDJSON_DELIBERATE_FALLTHROUGH; case 0: { diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/stack.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/stack.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strfunc.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strfunc.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strtod.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/strtod.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/swap.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/internal/swap.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/istreamwrapper.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/istreamwrapper.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/memorybuffer.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/memorybuffer.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/memorystream.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/memorystream.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/inttypes.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/inttypes.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/stdint.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/msinttypes/stdint.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/ostreamwrapper.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/ostreamwrapper.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/pointer.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/pointer.h old mode 100755 new mode 100644 index 063abab..b8143b6 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/pointer.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/pointer.h @@ -488,10 +488,11 @@ class GenericPointer { v = &((*v)[t->index]); } else { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) { v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); - v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end + m = v->MemberEnd(); + v = &(--m)->value; // Assumes AddMember() appends at the end exist = false; } else @@ -543,7 +544,7 @@ class GenericPointer { switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) break; v = &m->value; @@ -779,7 +780,7 @@ class GenericPointer { switch (v->GetType()) { case kObjectType: { - typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); + typename ValueType::MemberIterator m = v->FindMember(GenericValue(GenericStringRef(t->name, t->length))); if (m == v->MemberEnd()) return false; v = &m->value; diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/prettywriter.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/prettywriter.h old mode 100755 new mode 100644 index 45afb69..94eeb69 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/prettywriter.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/prettywriter.h @@ -60,7 +60,7 @@ class PrettyWriter : public Writer -#define RAPIDJSON_ASSERT(x) /*assert(x)*/ +#define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// @@ -490,6 +490,12 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) +#if defined(__has_builtin) +#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) +#else +#define RAPIDJSON_HAS_BUILTIN(x) 0 +#endif + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF @@ -591,6 +597,19 @@ RAPIDJSON_NAMESPACE_END #endif #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR +/////////////////////////////////////////////////////////////////////////////// +// C++17 features + +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute(fallthrough) +# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] +# else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +# endif +#else +# define RAPIDJSON_DELIBERATE_FALLTHROUGH +#endif + //!@endcond //! Assertion (in non-throwing contexts). @@ -612,13 +631,30 @@ RAPIDJSON_NAMESPACE_END #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT_ASSERT(x) #else -#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#include +#define RAPIDJSON_NOEXCEPT_ASSERT(x) assert(x) #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT #else #define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) #endif // RAPIDJSON_ASSERT_THROWS #endif // RAPIDJSON_NOEXCEPT_ASSERT +/////////////////////////////////////////////////////////////////////////////// +// malloc/realloc/free + +#ifndef RAPIDJSON_MALLOC +///! customization point for global \c malloc +#define RAPIDJSON_MALLOC(size) std::malloc(size) +#endif +#ifndef RAPIDJSON_REALLOC +///! customization point for global \c realloc +#define RAPIDJSON_REALLOC(ptr, new_size) std::realloc(ptr, new_size) +#endif +#ifndef RAPIDJSON_FREE +///! customization point for global \c free +#define RAPIDJSON_FREE(ptr) std::free(ptr) +#endif + /////////////////////////////////////////////////////////////////////////////// // new/delete diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/reader.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/reader.h old mode 100755 new mode 100644 index 44a6bcd..30e45e1 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/reader.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/reader.h @@ -20,6 +20,7 @@ #include "allocators.h" #include "stream.h" #include "encodedstream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" @@ -153,6 +154,7 @@ enum ParseFlag { kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. + kParseEscapedApostropheFlag = 512, //!< Allow escaped apostrophe in strings. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; @@ -443,16 +445,16 @@ inline const char *SkipWhitespace_SIMD(const char* p) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz =__builtin_clzll(high);; + uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low);; + uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } @@ -479,16 +481,16 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz = __builtin_clzll(high); + uint32_t lz = internal::clzll(high); return p + 8 + (lz >> 3); } } else { - int lz = __builtin_clzll(low); + uint32_t lz = internal::clzll(low); return p + (lz >> 3); } } @@ -990,7 +992,7 @@ class GenericReader { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1013,19 +1015,31 @@ class GenericReader { is.Take(); os.Put(static_cast(escape[static_cast(e)])); } + else if ((parseFlags & kParseEscapedApostropheFlag) && RAPIDJSON_LIKELY(e == '\'')) { // Allow escaped apostrophe + is.Take(); + os.Put('\''); + } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { - // Handle UTF-16 surrogate pair - if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - unsigned codepoint2 = ParseHex4(is, escapeOffset); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDFFF)) { + // high surrogate, check if followed by valid low surrogate + if (RAPIDJSON_LIKELY(codepoint <= 0xDBFF)) { + // Handle UTF-16 surrogate pair + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + // single low surrogate + else + { RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } } TEncoding::Encode(os, codepoint); } @@ -1244,19 +1258,19 @@ class GenericReader { x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high);; + uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low);; + uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } @@ -1314,19 +1328,19 @@ class GenericReader { x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = internal::clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = internal::clzll(low); length = lz >> 3; escaped = true; } @@ -1370,17 +1384,17 @@ class GenericReader { x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract if (low == 0) { if (high != 0) { - int lz = __builtin_clzll(high); + uint32_t lz = internal::clzll(high); p += 8 + (lz >> 3); break; } } else { - int lz = __builtin_clzll(low); + uint32_t lz = internal::clzll(low); p += lz >> 3; break; } @@ -1403,7 +1417,7 @@ class GenericReader { RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } - RAPIDJSON_FORCEINLINE void Push(char) {} + RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/schema.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/schema.h old mode 100755 new mode 100644 index 26ae947..fc39d06 --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/schema.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/schema.h @@ -443,7 +443,6 @@ class Schema { exclusiveMaximum_(false), defaultValueLength_(0) { - typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; @@ -899,7 +898,7 @@ class Schema { } } - SizeType index; + SizeType index = 0; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/stream.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/stream.h old mode 100755 new mode 100644 index c08a87e..7f2643e --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/stream.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/stream.h @@ -188,9 +188,7 @@ template struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) { - SkipBOM(); - } + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } @@ -207,31 +205,6 @@ struct GenericInsituStringStream { Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Pop(size_t count) { dst_ -= count; } - /* - Detect encoding type with BOM or RFC 4627 - BOM (Byte Order Mark): - 00 00 FE FF UTF-32BE - FF FE 00 00 UTF-32LE - FE FF UTF-16BE - FF FE UTF-16LE - EF BB BF UTF-8 - */ - void SkipBOM() { - - unsigned char *c = reinterpret_cast(src_); - if (!c) return; - - unsigned bom = (c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); - - if (bom == 0xFFFE0000) { Take(); Take(); Take(); Take(); } - else if (bom == 0x0000FEFF) { Take(); Take(); Take(); Take(); } - else if ((bom & 0xFFFF) == 0xFFFE) { Take(); Take(); } - else if ((bom & 0xFFFF) == 0xFEFF) { Take(); Take(); } - else if ((bom & 0xFFFFFF) == 0xBFBBEF) { Take(); Take(); Take(); } - - //It might need to clarify this file is a type of RFC 4627? - } - Ch* src_; Ch* dst_; Ch* head_; diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/stringbuffer.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/stringbuffer.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/lottie/rapidjson/writer.h b/AXrLottie/src/main/cpp/src/lottie/rapidjson/writer.h old mode 100755 new mode 100644 index 6f5b690..51dd86d --- a/AXrLottie/src/main/cpp/src/lottie/rapidjson/writer.h +++ b/AXrLottie/src/main/cpp/src/lottie/rapidjson/writer.h @@ -16,6 +16,7 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/clzll.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" @@ -226,7 +227,7 @@ class Writer { return Key(str.data(), SizeType(str.size())); } #endif - + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object @@ -282,6 +283,8 @@ class Writer { os_->Flush(); } + static const size_t kDefaultLevelDepth = 32; + protected: //! Information for each nested level struct Level { @@ -290,8 +293,6 @@ class Writer { bool inArray; //!< true if in array, otherwise in object }; - static const size_t kDefaultLevelDepth = 32; - bool WriteNull() { PutReserve(*os_, 4); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; @@ -668,19 +669,19 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 - uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract - uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract + uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract SizeType len = 0; bool escaped = false; if (low == 0) { if (high != 0) { - unsigned lz = (unsigned)__builtin_clzll(high); + uint32_t lz = internal::clzll(high); len = 8 + (lz >> 3); escaped = true; } } else { - unsigned lz = (unsigned)__builtin_clzll(low); + uint32_t lz = internal::clzll(low); len = lz >> 3; escaped = true; } diff --git a/AXrLottie/src/main/cpp/src/vector/CMakeLists.txt b/AXrLottie/src/main/cpp/src/vector/CMakeLists.txt old mode 100755 new mode 100644 index 67367ad..3ae96e6 --- a/AXrLottie/src/main/cpp/src/vector/CMakeLists.txt +++ b/AXrLottie/src/main/cpp/src/vector/CMakeLists.txt @@ -10,8 +10,9 @@ target_sources(rlottie "${CMAKE_CURRENT_LIST_DIR}/vbrush.cpp" "${CMAKE_CURRENT_LIST_DIR}/vbitmap.cpp" "${CMAKE_CURRENT_LIST_DIR}/vpainter.cpp" + "${CMAKE_CURRENT_LIST_DIR}/vdrawhelper_common.cpp" "${CMAKE_CURRENT_LIST_DIR}/vdrawhelper.cpp" - "${CMAKE_CURRENT_LIST_DIR}/vcompositionfunctions.cpp" + "${CMAKE_CURRENT_LIST_DIR}/vdrawhelper_sse2.cpp" "${CMAKE_CURRENT_LIST_DIR}/vdrawhelper_neon.cpp" "${CMAKE_CURRENT_LIST_DIR}/vrle.cpp" "${CMAKE_CURRENT_LIST_DIR}/vpath.cpp" diff --git a/AXrLottie/src/main/cpp/src/vector/config.h b/AXrLottie/src/main/cpp/src/vector/config.h deleted file mode 100755 index 116e029..0000000 --- a/AXrLottie/src/main/cpp/src/vector/config.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -//enable logging -//#define LOTTIE_LOGGING_SUPPORT - -//enable static building of image loader -//#define LOTTIE_STATIC_IMAGE_LOADER - -//enable lottie model caching -//#define LOTTIE_CACHE_SUPPORT - -#endif // CONFIG_H diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/CMakeLists.txt b/AXrLottie/src/main/cpp/src/vector/freetype/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.cpp b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.cpp old mode 100755 new mode 100644 index 5a71e70..a3f0af2 --- a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.cpp +++ b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.cpp @@ -206,14 +206,16 @@ static void ft_trig_pseudo_rotate(SW_FT_Vector* vec, SW_FT_Angle theta) /* Pseudorotations, with right shifts */ for (i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++) { + SW_FT_Fixed v1 = ((y + b) >> i); + SW_FT_Fixed v2 = ((x + b) >> i); if (theta < 0) { - xtemp = x + ((y + b) >> i); - y = y - ((x + b) >> i); + xtemp = x + v1; + y = y - v2; x = xtemp; theta += *arctanptr++; } else { - xtemp = x - ((y + b) >> i); - y = y + ((x + b) >> i); + xtemp = x - v1; + y = y + v2; x = xtemp; theta -= *arctanptr++; } @@ -260,14 +262,16 @@ static void ft_trig_pseudo_polarize(SW_FT_Vector* vec) /* Pseudorotations, with right shifts */ for (i = 1, b = 1; i < SW_FT_TRIG_MAX_ITERS; b <<= 1, i++) { + SW_FT_Fixed v1 = ((y + b) >> i); + SW_FT_Fixed v2 = ((x + b) >> i); if (y > 0) { - xtemp = x + ((y + b) >> i); - y = y - ((x + b) >> i); + xtemp = x + v1; + y = y - v2; x = xtemp; theta += *arctanptr++; } else { - xtemp = x - ((y + b) >> i); - y = y + ((x + b) >> i); + xtemp = x - v1; + y = y + v2; x = xtemp; theta -= *arctanptr++; } @@ -441,16 +445,17 @@ void SW_FT_Vector_From_Polar(SW_FT_Vector* vec, SW_FT_Fixed length, /* documentation is in fttrigon.h */ -SW_FT_Angle SW_FT_Angle_Diff(SW_FT_Angle angle1, SW_FT_Angle angle2) +SW_FT_Angle SW_FT_Angle_Diff( SW_FT_Angle angle1, SW_FT_Angle angle2 ) { - SW_FT_Angle delta = angle2 - angle1; + SW_FT_Angle delta = angle2 - angle1; - delta %= SW_FT_ANGLE_2PI; - if (delta < 0) delta += SW_FT_ANGLE_2PI; + while ( delta <= -SW_FT_ANGLE_PI ) + delta += SW_FT_ANGLE_2PI; - if (delta > SW_FT_ANGLE_PI) delta -= SW_FT_ANGLE_2PI; + while ( delta > SW_FT_ANGLE_PI ) + delta -= SW_FT_ANGLE_2PI; - return delta; + return delta; } /* END */ diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.h b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_math.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.cpp b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.cpp old mode 100755 new mode 100644 index c97e6b2..e48ad1b --- a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.cpp +++ b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.cpp @@ -71,7 +71,6 @@ #include #include #include - #define SW_FT_UINT_MAX UINT_MAX #define SW_FT_INT_MAX INT_MAX #define SW_FT_ULONG_MAX ULONG_MAX @@ -188,8 +187,7 @@ typedef struct SW_FT_Outline_Funcs_ { #define ONE_PIXEL (1L << PIXEL_BITS) #define PIXEL_MASK (-1L << PIXEL_BITS) #define TRUNC(x) ((TCoord)((x) >> PIXEL_BITS)) -#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) - +#define SUBPIXELS(x) ((TPos)(x) << PIXEL_BITS) #define FLOOR(x) ((x) & -ONE_PIXEL) #define CEILING(x) (((x) + ONE_PIXEL - 1) & -ONE_PIXEL) #define ROUND(x) (((x) + ONE_PIXEL / 2) & -ONE_PIXEL) @@ -233,12 +231,11 @@ typedef struct SW_FT_Outline_Funcs_ { /* These macros speed up repetitive divisions by replacing them */ /* with multiplications and right shifts. */ -#define SW_FT_UDIVPREP( c, b ) \ - long b ## _r = c ? (long)( SW_FT_ULONG_MAX >> PIXEL_BITS ) / ( b ) \ - : 0 -#define SW_FT_UDIV( a, b ) \ - (TCoord)( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \ - ( sizeof( long ) * SW_FT_CHAR_BIT - PIXEL_BITS ) ) +#define SW_FT_UDIVPREP(b) \ + long b##_r = (long)(SW_FT_ULONG_MAX >> PIXEL_BITS) / (b) +#define SW_FT_UDIV(a, b) \ + (((unsigned long)(a) * (unsigned long)(b##_r)) >> \ + (sizeof(long) * SW_FT_CHAR_BIT - PIXEL_BITS)) /*************************************************************************/ /* */ @@ -293,8 +290,6 @@ typedef struct TCell_ { #endif /* _MSC_VER */ typedef struct gray_TWorker_ { - ft_jmp_buf jump_buffer; - TCoord ex, ey; TPos min_ex, max_ex; TPos min_ey, max_ey; @@ -330,6 +325,8 @@ typedef struct gray_TWorker_ { int band_size; int band_shoot; + ft_jmp_buf jump_buffer; + void* buffer; long buffer_size; @@ -445,7 +442,7 @@ static PCell gray_find_cell(RAS_ARG) cell->next = *pcell; *pcell = cell; - Exit: +Exit: return cell; } @@ -496,7 +493,7 @@ static void gray_set_cell(RAS_ARG_ TCoord ex, TCoord ey) } ras.invalid = - ((unsigned)ey >= (unsigned)ras.count_ey || ex >= ras.count_ex); + ((unsigned)ey >= (unsigned)ras.count_ey || ex >= ras.count_ex); } /*************************************************************************/ @@ -522,144 +519,126 @@ static void gray_start_cell(RAS_ARG_ TCoord ex, TCoord ey) /* */ /* Render a straight line across multiple cells in any direction. */ /* */ -static void -gray_render_line( RAS_ARG_ TPos to_x, - TPos to_y ) +static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) { - TPos dx, dy; - TCoord fx1, fy1, fx2, fy2; - TCoord ex1, ey1, ex2, ey2; - + TPos dx, dy, fx1, fy1, fx2, fy2; + TCoord ex1, ex2, ey1, ey2; - ey1 = TRUNC( ras.y ); - ey2 = TRUNC( to_y ); + ex1 = TRUNC(ras.x); + ex2 = TRUNC(to_x); + ey1 = TRUNC(ras.y); + ey2 = TRUNC(to_y); /* perform vertical clipping */ - if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || - ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) + if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) || + (ey1 < ras.min_ey && ey2 < ras.min_ey)) goto End; - ex1 = TRUNC( ras.x ); - ex2 = TRUNC( to_x ); - - fx1 = FRACT( ras.x ); - fy1 = FRACT( ras.y ); - dx = to_x - ras.x; dy = to_y - ras.y; - if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ + fx1 = ras.x - SUBPIXELS(ex1); + fy1 = ras.y - SUBPIXELS(ey1); + + if (ex1 == ex2 && ey1 == ey2) /* inside one cell */ ; - else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */ + else if (dy == 0) /* ex1 != ex2 */ /* any horizontal line */ { - gray_set_cell( RAS_VAR_ ex2, ey2 ); - goto End; - } - else if ( dx == 0 ) - { - if ( dy > 0 ) /* vertical line up */ - do - { + ex1 = ex2; + gray_set_cell(RAS_VAR_ ex1, ey1); + } else if (dx == 0) { + if (dy > 0) /* vertical line up */ + do { fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * fx1 * 2; fy1 = 0; ey1++; - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ey1 != ey2 ); - else /* vertical line down */ - do - { + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ey1 != ey2); + else /* vertical line down */ + do { fy2 = 0; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * fx1 * 2; + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * fx1 * 2; fy1 = ONE_PIXEL; ey1--; - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ey1 != ey2 ); - } - else /* any other line */ + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ey1 != ey2); + } else /* any other line */ { - TPos prod = dx * (TPos)fy1 - dy * (TPos)fx1; - SW_FT_UDIVPREP( ex1 != ex2, dx ); - SW_FT_UDIVPREP( ey1 != ey2, dy ); - + TArea prod = dx * fy1 - dy * fx1; + SW_FT_UDIVPREP(dx); + SW_FT_UDIVPREP(dy); /* The fundamental value `prod' determines which side and the */ /* exact coordinate where the line exits current cell. It is */ /* also easily updated when moving from one cell to the next. */ - do - { - if ( prod <= 0 && - prod - dx * ONE_PIXEL > 0 ) /* left */ + do { + if (prod <= 0 && prod - dx * ONE_PIXEL > 0) /* left */ { fx2 = 0; - fy2 = SW_FT_UDIV( -prod, -dx ); + fy2 = (TPos)SW_FT_UDIV(-prod, -dx); prod -= dy * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = ONE_PIXEL; fy1 = fy2; ex1--; - } - else if ( prod - dx * ONE_PIXEL <= 0 && - prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */ + } else if (prod - dx * ONE_PIXEL <= 0 && + prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0) /* up */ { prod -= dx * ONE_PIXEL; - fx2 = SW_FT_UDIV( -prod, dy ); + fx2 = (TPos)SW_FT_UDIV(-prod, dy); fy2 = ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = fx2; fy1 = 0; ey1++; - } - else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && - prod + dy * ONE_PIXEL >= 0 ) /* right */ + } else if (prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 && + prod + dy * ONE_PIXEL >= 0) /* right */ { prod += dy * ONE_PIXEL; fx2 = ONE_PIXEL; - fy2 = SW_FT_UDIV( prod, dx ); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + fy2 = (TPos)SW_FT_UDIV(prod, dx); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = 0; fy1 = fy2; ex1++; - } - else /* ( prod + dy * ONE_PIXEL < 0 && - prod > 0 ) down */ + } else /* ( prod + dy * ONE_PIXEL < 0 && + prod > 0 ) down */ { - fx2 = SW_FT_UDIV( prod, -dy ); + fx2 = (TPos)SW_FT_UDIV(prod, -dy); fy2 = 0; prod += dx * ONE_PIXEL; - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); fx1 = fx2; fy1 = ONE_PIXEL; ey1--; } - gray_set_cell( RAS_VAR_ ex1, ey1 ); - } while ( ex1 != ex2 || ey1 != ey2 ); + gray_set_cell(RAS_VAR_ ex1, ey1); + } while (ex1 != ex2 || ey1 != ey2); } - fx2 = FRACT( to_x ); - fy2 = FRACT( to_y ); + fx2 = to_x - SUBPIXELS(ex2); + fy2 = to_y - SUBPIXELS(ey2); - ras.cover += ( fy2 - fy1 ); - ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); + ras.cover += (fy2 - fy1); + ras.area += (fy2 - fy1) * (fx1 + fx2); - End: - ras.x = to_x; - ras.y = to_y; +End: + ras.x = to_x; + ras.y = to_y; } -static void -gray_split_conic( SW_FT_Vector* base ) +static void gray_split_conic(SW_FT_Vector* base) { TPos a, b; - base[4].x = base[2].x; a = base[0].x + base[1].x; b = base[1].x + base[2].x; @@ -675,71 +654,72 @@ gray_split_conic( SW_FT_Vector* base ) base[1].y = a >> 1; } -static void -gray_render_conic( RAS_ARG_ const SW_FT_Vector* control, - const SW_FT_Vector* to ) +static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, + const SW_FT_Vector* to) { - SW_FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */ - SW_FT_Vector* arc = bez_stack; - TPos dx, dy; - int draw, split; - - - arc[0].x = UPSCALE( to->x ); - arc[0].y = UPSCALE( to->y ); - arc[1].x = UPSCALE( control->x ); - arc[1].y = UPSCALE( control->y ); + TPos dx, dy; + TPos min, max, y; + int top, level; + int* levels; + SW_FT_Vector* arc; + + levels = ras.lev_stack; + + arc = ras.bez_stack; + arc[0].x = UPSCALE(to->x); + arc[0].y = UPSCALE(to->y); + arc[1].x = UPSCALE(control->x); + arc[1].y = UPSCALE(control->y); arc[2].x = ras.x; arc[2].y = ras.y; + top = 0; + + dx = SW_FT_ABS(arc[2].x + arc[0].x - 2 * arc[1].x); + dy = SW_FT_ABS(arc[2].y + arc[0].y - 2 * arc[1].y); + if (dx < dy) dx = dy; + + if (dx < ONE_PIXEL / 4) goto Draw; /* short-cut the arc that crosses the current band */ - if ( ( TRUNC( arc[0].y ) >= ras.max_ey && - TRUNC( arc[1].y ) >= ras.max_ey && - TRUNC( arc[2].y ) >= ras.max_ey ) || - ( TRUNC( arc[0].y ) < ras.min_ey && - TRUNC( arc[1].y ) < ras.min_ey && - TRUNC( arc[2].y ) < ras.min_ey ) ) - { - ras.x = arc[0].x; - ras.y = arc[0].y; - return; - } + min = max = arc[0].y; - dx = SW_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x ); - dy = SW_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y ); - if ( dx < dy ) - dx = dy; + y = arc[1].y; + if (y < min) min = y; + if (y > max) max = y; - /* We can calculate the number of necessary bisections because */ - /* each bisection predictably reduces deviation exactly 4-fold. */ - /* Even 32-bit deviation would vanish after 16 bisections. */ - draw = 1; - while ( dx > ONE_PIXEL / 4 ) - { - dx >>= 2; - draw <<= 1; - } + y = arc[2].y; + if (y < min) min = y; + if (y > max) max = y; - /* We use decrement counter to count the total number of segments */ - /* to draw starting from 2^level. Before each draw we split as */ - /* many times as there are trailing zeros in the counter. */ - do - { - split = draw & ( -draw ); /* isolate the rightmost 1-bit */ - while ( ( split >>= 1 ) ) - { - gray_split_conic( arc ); + if (TRUNC(min) >= ras.max_ey || TRUNC(max) < ras.min_ey) goto Draw; + + level = 0; + do { + dx >>= 2; + level++; + } while (dx > ONE_PIXEL / 4); + + levels[0] = level; + + do { + level = levels[top]; + if (level > 0) { + gray_split_conic(arc); arc += 2; + top++; + levels[top] = levels[top - 1] = level - 1; + continue; } - gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + Draw: + gray_render_line(RAS_VAR_ arc[0].x, arc[0].y); + top--; arc -= 2; - } while ( --draw ); + } while (top >= 0); } -static void -gray_split_cubic( SW_FT_Vector* base ) +static void gray_split_cubic(SW_FT_Vector* base) { TPos a, b, c; @@ -769,14 +749,13 @@ gray_split_cubic( SW_FT_Vector* base ) base[3].y = ( a + c ) >> 3; } + static void -gray_render_cubic( RAS_ARG_ const SW_FT_Vector* control1, - const SW_FT_Vector* control2, - const SW_FT_Vector* to ) +gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, + const SW_FT_Vector* control2, + const SW_FT_Vector* to) { - SW_FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */ - SW_FT_Vector* arc = bez_stack; - + SW_FT_Vector* arc = ras.bez_stack; arc[0].x = UPSCALE( to->x ); arc[0].y = UPSCALE( to->y ); @@ -797,33 +776,33 @@ gray_render_cubic( RAS_ARG_ const SW_FT_Vector* control1, TRUNC( arc[2].y ) < ras.min_ey && TRUNC( arc[3].y ) < ras.min_ey ) ) { - ras.x = arc[0].x; - ras.y = arc[0].y; - return; + ras.x = arc[0].x; + ras.y = arc[0].y; + return; } for (;;) { - /* with each split, control points quickly converge towards */ - /* chord trisection points and the vanishing distances below */ - /* indicate when the segment is flat enough to draw */ - if ( SW_FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || - SW_FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || - SW_FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || - SW_FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) - goto Split; - - gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); - - if ( arc == bez_stack ) - return; + /* with each split, control points quickly converge towards */ + /* chord trisection points and the vanishing distances below */ + /* indicate when the segment is flat enough to draw */ + if ( SW_FT_ABS( 2 * arc[0].x - 3 * arc[1].x + arc[3].x ) > ONE_PIXEL / 2 || + SW_FT_ABS( 2 * arc[0].y - 3 * arc[1].y + arc[3].y ) > ONE_PIXEL / 2 || + SW_FT_ABS( arc[0].x - 3 * arc[2].x + 2 * arc[3].x ) > ONE_PIXEL / 2 || + SW_FT_ABS( arc[0].y - 3 * arc[2].y + 2 * arc[3].y ) > ONE_PIXEL / 2 ) + goto Split; + + gray_render_line( RAS_VAR_ arc[0].x, arc[0].y ); + + if ( arc == ras.bez_stack ) + return; - arc -= 3; - continue; + arc -= 3; + continue; - Split: - gray_split_cubic( arc ); - arc += 3; + Split: + gray_split_cubic( arc ); + arc += 3; } } @@ -925,7 +904,7 @@ static void gray_hline(RAS_ARG_ TCoord x, TCoord y, TPos area, TCoord acount) #ifdef DEBUG_GRAYS - if (1) { + if (1) { int n; fprintf(stderr, "count = %3d ", count); @@ -1051,11 +1030,7 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, int shift; TPos delta; - if ( !outline ) - return SW_FT_THROW( Invalid_Outline ); - - if ( !func_interface ) - return SW_FT_THROW( Invalid_Argument ); + if (!outline || !func_interface) return SW_FT_THROW(Invalid_Argument); shift = func_interface->shift; delta = func_interface->delta; @@ -1112,95 +1087,95 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, tag = SW_FT_CURVE_TAG(tags[0]); switch (tag) { - case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ - { - SW_FT_Vector vec; - - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); - - error = func_interface->line_to(&vec, user); - if (error) goto Exit; - continue; - } - - case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ - v_control.x = SCALED(point->x); - v_control.y = SCALED(point->y); + case SW_FT_CURVE_TAG_ON: /* emit a single line_to */ + { + SW_FT_Vector vec; - Do_Conic: - if (point < limit) { - SW_FT_Vector vec; - SW_FT_Vector v_middle; + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); - point++; - tags++; - tag = SW_FT_CURVE_TAG(tags[0]); + error = func_interface->line_to(&vec, user); + if (error) goto Exit; + continue; + } - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); + case SW_FT_CURVE_TAG_CONIC: /* consume conic arcs */ + v_control.x = SCALED(point->x); + v_control.y = SCALED(point->y); - if (tag == SW_FT_CURVE_TAG_ON) { - error = - func_interface->conic_to(&v_control, &vec, user); - if (error) goto Exit; - continue; - } + Do_Conic: + if (point < limit) { + SW_FT_Vector vec; + SW_FT_Vector v_middle; - if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; + point++; + tags++; + tag = SW_FT_CURVE_TAG(tags[0]); - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + if (tag == SW_FT_CURVE_TAG_ON) { error = - func_interface->conic_to(&v_control, &v_middle, user); + func_interface->conic_to(&v_control, &vec, user); if (error) goto Exit; - - v_control = vec; - goto Do_Conic; + continue; } - error = func_interface->conic_to(&v_control, &v_start, user); - goto Close; + if (tag != SW_FT_CURVE_TAG_CONIC) goto Invalid_Outline; - default: /* SW_FT_CURVE_TAG_CUBIC */ - { - SW_FT_Vector vec1, vec2; + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; - if (point + 1 > limit || - SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) - goto Invalid_Outline; + error = + func_interface->conic_to(&v_control, &v_middle, user); + if (error) goto Exit; - point += 2; - tags += 2; + v_control = vec; + goto Do_Conic; + } - vec1.x = SCALED(point[-2].x); - vec1.y = SCALED(point[-2].y); + error = func_interface->conic_to(&v_control, &v_start, user); + goto Close; - vec2.x = SCALED(point[-1].x); - vec2.y = SCALED(point[-1].y); + default: /* SW_FT_CURVE_TAG_CUBIC */ + { + SW_FT_Vector vec1, vec2; - if (point <= limit) { - SW_FT_Vector vec; + if (point + 1 > limit || + SW_FT_CURVE_TAG(tags[1]) != SW_FT_CURVE_TAG_CUBIC) + goto Invalid_Outline; - vec.x = SCALED(point->x); - vec.y = SCALED(point->y); + point += 2; + tags += 2; - error = func_interface->cubic_to(&vec1, &vec2, &vec, user); - if (error) goto Exit; - continue; - } + vec1.x = SCALED(point[-2].x); + vec1.y = SCALED(point[-2].y); - error = func_interface->cubic_to(&vec1, &vec2, &v_start, user); - goto Close; + vec2.x = SCALED(point[-1].x); + vec2.y = SCALED(point[-1].y); + + if (point <= limit) { + SW_FT_Vector vec; + + vec.x = SCALED(point->x); + vec.y = SCALED(point->y); + + error = func_interface->cubic_to(&vec1, &vec2, &vec, user); + if (error) goto Exit; + continue; } + + error = func_interface->cubic_to(&vec1, &vec2, &v_start, user); + goto Close; + } } } /* close the contour with a line segment */ error = func_interface->line_to(&v_start, user); - Close: + Close: if (error) goto Exit; first = last + 1; @@ -1208,10 +1183,10 @@ static int SW_FT_Outline_Decompose(const SW_FT_Outline* outline, return 0; - Exit: +Exit: return error; - Invalid_Outline: +Invalid_Outline: return SW_FT_THROW(Invalid_Outline); } @@ -1329,7 +1304,7 @@ static int gray_convert_glyph(RAS_ARG) } else if (error != ErrRaster_Memory_Overflow) return 1; - ReduceBands: + ReduceBands: /* render pool overflow; we will reduce the render band by half */ bottom = band->min; top = band->max; diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.h b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.h old mode 100755 new mode 100644 index bab40ef..7897289 --- a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.h +++ b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_raster.h @@ -338,12 +338,6 @@ typedef struct SW_FT_Outline_ #define SW_FT_RASTER_FLAG_DIRECT 0x2 #define SW_FT_RASTER_FLAG_CLIP 0x4 - /* deprecated */ -#define ft_raster_flag_default SW_FT_RASTER_FLAG_DEFAULT -#define ft_raster_flag_aa SW_FT_RASTER_FLAG_AA -#define ft_raster_flag_direct SW_FT_RASTER_FLAG_DIRECT -#define ft_raster_flag_clip SW_FT_RASTER_FLAG_CLIP - /*************************************************************************/ /* */ diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.cpp b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.cpp old mode 100755 new mode 100644 index 2a85707..3160f84 --- a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.cpp +++ b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.cpp @@ -47,16 +47,18 @@ static void ft_conic_split(SW_FT_Vector* base) SW_FT_Pos a, b; base[4].x = base[2].x; - b = base[1].x; - a = base[3].x = (base[2].x + b) / 2; - b = base[1].x = (base[0].x + b) / 2; - base[2].x = (a + b) / 2; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + base[3].x = b >> 1; + base[2].x = ( a + b ) >> 2; + base[1].x = a >> 1; base[4].y = base[2].y; - b = base[1].y; - a = base[3].y = (base[2].y + b) / 2; - b = base[1].y = (base[0].y + b) / 2; - base[2].y = (a + b) / 2; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + base[3].y = b >> 1; + base[2].y = ( a + b ) >> 2; + base[1].y = a >> 1; } static SW_FT_Bool ft_conic_is_small_enough(SW_FT_Vector* base, @@ -99,27 +101,31 @@ static SW_FT_Bool ft_conic_is_small_enough(SW_FT_Vector* base, static void ft_cubic_split(SW_FT_Vector* base) { - SW_FT_Pos a, b, c, d; + SW_FT_Pos a, b, c; base[6].x = base[3].x; - c = base[1].x; - d = base[2].x; - base[1].x = a = (base[0].x + c) / 2; - base[5].x = b = (base[3].x + d) / 2; - c = (c + d) / 2; - base[2].x = a = (a + c) / 2; - base[4].x = b = (b + c) / 2; - base[3].x = (a + b) / 2; + a = base[0].x + base[1].x; + b = base[1].x + base[2].x; + c = base[2].x + base[3].x; + base[5].x = c >> 1; + c += b; + base[4].x = c >> 2; + base[1].x = a >> 1; + a += b; + base[2].x = a >> 2; + base[3].x = ( a + c ) >> 3; base[6].y = base[3].y; - c = base[1].y; - d = base[2].y; - base[1].y = a = (base[0].y + c) / 2; - base[5].y = b = (base[3].y + d) / 2; - c = (c + d) / 2; - base[2].y = a = (a + c) / 2; - base[4].y = b = (b + c) / 2; - base[3].y = (a + b) / 2; + a = base[0].y + base[1].y; + b = base[1].y + base[2].y; + c = base[2].y + base[3].y; + base[5].y = c >> 1; + c += b; + base[4].y = c >> 2; + base[1].y = a >> 1; + a += b; + base[2].y = a >> 2; + base[3].y = ( a + c ) >> 3; } /* Return the average of `angle1' and `angle2'. */ @@ -475,65 +481,60 @@ static SW_FT_Error ft_stroke_border_cubicto(SW_FT_StrokeBorder border, #define SW_FT_ARC_CUBIC_ANGLE (SW_FT_ANGLE_PI / 2) -static SW_FT_Error ft_stroke_border_arcto(SW_FT_StrokeBorder border, - SW_FT_Vector* center, - SW_FT_Fixed radius, - SW_FT_Angle angle_start, - SW_FT_Angle angle_diff) + +static SW_FT_Error +ft_stroke_border_arcto( SW_FT_StrokeBorder border, + SW_FT_Vector* center, + SW_FT_Fixed radius, + SW_FT_Angle angle_start, + SW_FT_Angle angle_diff ) { - SW_FT_Angle total, angle, step, rotate, next, theta; - SW_FT_Vector a, b, a2, b2; - SW_FT_Fixed length; - SW_FT_Error error = 0; - - /* compute start point */ - SW_FT_Vector_From_Polar(&a, radius, angle_start); - a.x += center->x; - a.y += center->y; - - total = angle_diff; - angle = angle_start; - rotate = (angle_diff >= 0) ? SW_FT_ANGLE_PI2 : -SW_FT_ANGLE_PI2; - - while (total != 0) { - step = total; - if (step > SW_FT_ARC_CUBIC_ANGLE) - step = SW_FT_ARC_CUBIC_ANGLE; - - else if (step < -SW_FT_ARC_CUBIC_ANGLE) - step = -SW_FT_ARC_CUBIC_ANGLE; - - next = angle + step; - theta = step; - if (theta < 0) theta = -theta; - - theta >>= 1; - - /* compute end point */ - SW_FT_Vector_From_Polar(&b, radius, next); - b.x += center->x; - b.y += center->y; - - /* compute first and second control points */ - length = SW_FT_MulDiv(radius, SW_FT_Sin(theta) * 4, - (0x10000L + SW_FT_Cos(theta)) * 3); - - SW_FT_Vector_From_Polar(&a2, length, angle + rotate); - a2.x += a.x; - a2.y += a.y; - - SW_FT_Vector_From_Polar(&b2, length, next - rotate); - b2.x += b.x; - b2.y += b.y; - - /* add cubic arc */ - error = ft_stroke_border_cubicto(border, &a2, &b2, &b); - if (error) break; - - /* process the rest of the arc ?? */ - a = b; - total -= step; - angle = next; + SW_FT_Fixed coef; + SW_FT_Vector a0, a1, a2, a3; + SW_FT_Int i, arcs = 1; + SW_FT_Error error = 0; + + + /* number of cubic arcs to draw */ + while ( angle_diff > SW_FT_ARC_CUBIC_ANGLE * arcs || + -angle_diff > SW_FT_ARC_CUBIC_ANGLE * arcs ) + arcs++; + + /* control tangents */ + coef = SW_FT_Tan( angle_diff / ( 4 * arcs ) ); + coef += coef / 3; + + /* compute start and first control point */ + SW_FT_Vector_From_Polar( &a0, radius, angle_start ); + a1.x = SW_FT_MulFix( -a0.y, coef ); + a1.y = SW_FT_MulFix( a0.x, coef ); + + a0.x += center->x; + a0.y += center->y; + a1.x += a0.x; + a1.y += a0.y; + + for ( i = 1; i <= arcs; i++ ) + { + /* compute end and second control point */ + SW_FT_Vector_From_Polar( &a3, radius, + angle_start + i * angle_diff / arcs ); + a2.x = SW_FT_MulFix( a3.y, coef ); + a2.y = SW_FT_MulFix( -a3.x, coef ); + + a3.x += center->x; + a3.y += center->y; + a2.x += a3.x; + a2.y += a3.y; + + /* add cubic arc */ + error = ft_stroke_border_cubicto( border, &a1, &a2, &a3 ); + if ( error ) + break; + + /* a0 = a3; */ + a1.x = a3.x - a2.x + a3.x; + a1.y = a3.y - a2.y + a3.y; } return error; @@ -776,61 +777,56 @@ static SW_FT_Error ft_stroker_arcto(SW_FT_Stroker stroker, SW_FT_Int side) } /* add a cap at the end of an opened path */ -static SW_FT_Error ft_stroker_cap(SW_FT_Stroker stroker, SW_FT_Angle angle, - SW_FT_Int side) +static SW_FT_Error +ft_stroker_cap(SW_FT_Stroker stroker, + SW_FT_Angle angle, + SW_FT_Int side) { SW_FT_Error error = 0; - if (stroker->line_cap == SW_FT_STROKER_LINECAP_ROUND) { + if (stroker->line_cap == SW_FT_STROKER_LINECAP_ROUND) + { /* add a round cap */ stroker->angle_in = angle; stroker->angle_out = angle + SW_FT_ANGLE_PI; error = ft_stroker_arcto(stroker, side); - } else if (stroker->line_cap == SW_FT_STROKER_LINECAP_SQUARE) { - /* add a square cap */ - SW_FT_Vector delta, delta2; - SW_FT_Angle rotate = SW_FT_SIDE_TO_ROTATE(side); - SW_FT_Fixed radius = stroker->radius; - SW_FT_StrokeBorder border = stroker->borders + side; - - SW_FT_Vector_From_Polar(&delta2, radius, angle + rotate); - SW_FT_Vector_From_Polar(&delta, radius, angle); - - delta.x += stroker->center.x + delta2.x; - delta.y += stroker->center.y + delta2.y; - - error = ft_stroke_border_lineto(border, &delta, FALSE); - if (error) goto Exit; - - SW_FT_Vector_From_Polar(&delta2, radius, angle - rotate); - SW_FT_Vector_From_Polar(&delta, radius, angle); - - delta.x += delta2.x + stroker->center.x; - delta.y += delta2.y + stroker->center.y; - - error = ft_stroke_border_lineto(border, &delta, FALSE); - } else if (stroker->line_cap == SW_FT_STROKER_LINECAP_BUTT) { - /* add a butt ending */ - SW_FT_Vector delta; - SW_FT_Angle rotate = SW_FT_SIDE_TO_ROTATE(side); - SW_FT_Fixed radius = stroker->radius; - SW_FT_StrokeBorder border = stroker->borders + side; + } + else + { + /* add a square or butt cap */ + SW_FT_Vector middle, delta; + SW_FT_Fixed radius = stroker->radius; + SW_FT_StrokeBorder border = stroker->borders + side; - SW_FT_Vector_From_Polar(&delta, radius, angle + rotate); + /* compute middle point and first angle point */ + SW_FT_Vector_From_Polar( &middle, radius, angle ); + delta.x = side ? middle.y : -middle.y; + delta.y = side ? -middle.x : middle.x; - delta.x += stroker->center.x; - delta.y += stroker->center.y; + if ( stroker->line_cap == SW_FT_STROKER_LINECAP_SQUARE ) + { + middle.x += stroker->center.x; + middle.y += stroker->center.y; + } + else /* SW_FT_STROKER_LINECAP_BUTT */ + { + middle.x = stroker->center.x; + middle.y = stroker->center.y; + } - error = ft_stroke_border_lineto(border, &delta, FALSE); - if (error) goto Exit; + delta.x += middle.x; + delta.y += middle.y; - SW_FT_Vector_From_Polar(&delta, radius, angle - rotate); + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; - delta.x += stroker->center.x; - delta.y += stroker->center.y; + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; - error = ft_stroke_border_lineto(border, &delta, FALSE); + error = ft_stroke_border_lineto( border, &delta, FALSE ); } Exit: @@ -843,8 +839,8 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, { SW_FT_StrokeBorder border = stroker->borders + side; SW_FT_Angle phi, theta, rotate; - SW_FT_Fixed length, thcos; - SW_FT_Vector delta; + SW_FT_Fixed length; + SW_FT_Vector sigma, delta; SW_FT_Error error = 0; SW_FT_Bool intersect; /* use intersection of lines? */ @@ -854,15 +850,21 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, /* Only intersect borders if between two lineto's and both */ /* lines are long enough (line_length is zero for curves). */ - if (!border->movable || line_length == 0) + if (!border->movable || line_length == 0 || + theta > 0x59C000 || theta < -0x59C000 ) intersect = FALSE; else { - /* compute minimum required length of lines */ - SW_FT_Fixed min_length = - ft_pos_abs(SW_FT_MulFix(stroker->radius, SW_FT_Tan(theta))); + /* compute minimum required length of lines */ + SW_FT_Fixed min_length; - intersect = SW_FT_BOOL(stroker->line_length >= min_length && - line_length >= min_length); + + SW_FT_Vector_Unit( &sigma, theta ); + min_length = + ft_pos_abs( SW_FT_MulDiv( stroker->radius, sigma.y, sigma.x ) ); + + intersect = SW_FT_BOOL( min_length && + stroker->line_length >= min_length && + line_length >= min_length ); } if (!intersect) { @@ -874,15 +876,13 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, border->movable = FALSE; } else { /* compute median angle */ - phi = stroker->angle_in + theta; + phi = stroker->angle_in + theta + rotate; - thcos = SW_FT_Cos(theta); + length = SW_FT_DivFix( stroker->radius, sigma.x ); - length = SW_FT_DivFix(stroker->radius, thcos); - - SW_FT_Vector_From_Polar(&delta, length, phi + rotate); - delta.x += stroker->center.x; - delta.y += stroker->center.y; + SW_FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; } error = ft_stroke_border_lineto(border, &delta, FALSE); @@ -890,137 +890,156 @@ static SW_FT_Error ft_stroker_inside(SW_FT_Stroker stroker, SW_FT_Int side, return error; } -/* process an outside corner, i.e. compute bevel/miter/round */ -static SW_FT_Error ft_stroker_outside(SW_FT_Stroker stroker, SW_FT_Int side, - SW_FT_Fixed line_length) + /* process an outside corner, i.e. compute bevel/miter/round */ +static SW_FT_Error +ft_stroker_outside( SW_FT_Stroker stroker, + SW_FT_Int side, + SW_FT_Fixed line_length ) { - SW_FT_StrokeBorder border = stroker->borders + side; - SW_FT_Error error; - SW_FT_Angle rotate; + SW_FT_StrokeBorder border = stroker->borders + side; + SW_FT_Error error; + SW_FT_Angle rotate; - if (stroker->line_join == SW_FT_STROKER_LINEJOIN_ROUND) - error = ft_stroker_arcto(stroker, side); - else { - /* this is a mitered (pointed) or beveled (truncated) corner */ - SW_FT_Fixed sigma = 0, radius = stroker->radius; - SW_FT_Angle theta = 0, phi = 0; - SW_FT_Fixed thcos = 0; - SW_FT_Bool bevel, fixed_bevel; - rotate = SW_FT_SIDE_TO_ROTATE(side); + if ( stroker->line_join == SW_FT_STROKER_LINEJOIN_ROUND ) + error = ft_stroker_arcto( stroker, side ); + else + { + /* this is a mitered (pointed) or beveled (truncated) corner */ + SW_FT_Fixed radius = stroker->radius; + SW_FT_Vector sigma; + SW_FT_Angle theta = 0, phi = 0; + SW_FT_Bool bevel, fixed_bevel; - bevel = SW_FT_BOOL(stroker->line_join == SW_FT_STROKER_LINEJOIN_BEVEL); - fixed_bevel = SW_FT_BOOL(stroker->line_join != - SW_FT_STROKER_LINEJOIN_MITER_VARIABLE); + rotate = SW_FT_SIDE_TO_ROTATE( side ); - if (!bevel) { - theta = SW_FT_Angle_Diff(stroker->angle_in, stroker->angle_out); + bevel = + SW_FT_BOOL( stroker->line_join == SW_FT_STROKER_LINEJOIN_BEVEL ); - if (theta == SW_FT_ANGLE_PI) { - theta = rotate; - phi = stroker->angle_in; - } else { - theta /= 2; - phi = stroker->angle_in + theta + rotate; - } + fixed_bevel = + SW_FT_BOOL( stroker->line_join != SW_FT_STROKER_LINEJOIN_MITER_VARIABLE ); - thcos = SW_FT_Cos(theta); - sigma = SW_FT_MulFix(stroker->miter_limit, thcos); + /* check miter limit first */ + if ( !bevel ) + { + theta = SW_FT_Angle_Diff( stroker->angle_in, stroker->angle_out ) / 2; - /* is miter limit exceeded? */ - if (sigma < 0x10000L) { - /* don't create variable bevels for very small deviations; */ - /* SW_FT_Sin(x) = 0 for x <= 57 */ - if (fixed_bevel || ft_pos_abs(theta) > 57) bevel = TRUE; - } + if ( theta == SW_FT_ANGLE_PI2 ) + theta = -rotate; + + phi = stroker->angle_in + theta + rotate; + + SW_FT_Vector_From_Polar( &sigma, stroker->miter_limit, theta ); + + /* is miter limit exceeded? */ + if ( sigma.x < 0x10000L ) + { + /* don't create variable bevels for very small deviations; */ + /* FT_Sin(x) = 0 for x <= 57 */ + if ( fixed_bevel || ft_pos_abs( theta ) > 57 ) + bevel = TRUE; } + } - if (bevel) /* this is a bevel (broken angle) */ + if ( bevel ) /* this is a bevel (broken angle) */ + { + if ( fixed_bevel ) { - if (fixed_bevel) { - /* the outer corners are simply joined together */ - SW_FT_Vector delta; - - /* add bevel */ - SW_FT_Vector_From_Polar(&delta, radius, - stroker->angle_out + rotate); - delta.x += stroker->center.x; - delta.y += stroker->center.y; - - border->movable = FALSE; - error = ft_stroke_border_lineto(border, &delta, FALSE); - } else /* variable bevel */ - { - /* the miter is truncated */ - SW_FT_Vector middle, delta; - SW_FT_Fixed length; + /* the outer corners are simply joined together */ + SW_FT_Vector delta; - /* compute middle point */ - SW_FT_Vector_From_Polar( - &middle, SW_FT_MulFix(radius, stroker->miter_limit), phi); - middle.x += stroker->center.x; - middle.y += stroker->center.y; - /* compute first angle point */ - length = SW_FT_MulDiv(radius, 0x10000L - sigma, - ft_pos_abs(SW_FT_Sin(theta))); + /* add bevel */ + SW_FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; - SW_FT_Vector_From_Polar(&delta, length, phi + rotate); - delta.x += middle.x; - delta.y += middle.y; + border->movable = FALSE; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + else /* variable bevel or clipped miter */ + { + /* the miter is truncated */ + SW_FT_Vector middle, delta; + SW_FT_Fixed coef; - error = ft_stroke_border_lineto(border, &delta, FALSE); - if (error) goto Exit; - /* compute second angle point */ - SW_FT_Vector_From_Polar(&delta, length, phi - rotate); - delta.x += middle.x; - delta.y += middle.y; + /* compute middle point and first angle point */ + SW_FT_Vector_From_Polar( &middle, + SW_FT_MulFix( radius, stroker->miter_limit ), + phi ); - error = ft_stroke_border_lineto(border, &delta, FALSE); - if (error) goto Exit; + coef = SW_FT_DivFix( 0x10000L - sigma.x, sigma.y ); + delta.x = SW_FT_MulFix( middle.y, coef ); + delta.y = SW_FT_MulFix( -middle.x, coef ); - /* finally, add an end point; only needed if not lineto */ - /* (line_length is zero for curves) */ - if (line_length == 0) { - SW_FT_Vector_From_Polar(&delta, radius, - stroker->angle_out + rotate); + middle.x += stroker->center.x; + middle.y += stroker->center.y; + delta.x += middle.x; + delta.y += middle.y; - delta.x += stroker->center.x; - delta.y += stroker->center.y; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; - error = ft_stroke_border_lineto(border, &delta, FALSE); - } - } - } else /* this is a miter (intersection) */ - { - SW_FT_Fixed length; - SW_FT_Vector delta; + /* compute second angle point */ + delta.x = middle.x - delta.x + middle.x; + delta.y = middle.y - delta.y + middle.y; - length = SW_FT_DivFix(stroker->radius, thcos); + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* finally, add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + SW_FT_Vector_From_Polar( &delta, + radius, + stroker->angle_out + rotate ); - SW_FT_Vector_From_Polar(&delta, length, phi); delta.x += stroker->center.x; delta.y += stroker->center.y; - error = ft_stroke_border_lineto(border, &delta, FALSE); - if (error) goto Exit; + error = ft_stroke_border_lineto( border, &delta, FALSE ); + } + } + } + else /* this is a miter (intersection) */ + { + SW_FT_Fixed length; + SW_FT_Vector delta; - /* now add an end point; only needed if not lineto */ - /* (line_length is zero for curves) */ - if (line_length == 0) { - SW_FT_Vector_From_Polar(&delta, stroker->radius, - stroker->angle_out + rotate); - delta.x += stroker->center.x; - delta.y += stroker->center.y; - error = ft_stroke_border_lineto(border, &delta, FALSE); - } + length = SW_FT_MulDiv( stroker->radius, stroker->miter_limit, sigma.x ); + + SW_FT_Vector_From_Polar( &delta, length, phi ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); + if ( error ) + goto Exit; + + /* now add an end point; only needed if not lineto */ + /* (line_length is zero for curves) */ + if ( line_length == 0 ) + { + SW_FT_Vector_From_Polar( &delta, + stroker->radius, + stroker->angle_out + rotate ); + delta.x += stroker->center.x; + delta.y += stroker->center.y; + + error = ft_stroke_border_lineto( border, &delta, FALSE ); } + } } -Exit: + Exit: return error; } diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.h b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_stroker.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_types.h b/AXrLottie/src/main/cpp/src/vector/freetype/v_ft_types.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/CMakeLists.txt b/AXrLottie/src/main/cpp/src/vector/pixman/CMakeLists.txt old mode 100755 new mode 100644 index 3c24e1a..d904ca8 --- a/AXrLottie/src/main/cpp/src/vector/pixman/CMakeLists.txt +++ b/AXrLottie/src/main/cpp/src/vector/pixman/CMakeLists.txt @@ -7,11 +7,6 @@ target_sources(rlottie ) ENDIF("${ARCH}" STREQUAL "arm") -target_sources(rlottie - PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/vregion.cpp" - ) - target_include_directories(rlottie PRIVATE "${CMAKE_CURRENT_LIST_DIR}" diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.S b/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.S old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.h b/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arm-neon-asm.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.S b/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.S deleted file mode 100755 index 7705eee..0000000 --- a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.S +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright © 2009 Nokia Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Siarhei Siamashka (siarhei.siamashka@nokia.com) - */ - -/* - * This file contains implementations of NEON optimized pixel processing - * functions. There is no full and detailed tutorial, but some functions - * (those which are exposing some new or interesting features) are - * extensively commented and can be used as examples. - * - * You may want to have a look at the comments for following functions: - * - pixman_composite_over_8888_0565_asm_neon - * - pixman_composite_over_n_8_0565_asm_neon - */ - -/* Prevent the stack from becoming executable for no reason... */ -#if defined(__linux__) && defined(__ELF__) -.section .note.GNU-stack,"",%progbits -#endif - -.text -.arch armv8-a -.altmacro -.p2align 2 - -/* Supplementary macro for setting function attributes */ -.macro pixman_asm_function fname -.func fname -.global fname -#ifdef __ELF__ -.hidden fname -.type fname, %function -#endif -fname: -.endm - -#include "pixman-arma64-neon-asm.h" - -/* Global configuration options and preferences */ - -/* - * The code can optionally make use of unaligned memory accesses to improve - * performance of handling leading/trailing pixels for each scanline. - * Configuration variable RESPECT_STRICT_ALIGNMENT can be set to 0 for - * example in linux if unaligned memory accesses are not configured to - * generate.exceptions. - */ -.set RESPECT_STRICT_ALIGNMENT, 1 - -/* - * Set default prefetch type. There is a choice between the following options: - * - * PREFETCH_TYPE_NONE (may be useful for the ARM cores where PLD is set to work - * as NOP to workaround some HW bugs or for whatever other reason) - * - * PREFETCH_TYPE_SIMPLE (may be useful for simple single-issue ARM cores where - * advanced prefetch intruduces heavy overhead) - * - * PREFETCH_TYPE_ADVANCED (useful for superscalar cores such as ARM Cortex-A8 - * which can run ARM and NEON instructions simultaneously so that extra ARM - * instructions do not add (many) extra cycles, but improve prefetch efficiency) - * - * Note: some types of function can't support advanced prefetch and fallback - * to simple one (those which handle 24bpp pixels) - */ -.set PREFETCH_TYPE_DEFAULT, PREFETCH_TYPE_ADVANCED - -/* Prefetch distance in pixels for simple prefetch */ -.set PREFETCH_DISTANCE_SIMPLE, 64 - -/* - * Implementation of pixman_composite_over_8888_0565_asm_neon - * - * This function takes a8r8g8b8 source buffer, r5g6b5 destination buffer and - * performs OVER compositing operation. Function fast_composite_over_8888_0565 - * from pixman-fast-path.c does the same in C and can be used as a reference. - * - * First we need to have some NEON assembly code which can do the actual - * operation on the pixels and provide it to the template macro. - * - * Template macro quite conveniently takes care of emitting all the necessary - * code for memory reading and writing (including quite tricky cases of - * handling unaligned leading/trailing pixels), so we only need to deal with - * the data in NEON registers. - * - * NEON registers allocation in general is recommented to be the following: - * v0, v1, v2, v3 - contain loaded source pixel data - * v4, v5, v6, v7 - contain loaded destination pixels (if they are needed) - * v24, v25, v26, v27 - contain loading mask pixel data (if mask is used) - * v28, v29, v30, v31 - place for storing the result (destination pixels) - * - * As can be seen above, four 64-bit NEON registers are used for keeping - * intermediate pixel data and up to 8 pixels can be processed in one step - * for 32bpp formats (16 pixels for 16bpp, 32 pixels for 8bpp). - * - * This particular function uses the following registers allocation: - * v0, v1, v2, v3 - contain loaded source pixel data - * v4, v5 - contain loaded destination pixels (they are needed) - * v28, v29 - place for storing the result (destination pixels) - */ - -/* - * Step one. We need to have some code to do some arithmetics on pixel data. - * This is implemented as a pair of macros: '*_head' and '*_tail'. When used - * back-to-back, they take pixel data from {v0, v1, v2, v3} and {v4, v5}, - * perform all the needed calculations and write the result to {v28, v29}. - * The rationale for having two macros and not just one will be explained - * later. In practice, any single monolitic function which does the work can - * be split into two parts in any arbitrary way without affecting correctness. - * - * There is one special trick here too. Common template macro can optionally - * make our life a bit easier by doing R, G, B, A color components - * deinterleaving for 32bpp pixel formats (and this feature is used in - * 'pixman_composite_over_8888_0565_asm_neon' function). So it means that - * instead of having 8 packed pixels in {v0, v1, v2, v3} registers, we - * actually use v0 register for blue channel (a vector of eight 8-bit - * values), v1 register for green, v2 for red and v3 for alpha. This - * simple conversion can be also done with a few NEON instructions: - * - * Packed to planar conversion: // vuzp8 is a wrapper macro - * vuzp8 v0, v1 - * vuzp8 v2, v3 - * vuzp8 v1, v3 - * vuzp8 v0, v2 - * - * Planar to packed conversion: // vzip8 is a wrapper macro - * vzip8 v0, v2 - * vzip8 v1, v3 - * vzip8 v2, v3 - * vzip8 v0, v1 - * - * But pixel can be loaded directly in planar format using LD4 / b NEON - * instruction. It is 1 cycle slower than LD1 / s, so this is not always - * desirable, that's why deinterleaving is optional. - * - * But anyway, here is the code: - */ - -.macro pixman_composite_out_reverse_8888_8888_process_pixblock_head - mvn v24.8b, v3.8b /* get inverted alpha */ - /* do alpha blending */ - umull v8.8h, v24.8b, v4.8b - umull v9.8h, v24.8b, v5.8b - umull v10.8h, v24.8b, v6.8b - umull v11.8h, v24.8b, v7.8b -.endm - -.macro pixman_composite_out_reverse_8888_8888_process_pixblock_tail - urshr v14.8h, v8.8h, #8 - urshr v15.8h, v9.8h, #8 - urshr v16.8h, v10.8h, #8 - urshr v17.8h, v11.8h, #8 - raddhn v28.8b, v14.8h, v8.8h - raddhn v29.8b, v15.8h, v9.8h - raddhn v30.8b, v16.8h, v10.8h - raddhn v31.8b, v17.8h, v11.8h -.endm - -/******************************************************************************/ - -.macro pixman_composite_over_8888_8888_process_pixblock_head - pixman_composite_out_reverse_8888_8888_process_pixblock_head -.endm - -.macro pixman_composite_over_8888_8888_process_pixblock_tail - pixman_composite_out_reverse_8888_8888_process_pixblock_tail - uqadd v28.8b, v0.8b, v28.8b - uqadd v29.8b, v1.8b, v29.8b - uqadd v30.8b, v2.8b, v30.8b - uqadd v31.8b, v3.8b, v31.8b -.endm - -.macro pixman_composite_over_8888_8888_process_pixblock_tail_head - ld4 {v4.8b, v5.8b, v6.8b, v7.8b}, [DST_R], #32 - urshr v14.8h, v8.8h, #8 - PF add PF_X, PF_X, #8 - PF tst PF_CTL, #0xF - urshr v15.8h, v9.8h, #8 - urshr v16.8h, v10.8h, #8 - urshr v17.8h, v11.8h, #8 - PF beq 10f - PF add PF_X, PF_X, #8 - PF sub PF_CTL, PF_CTL, #1 -10: - raddhn v28.8b, v14.8h, v8.8h - raddhn v29.8b, v15.8h, v9.8h - PF cmp PF_X, ORIG_W - raddhn v30.8b, v16.8h, v10.8h - raddhn v31.8b, v17.8h, v11.8h - uqadd v28.8b, v0.8b, v28.8b - uqadd v29.8b, v1.8b, v29.8b - uqadd v30.8b, v2.8b, v30.8b - uqadd v31.8b, v3.8b, v31.8b - fetch_src_pixblock - PF lsl DUMMY, PF_X, #src_bpp_shift - PF prfm PREFETCH_MODE, [PF_SRC, DUMMY] - mvn v22.8b, v3.8b - PF lsl DUMMY, PF_X, #dst_bpp_shift - PF prfm PREFETCH_MODE, [PF_DST, DUMMY] - st4 {v28.8b, v29.8b, v30.8b, v31.8b}, [DST_W], #32 - PF ble 10f - PF sub PF_X, PF_X, ORIG_W -10: - umull v8.8h, v22.8b, v4.8b - PF ble 10f - PF subs PF_CTL, PF_CTL, #0x10 -10: - umull v9.8h, v22.8b, v5.8b - PF ble 10f - PF lsl DUMMY, SRC_STRIDE, #src_bpp_shift - PF ldrsb DUMMY, [PF_SRC, DUMMY] - PF add PF_SRC, PF_SRC, #1 -10: - umull v10.8h, v22.8b, v6.8b - PF ble 10f - PF lsl DUMMY, DST_STRIDE, #dst_bpp_shift - PF ldrsb DUMMY, [PF_DST, DUMMY] - PF add PF_DST, PF_DST, #1 -10: - umull v11.8h, v22.8b, v7.8b -.endm - -generate_composite_function \ - pixman_composite_over_8888_8888_asm_neon, 32, 0, 32, \ - FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \ - 8, /* number of pixels, processed in a single block */ \ - 5, /* prefetch distance */ \ - default_init, \ - default_cleanup, \ - pixman_composite_over_8888_8888_process_pixblock_head, \ - pixman_composite_over_8888_8888_process_pixblock_tail, \ - pixman_composite_over_8888_8888_process_pixblock_tail_head - -generate_composite_function_single_scanline \ - pixman_composite_scanline_over_asm_neon, 32, 0, 32, \ - FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \ - 8, /* number of pixels, processed in a single block */ \ - default_init, \ - default_cleanup, \ - pixman_composite_over_8888_8888_process_pixblock_head, \ - pixman_composite_over_8888_8888_process_pixblock_tail, \ - pixman_composite_over_8888_8888_process_pixblock_tail_head - -/******************************************************************************/ - -.macro pixman_composite_over_n_8888_process_pixblock_head - /* deinterleaved source pixels in {v0, v1, v2, v3} */ - /* inverted alpha in {v24} */ - /* destination pixels in {v4, v5, v6, v7} */ - umull v8.8h, v24.8b, v4.8b - umull v9.8h, v24.8b, v5.8b - umull v10.8h, v24.8b, v6.8b - umull v11.8h, v24.8b, v7.8b -.endm - -.macro pixman_composite_over_n_8888_process_pixblock_tail - urshr v14.8h, v8.8h, #8 - urshr v15.8h, v9.8h, #8 - urshr v16.8h, v10.8h, #8 - urshr v17.8h, v11.8h, #8 - raddhn v28.8b, v14.8h, v8.8h - raddhn v29.8b, v15.8h, v9.8h - raddhn v30.8b, v16.8h, v10.8h - raddhn v31.8b, v17.8h, v11.8h - uqadd v28.8b, v0.8b, v28.8b - uqadd v29.8b, v1.8b, v29.8b - uqadd v30.8b, v2.8b, v30.8b - uqadd v31.8b, v3.8b, v31.8b -.endm - -.macro pixman_composite_over_n_8888_process_pixblock_tail_head - urshr v14.8h, v8.8h, #8 - urshr v15.8h, v9.8h, #8 - urshr v16.8h, v10.8h, #8 - urshr v17.8h, v11.8h, #8 - raddhn v28.8b, v14.8h, v8.8h - raddhn v29.8b, v15.8h, v9.8h - raddhn v30.8b, v16.8h, v10.8h - raddhn v31.8b, v17.8h, v11.8h - ld4 {v4.8b, v5.8b, v6.8b, v7.8b}, [DST_R], #32 - uqadd v28.8b, v0.8b, v28.8b - PF add PF_X, PF_X, #8 - PF tst PF_CTL, #0x0F - PF beq 10f - PF add PF_X, PF_X, #8 - PF sub PF_CTL, PF_CTL, #1 -10: - uqadd v29.8b, v1.8b, v29.8b - uqadd v30.8b, v2.8b, v30.8b - uqadd v31.8b, v3.8b, v31.8b - PF cmp PF_X, ORIG_W - umull v8.8h, v24.8b, v4.8b - PF lsl DUMMY, PF_X, #dst_bpp_shift - PF prfm PREFETCH_MODE, [PF_DST, DUMMY] - umull v9.8h, v24.8b, v5.8b - PF ble 10f - PF sub PF_X, PF_X, ORIG_W -10: - umull v10.8h, v24.8b, v6.8b - PF subs PF_CTL, PF_CTL, #0x10 - umull v11.8h, v24.8b, v7.8b - PF ble 10f - PF lsl DUMMY, DST_STRIDE, #dst_bpp_shift - PF ldrsb DUMMY, [PF_DST, DUMMY] - PF add PF_DST, PF_DST, #1 -10: - st4 {v28.8b, v29.8b, v30.8b, v31.8b}, [DST_W], #32 -.endm - -.macro pixman_composite_over_n_8888_init - mov v3.s[0], w4 - dup v0.8b, v3.b[0] - dup v1.8b, v3.b[1] - dup v2.8b, v3.b[2] - dup v3.8b, v3.b[3] - mvn v24.8b, v3.8b /* get inverted alpha */ -.endm - -generate_composite_function \ - pixman_composite_over_n_8888_asm_neon, 0, 0, 32, \ - FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \ - 8, /* number of pixels, processed in a single block */ \ - 5, /* prefetch distance */ \ - pixman_composite_over_n_8888_init, \ - default_cleanup, \ - pixman_composite_over_8888_8888_process_pixblock_head, \ - pixman_composite_over_8888_8888_process_pixblock_tail, \ - pixman_composite_over_n_8888_process_pixblock_tail_head - -/******************************************************************************/ - -.macro pixman_composite_src_n_8888_process_pixblock_head -.endm - -.macro pixman_composite_src_n_8888_process_pixblock_tail -.endm - -.macro pixman_composite_src_n_8888_process_pixblock_tail_head - st1 {v0.2s, v1.2s, v2.2s, v3.2s}, [DST_W], #32 -.endm - -.macro pixman_composite_src_n_8888_init - mov v0.s[0], w4 - dup v3.2s, v0.s[0] - dup v2.2s, v0.s[0] - dup v1.2s, v0.s[0] - dup v0.2s, v0.s[0] -.endm - -.macro pixman_composite_src_n_8888_cleanup -.endm - -generate_composite_function \ - pixman_composite_src_n_8888_asm_neon, 0, 0, 32, \ - FLAG_DST_WRITEONLY, \ - 8, /* number of pixels, processed in a single block */ \ - 0, /* prefetch distance */ \ - pixman_composite_src_n_8888_init, \ - pixman_composite_src_n_8888_cleanup, \ - pixman_composite_src_n_8888_process_pixblock_head, \ - pixman_composite_src_n_8888_process_pixblock_tail, \ - pixman_composite_src_n_8888_process_pixblock_tail_head, \ - 0, /* dst_w_basereg */ \ - 0, /* dst_r_basereg */ \ - 0, /* src_basereg */ \ - 0 /* mask_basereg */ - -/******************************************************************************/ - -.macro pixman_composite_src_8888_8888_process_pixblock_head -.endm - -.macro pixman_composite_src_8888_8888_process_pixblock_tail -.endm - -.macro pixman_composite_src_8888_8888_process_pixblock_tail_head - st1 {v0.2s, v1.2s, v2.2s, v3.2s}, [DST_W], #32 - fetch_src_pixblock - cache_preload 8, 8 -.endm - -generate_composite_function \ - pixman_composite_src_8888_8888_asm_neon, 32, 0, 32, \ - FLAG_DST_WRITEONLY, \ - 8, /* number of pixels, processed in a single block */ \ - 10, /* prefetch distance */ \ - default_init, \ - default_cleanup, \ - pixman_composite_src_8888_8888_process_pixblock_head, \ - pixman_composite_src_8888_8888_process_pixblock_tail, \ - pixman_composite_src_8888_8888_process_pixblock_tail_head, \ - 0, /* dst_w_basereg */ \ - 0, /* dst_r_basereg */ \ - 0, /* src_basereg */ \ - 0 /* mask_basereg */ - -/******************************************************************************/ diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.h b/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.h deleted file mode 100755 index 1103084..0000000 --- a/AXrLottie/src/main/cpp/src/vector/pixman/pixman-arma64-neon-asm.h +++ /dev/null @@ -1,1223 +0,0 @@ -/* - * Copyright © 2009 Nokia Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Author: Siarhei Siamashka (siarhei.siamashka@nokia.com) - */ - -/* - * This file contains a macro ('generate_composite_function') which can - * construct 2D image processing functions, based on a common template. - * Any combinations of source, destination and mask images with 8bpp, - * 16bpp, 24bpp, 32bpp color formats are supported. - * - * This macro takes care of: - * - handling of leading and trailing unaligned pixels - * - doing most of the work related to L2 cache preload - * - encourages the use of software pipelining for better instructions - * scheduling - * - * The user of this macro has to provide some configuration parameters - * (bit depths for the images, prefetch distance, etc.) and a set of - * macros, which should implement basic code chunks responsible for - * pixels processing. See 'pixman-armv8-neon-asm.S' file for the usage - * examples. - * - * TODO: - * - try overlapped pixel method (from Ian Rickards) when processing - * exactly two blocks of pixels - * - maybe add an option to do reverse scanline processing - */ - -/* - * Bit flags for 'generate_composite_function' macro which are used - * to tune generated functions behavior. - */ -.set FLAG_DST_WRITEONLY, 0 -.set FLAG_DST_READWRITE, 1 -.set FLAG_DEINTERLEAVE_32BPP, 2 - -/* - * Constants for selecting preferable prefetch type. - */ -.set PREFETCH_TYPE_NONE, 0 /* No prefetch at all */ -.set PREFETCH_TYPE_SIMPLE, 1 /* A simple, fixed-distance-ahead prefetch */ -.set PREFETCH_TYPE_ADVANCED, 2 /* Advanced fine-grained prefetch */ - -/* - * prefetch mode - * available modes are: - * pldl1keep - * pldl1strm - * pldl2keep - * pldl2strm - * pldl3keep - * pldl3strm - */ -#define PREFETCH_MODE pldl1keep - -/* - * Definitions of supplementary pixld/pixst macros (for partial load/store of - * pixel data). - */ - -.macro pixldst1 op, elem_size, reg1, mem_operand, abits - op {v®1&.&elem_size}, [&mem_operand&], #8 -.endm - -.macro pixldst2 op, elem_size, reg1, reg2, mem_operand, abits - op {v®1&.&elem_size, v®2&.&elem_size}, [&mem_operand&], #16 -.endm - -.macro pixldst4 op, elem_size, reg1, reg2, reg3, reg4, mem_operand, abits - op {v®1&.&elem_size, v®2&.&elem_size, v®3&.&elem_size, v®4&.&elem_size}, [&mem_operand&], #32 -.endm - -.macro pixldst0 op, elem_size, reg1, idx, mem_operand, abits, bytes - op {v®1&.&elem_size}[idx], [&mem_operand&], #&bytes& -.endm - -.macro pixldst3 op, elem_size, reg1, reg2, reg3, mem_operand - op {v®1&.&elem_size, v®2&.&elem_size, v®3&.&elem_size}, [&mem_operand&], #24 -.endm - -.macro pixldst30 op, elem_size, reg1, reg2, reg3, idx, mem_operand - op {v®1&.&elem_size, v®2&.&elem_size, v®3&.&elem_size}[idx], [&mem_operand&], #3 -.endm - -.macro pixldst numbytes, op, elem_size, basereg, mem_operand, abits -.if numbytes == 32 - .if elem_size==32 - pixldst4 op, 2s, %(basereg+4), %(basereg+5), \ - %(basereg+6), %(basereg+7), mem_operand, abits - .elseif elem_size==16 - pixldst4 op, 4h, %(basereg+4), %(basereg+5), \ - %(basereg+6), %(basereg+7), mem_operand, abits - .else - pixldst4 op, 8b, %(basereg+4), %(basereg+5), \ - %(basereg+6), %(basereg+7), mem_operand, abits - .endif -.elseif numbytes == 16 - .if elem_size==32 - pixldst2 op, 2s, %(basereg+2), %(basereg+3), mem_operand, abits - .elseif elem_size==16 - pixldst2 op, 4h, %(basereg+2), %(basereg+3), mem_operand, abits - .else - pixldst2 op, 8b, %(basereg+2), %(basereg+3), mem_operand, abits - .endif -.elseif numbytes == 8 - .if elem_size==32 - pixldst1 op, 2s, %(basereg+1), mem_operand, abits - .elseif elem_size==16 - pixldst1 op, 4h, %(basereg+1), mem_operand, abits - .else - pixldst1 op, 8b, %(basereg+1), mem_operand, abits - .endif -.elseif numbytes == 4 - .if !RESPECT_STRICT_ALIGNMENT || (elem_size == 32) - pixldst0 op, s, %(basereg+0), 1, mem_operand, abits, 4 - .elseif elem_size == 16 - pixldst0 op, h, %(basereg+0), 2, mem_operand, abits, 2 - pixldst0 op, h, %(basereg+0), 3, mem_operand, abits, 2 - .else - pixldst0 op, b, %(basereg+0), 4, mem_operand, abits, 1 - pixldst0 op, b, %(basereg+0), 5, mem_operand, abits, 1 - pixldst0 op, b, %(basereg+0), 6, mem_operand, abits, 1 - pixldst0 op, b, %(basereg+0), 7, mem_operand, abits, 1 - .endif -.elseif numbytes == 2 - .if !RESPECT_STRICT_ALIGNMENT || (elem_size == 16) - pixldst0 op, h, %(basereg+0), 1, mem_operand, abits, 2 - .else - pixldst0 op, b, %(basereg+0), 2, mem_operand, abits, 1 - pixldst0 op, b, %(basereg+0), 3, mem_operand, abits, 1 - .endif -.elseif numbytes == 1 - pixldst0 op, b, %(basereg+0), 1, mem_operand, abits, 1 -.else - .error "unsupported size: numbytes" -.endif -.endm - -.macro pixld numpix, bpp, basereg, mem_operand, abits=0 -.if bpp > 0 -.if (bpp == 32) && (numpix == 8) && (DEINTERLEAVE_32BPP_ENABLED != 0) - pixldst4 ld4, 8b, %(basereg+4), %(basereg+5), \ - %(basereg+6), %(basereg+7), mem_operand, abits -.elseif (bpp == 24) && (numpix == 8) - pixldst3 ld3, 8b, %(basereg+3), %(basereg+4), %(basereg+5), mem_operand -.elseif (bpp == 24) && (numpix == 4) - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 4, mem_operand - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 5, mem_operand - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 6, mem_operand - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 7, mem_operand -.elseif (bpp == 24) && (numpix == 2) - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 2, mem_operand - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 3, mem_operand -.elseif (bpp == 24) && (numpix == 1) - pixldst30 ld3, b, %(basereg+0), %(basereg+1), %(basereg+2), 1, mem_operand -.else - pixldst %(numpix * bpp / 8), ld1, %(bpp), basereg, mem_operand, abits -.endif -.endif -.endm - -.macro pixst numpix, bpp, basereg, mem_operand, abits=0 -.if bpp > 0 -.if (bpp == 32) && (numpix == 8) && (DEINTERLEAVE_32BPP_ENABLED != 0) - pixldst4 st4, 8b, %(basereg+4), %(basereg+5), \ - %(basereg+6), %(basereg+7), mem_operand, abits -.elseif (bpp == 24) && (numpix == 8) - pixldst3 st3, 8b, %(basereg+3), %(basereg+4), %(basereg+5), mem_operand -.elseif (bpp == 24) && (numpix == 4) - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 4, mem_operand - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 5, mem_operand - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 6, mem_operand - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 7, mem_operand -.elseif (bpp == 24) && (numpix == 2) - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 2, mem_operand - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 3, mem_operand -.elseif (bpp == 24) && (numpix == 1) - pixldst30 st3, b, %(basereg+0), %(basereg+1), %(basereg+2), 1, mem_operand -.else - pixldst %(numpix * bpp / 8), st1, %(bpp), basereg, mem_operand, abits -.endif -.endif -.endm - -.macro pixld_a numpix, bpp, basereg, mem_operand -.if (bpp * numpix) <= 128 - pixld numpix, bpp, basereg, mem_operand, %(bpp * numpix) -.else - pixld numpix, bpp, basereg, mem_operand, 128 -.endif -.endm - -.macro pixst_a numpix, bpp, basereg, mem_operand -.if (bpp * numpix) <= 128 - pixst numpix, bpp, basereg, mem_operand, %(bpp * numpix) -.else - pixst numpix, bpp, basereg, mem_operand, 128 -.endif -.endm - -/* - * Pixel fetcher for nearest scaling (needs TMP1, TMP2, VX, UNIT_X register - * aliases to be defined) - */ -.macro pixld1_s elem_size, reg1, mem_operand -.if elem_size == 16 - asr TMP1, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP1, mem_operand, TMP1, lsl #1 - asr TMP2, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP2, mem_operand, TMP2, lsl #1 - ld1 {v®1&.h}[0], [TMP1] - asr TMP1, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP1, mem_operand, TMP1, lsl #1 - ld1 {v®1&.h}[1], [TMP2] - asr TMP2, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP2, mem_operand, TMP2, lsl #1 - ld1 {v®1&.h}[2], [TMP1] - ld1 {v®1&.h}[3], [TMP2] -.elseif elem_size == 32 - asr TMP1, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP1, mem_operand, TMP1, lsl #2 - asr TMP2, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP2, mem_operand, TMP2, lsl #2 - ld1 {v®1&.s}[0], [TMP1] - ld1 {v®1&.s}[1], [TMP2] -.else - .error "unsupported" -.endif -.endm - -.macro pixld2_s elem_size, reg1, reg2, mem_operand -.if 0 /* elem_size == 32 */ - mov TMP1, VX, asr #16 - add VX, VX, UNIT_X, asl #1 - add TMP1, mem_operand, TMP1, asl #2 - mov TMP2, VX, asr #16 - sub VX, VX, UNIT_X - add TMP2, mem_operand, TMP2, asl #2 - ld1 {v®1&.s}[0], [TMP1] - mov TMP1, VX, asr #16 - add VX, VX, UNIT_X, asl #1 - add TMP1, mem_operand, TMP1, asl #2 - ld1 {v®2&.s}[0], [TMP2, :32] - mov TMP2, VX, asr #16 - add VX, VX, UNIT_X - add TMP2, mem_operand, TMP2, asl #2 - ld1 {v®1&.s}[1], [TMP1] - ld1 {v®2&.s}[1], [TMP2] -.else - pixld1_s elem_size, reg1, mem_operand - pixld1_s elem_size, reg2, mem_operand -.endif -.endm - -.macro pixld0_s elem_size, reg1, idx, mem_operand -.if elem_size == 16 - asr TMP1, VX, #16 - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP1, mem_operand, TMP1, lsl #1 - ld1 {v®1&.h}[idx], [TMP1] -.elseif elem_size == 32 - asr DUMMY, VX, #16 - mov TMP1, DUMMY - adds VX, VX, UNIT_X - bmi 55f -5: subs VX, VX, SRC_WIDTH_FIXED - bpl 5b -55: - add TMP1, mem_operand, TMP1, lsl #2 - ld1 {v®1&.s}[idx], [TMP1] -.endif -.endm - -.macro pixld_s_internal numbytes, elem_size, basereg, mem_operand -.if numbytes == 32 - pixld2_s elem_size, %(basereg+4), %(basereg+5), mem_operand - pixld2_s elem_size, %(basereg+6), %(basereg+7), mem_operand - pixdeinterleave elem_size, %(basereg+4) -.elseif numbytes == 16 - pixld2_s elem_size, %(basereg+2), %(basereg+3), mem_operand -.elseif numbytes == 8 - pixld1_s elem_size, %(basereg+1), mem_operand -.elseif numbytes == 4 - .if elem_size == 32 - pixld0_s elem_size, %(basereg+0), 1, mem_operand - .elseif elem_size == 16 - pixld0_s elem_size, %(basereg+0), 2, mem_operand - pixld0_s elem_size, %(basereg+0), 3, mem_operand - .else - pixld0_s elem_size, %(basereg+0), 4, mem_operand - pixld0_s elem_size, %(basereg+0), 5, mem_operand - pixld0_s elem_size, %(basereg+0), 6, mem_operand - pixld0_s elem_size, %(basereg+0), 7, mem_operand - .endif -.elseif numbytes == 2 - .if elem_size == 16 - pixld0_s elem_size, %(basereg+0), 1, mem_operand - .else - pixld0_s elem_size, %(basereg+0), 2, mem_operand - pixld0_s elem_size, %(basereg+0), 3, mem_operand - .endif -.elseif numbytes == 1 - pixld0_s elem_size, %(basereg+0), 1, mem_operand -.else - .error "unsupported size: numbytes" -.endif -.endm - -.macro pixld_s numpix, bpp, basereg, mem_operand -.if bpp > 0 - pixld_s_internal %(numpix * bpp / 8), %(bpp), basereg, mem_operand -.endif -.endm - -.macro vuzp8 reg1, reg2 - umov DUMMY, v16.d[0] - uzp1 v16.8b, v®1&.8b, v®2&.8b - uzp2 v®2&.8b, v®1&.8b, v®2&.8b - mov v®1&.8b, v16.8b - mov v16.d[0], DUMMY -.endm - -.macro vzip8 reg1, reg2 - umov DUMMY, v16.d[0] - zip1 v16.8b, v®1&.8b, v®2&.8b - zip2 v®2&.8b, v®1&.8b, v®2&.8b - mov v®1&.8b, v16.8b - mov v16.d[0], DUMMY -.endm - -/* deinterleave B, G, R, A channels for eight 32bpp pixels in 4 registers */ -.macro pixdeinterleave bpp, basereg -.if (bpp == 32) && (DEINTERLEAVE_32BPP_ENABLED != 0) - vuzp8 %(basereg+0), %(basereg+1) - vuzp8 %(basereg+2), %(basereg+3) - vuzp8 %(basereg+1), %(basereg+3) - vuzp8 %(basereg+0), %(basereg+2) -.endif -.endm - -/* interleave B, G, R, A channels for eight 32bpp pixels in 4 registers */ -.macro pixinterleave bpp, basereg -.if (bpp == 32) && (DEINTERLEAVE_32BPP_ENABLED != 0) - vzip8 %(basereg+0), %(basereg+2) - vzip8 %(basereg+1), %(basereg+3) - vzip8 %(basereg+2), %(basereg+3) - vzip8 %(basereg+0), %(basereg+1) -.endif -.endm - -/* - * This is a macro for implementing cache preload. The main idea is that - * cache preload logic is mostly independent from the rest of pixels - * processing code. It starts at the top left pixel and moves forward - * across pixels and can jump across scanlines. Prefetch distance is - * handled in an 'incremental' way: it starts from 0 and advances to the - * optimal distance over time. After reaching optimal prefetch distance, - * it is kept constant. There are some checks which prevent prefetching - * unneeded pixel lines below the image (but it still can prefetch a bit - * more data on the right side of the image - not a big issue and may - * be actually helpful when rendering text glyphs). Additional trick is - * the use of LDR instruction for prefetch instead of PLD when moving to - * the next line, the point is that we have a high chance of getting TLB - * miss in this case, and PLD would be useless. - * - * This sounds like it may introduce a noticeable overhead (when working with - * fully cached data). But in reality, due to having a separate pipeline and - * instruction queue for NEON unit in ARM Cortex-A8, normal ARM code can - * execute simultaneously with NEON and be completely shadowed by it. Thus - * we get no performance overhead at all (*). This looks like a very nice - * feature of Cortex-A8, if used wisely. We don't have a hardware prefetcher, - * but still can implement some rather advanced prefetch logic in software - * for almost zero cost! - * - * (*) The overhead of the prefetcher is visible when running some trivial - * pixels processing like simple copy. Anyway, having prefetch is a must - * when working with the graphics data. - */ -.macro PF a, x:vararg -.if (PREFETCH_TYPE_CURRENT == PREFETCH_TYPE_ADVANCED) - a x -.endif -.endm - -.macro cache_preload std_increment, boost_increment -.if (src_bpp_shift >= 0) || (dst_r_bpp != 0) || (mask_bpp_shift >= 0) -.if std_increment != 0 - PF add PF_X, PF_X, #std_increment -.endif - PF tst PF_CTL, #0xF - PF beq 71f - PF add PF_X, PF_X, #boost_increment - PF sub PF_CTL, PF_CTL, #1 -71: - PF cmp PF_X, ORIG_W -.if src_bpp_shift >= 0 - PF lsl DUMMY, PF_X, #src_bpp_shift - PF prfm PREFETCH_MODE, [PF_SRC, DUMMY] -.endif -.if dst_r_bpp != 0 - PF lsl DUMMY, PF_X, #dst_bpp_shift - PF prfm PREFETCH_MODE, [PF_DST, DUMMY] -.endif -.if mask_bpp_shift >= 0 - PF lsl DUMMY, PF_X, #mask_bpp_shift - PF prfm PREFETCH_MODE, [PF_MASK, DUMMY] -.endif - PF ble 71f - PF sub PF_X, PF_X, ORIG_W - PF subs PF_CTL, PF_CTL, #0x10 -71: - PF ble 72f -.if src_bpp_shift >= 0 - PF lsl DUMMY, SRC_STRIDE, #src_bpp_shift - PF ldrsb DUMMY, [PF_SRC, DUMMY] - PF add PF_SRC, PF_SRC, #1 -.endif -.if dst_r_bpp != 0 - PF lsl DUMMY, DST_STRIDE, #dst_bpp_shift - PF ldrsb DUMMY, [PF_DST, DUMMY] - PF add PF_DST, PF_DST, #1 -.endif -.if mask_bpp_shift >= 0 - PF lsl DUMMY, MASK_STRIDE, #mask_bpp_shift - PF ldrsb DUMMY, [PF_MASK, DUMMY] - PF add PF_MASK, PF_MASK, #1 -.endif -72: -.endif -.endm - -.macro cache_preload_simple -.if (PREFETCH_TYPE_CURRENT == PREFETCH_TYPE_SIMPLE) -.if src_bpp > 0 - prfm PREFETCH_MODE, [SRC, #(PREFETCH_DISTANCE_SIMPLE * src_bpp / 8)] -.endif -.if dst_r_bpp > 0 - prfm PREFETCH_MODE, [DST_R, #(PREFETCH_DISTANCE_SIMPLE * dst_r_bpp / 8)] -.endif -.if mask_bpp > 0 - prfm PREFETCH_MODE, [MASK, #(PREFETCH_DISTANCE_SIMPLE * mask_bpp / 8)] -.endif -.endif -.endm - -.macro fetch_mask_pixblock - pixld pixblock_size, mask_bpp, \ - (mask_basereg - pixblock_size * mask_bpp / 64), MASK -.endm - -/* - * Macro which is used to process leading pixels until destination - * pointer is properly aligned (at 16 bytes boundary). When destination - * buffer uses 16bpp format, this is unnecessary, or even pointless. - */ -.macro ensure_destination_ptr_alignment process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head -.if dst_w_bpp != 24 - tst DST_R, #0xF - beq 52f -.irp lowbit, 1, 2, 4, 8, 16 -local skip1 -.if (dst_w_bpp <= (lowbit * 8)) && ((lowbit * 8) < (pixblock_size * dst_w_bpp)) -.if lowbit < 16 /* we don't need more than 16-byte alignment */ - tst DST_R, #lowbit - beq 51f -.endif - pixld_src (lowbit * 8 / dst_w_bpp), src_bpp, src_basereg, SRC - pixld (lowbit * 8 / dst_w_bpp), mask_bpp, mask_basereg, MASK -.if dst_r_bpp > 0 - pixld_a (lowbit * 8 / dst_r_bpp), dst_r_bpp, dst_r_basereg, DST_R -.else - add DST_R, DST_R, #lowbit -.endif - PF add PF_X, PF_X, #(lowbit * 8 / dst_w_bpp) - sub W, W, #(lowbit * 8 / dst_w_bpp) -51: -.endif -.endr - pixdeinterleave src_bpp, src_basereg - pixdeinterleave mask_bpp, mask_basereg - pixdeinterleave dst_r_bpp, dst_r_basereg - - process_pixblock_head - cache_preload 0, pixblock_size - cache_preload_simple - process_pixblock_tail - - pixinterleave dst_w_bpp, dst_w_basereg - -.irp lowbit, 1, 2, 4, 8, 16 -.if (dst_w_bpp <= (lowbit * 8)) && ((lowbit * 8) < (pixblock_size * dst_w_bpp)) -.if lowbit < 16 /* we don't need more than 16-byte alignment */ - tst DST_W, #lowbit - beq 51f -.endif - pixst_a (lowbit * 8 / dst_w_bpp), dst_w_bpp, dst_w_basereg, DST_W -51: -.endif -.endr -.endif -52: -.endm - -/* - * Special code for processing up to (pixblock_size - 1) remaining - * trailing pixels. As SIMD processing performs operation on - * pixblock_size pixels, anything smaller than this has to be loaded - * and stored in a special way. Loading and storing of pixel data is - * performed in such a way that we fill some 'slots' in the NEON - * registers (some slots naturally are unused), then perform compositing - * operation as usual. In the end, the data is taken from these 'slots' - * and saved to memory. - * - * cache_preload_flag - allows to suppress prefetch if - * set to 0 - * dst_aligned_flag - selects whether destination buffer - * is aligned - */ -.macro process_trailing_pixels cache_preload_flag, \ - dst_aligned_flag, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - tst W, #(pixblock_size - 1) - beq 52f -.irp chunk_size, 16, 8, 4, 2, 1 -.if pixblock_size > chunk_size - tst W, #chunk_size - beq 51f - pixld_src chunk_size, src_bpp, src_basereg, SRC - pixld chunk_size, mask_bpp, mask_basereg, MASK -.if dst_aligned_flag != 0 - pixld_a chunk_size, dst_r_bpp, dst_r_basereg, DST_R -.else - pixld chunk_size, dst_r_bpp, dst_r_basereg, DST_R -.endif -.if cache_preload_flag != 0 - PF add PF_X, PF_X, #chunk_size -.endif -51: -.endif -.endr - pixdeinterleave src_bpp, src_basereg - pixdeinterleave mask_bpp, mask_basereg - pixdeinterleave dst_r_bpp, dst_r_basereg - - process_pixblock_head -.if cache_preload_flag != 0 - cache_preload 0, pixblock_size - cache_preload_simple -.endif - process_pixblock_tail - pixinterleave dst_w_bpp, dst_w_basereg -.irp chunk_size, 16, 8, 4, 2, 1 -.if pixblock_size > chunk_size - tst W, #chunk_size - beq 51f -.if dst_aligned_flag != 0 - pixst_a chunk_size, dst_w_bpp, dst_w_basereg, DST_W -.else - pixst chunk_size, dst_w_bpp, dst_w_basereg, DST_W -.endif -51: -.endif -.endr -52: -.endm - -/* - * Macro, which performs all the needed operations to switch to the next - * scanline and start the next loop iteration unless all the scanlines - * are already processed. - */ -.macro advance_to_next_scanline start_of_loop_label - mov W, ORIG_W - add DST_W, DST_W, DST_STRIDE, lsl #dst_bpp_shift -.if src_bpp != 0 - add SRC, SRC, SRC_STRIDE, lsl #src_bpp_shift -.endif -.if mask_bpp != 0 - add MASK, MASK, MASK_STRIDE, lsl #mask_bpp_shift -.endif -.if (dst_w_bpp != 24) - sub DST_W, DST_W, W, lsl #dst_bpp_shift -.endif -.if (src_bpp != 24) && (src_bpp != 0) - sub SRC, SRC, W, lsl #src_bpp_shift -.endif -.if (mask_bpp != 24) && (mask_bpp != 0) - sub MASK, MASK, W, lsl #mask_bpp_shift -.endif - subs H, H, #1 - mov DST_R, DST_W - bge start_of_loop_label -.endm - -/* - * Registers are allocated in the following way by default: - * v0, v1, v2, v3 - reserved for loading source pixel data - * v4, v5, v6, v7 - reserved for loading destination pixel data - * v24, v25, v26, v27 - reserved for loading mask pixel data - * v28, v29, v30, v31 - final destination pixel data for writeback to memory - */ -.macro generate_composite_function fname, \ - src_bpp_, \ - mask_bpp_, \ - dst_w_bpp_, \ - flags, \ - pixblock_size_, \ - prefetch_distance, \ - init, \ - cleanup, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head, \ - dst_w_basereg_ = 28, \ - dst_r_basereg_ = 4, \ - src_basereg_ = 0, \ - mask_basereg_ = 24 - - pixman_asm_function fname - stp x29, x30, [sp, -16]! - mov x29, sp - sub sp, sp, 232 /* push all registers */ - sub x29, x29, 64 - st1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], #32 - st1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], #32 - stp x8, x9, [x29, -80] - stp x10, x11, [x29, -96] - stp x12, x13, [x29, -112] - stp x14, x15, [x29, -128] - stp x16, x17, [x29, -144] - stp x18, x19, [x29, -160] - stp x20, x21, [x29, -176] - stp x22, x23, [x29, -192] - stp x24, x25, [x29, -208] - stp x26, x27, [x29, -224] - str x28, [x29, -232] - -/* - * Select prefetch type for this function. If prefetch distance is - * set to 0 or one of the color formats is 24bpp, SIMPLE prefetch - * has to be used instead of ADVANCED. - */ - .set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_DEFAULT -.if prefetch_distance == 0 - .set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_NONE -.elseif (PREFETCH_TYPE_CURRENT > PREFETCH_TYPE_SIMPLE) && \ - ((src_bpp_ == 24) || (mask_bpp_ == 24) || (dst_w_bpp_ == 24)) - .set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_SIMPLE -.endif - -/* - * Make some macro arguments globally visible and accessible - * from other macros - */ - .set src_bpp, src_bpp_ - .set mask_bpp, mask_bpp_ - .set dst_w_bpp, dst_w_bpp_ - .set pixblock_size, pixblock_size_ - .set dst_w_basereg, dst_w_basereg_ - .set dst_r_basereg, dst_r_basereg_ - .set src_basereg, src_basereg_ - .set mask_basereg, mask_basereg_ - - .macro pixld_src x:vararg - pixld x - .endm - .macro fetch_src_pixblock - pixld_src pixblock_size, src_bpp, \ - (src_basereg - pixblock_size * src_bpp / 64), SRC - .endm -/* - * Assign symbolic names to registers - */ - W .req x0 /* width (is updated during processing) */ - H .req x1 /* height (is updated during processing) */ - DST_W .req x2 /* destination buffer pointer for writes */ - DST_STRIDE .req x3 /* destination image stride */ - SRC .req x4 /* source buffer pointer */ - SRC_STRIDE .req x5 /* source image stride */ - MASK .req x6 /* mask pointer */ - MASK_STRIDE .req x7 /* mask stride */ - - DST_R .req x8 /* destination buffer pointer for reads */ - - PF_CTL .req x9 /* combined lines counter and prefetch */ - /* distance increment counter */ - PF_X .req x10 /* pixel index in a scanline for current */ - /* pretetch position */ - PF_SRC .req x11 /* pointer to source scanline start */ - /* for prefetch purposes */ - PF_DST .req x12 /* pointer to destination scanline start */ - /* for prefetch purposes */ - PF_MASK .req x13 /* pointer to mask scanline start */ - /* for prefetch purposes */ - - ORIG_W .req x14 /* saved original width */ - DUMMY .req x15 /* temporary register */ - - sxtw x0, w0 - sxtw x1, w1 - sxtw x3, w3 - sxtw x5, w5 - sxtw x7, w7 - - .set mask_bpp_shift, -1 -.if src_bpp == 32 - .set src_bpp_shift, 2 -.elseif src_bpp == 24 - .set src_bpp_shift, 0 -.elseif src_bpp == 16 - .set src_bpp_shift, 1 -.elseif src_bpp == 8 - .set src_bpp_shift, 0 -.elseif src_bpp == 0 - .set src_bpp_shift, -1 -.else - .error "requested src bpp (src_bpp) is not supported" -.endif -.if mask_bpp == 32 - .set mask_bpp_shift, 2 -.elseif mask_bpp == 24 - .set mask_bpp_shift, 0 -.elseif mask_bpp == 8 - .set mask_bpp_shift, 0 -.elseif mask_bpp == 0 - .set mask_bpp_shift, -1 -.else - .error "requested mask bpp (mask_bpp) is not supported" -.endif -.if dst_w_bpp == 32 - .set dst_bpp_shift, 2 -.elseif dst_w_bpp == 24 - .set dst_bpp_shift, 0 -.elseif dst_w_bpp == 16 - .set dst_bpp_shift, 1 -.elseif dst_w_bpp == 8 - .set dst_bpp_shift, 0 -.else - .error "requested dst bpp (dst_w_bpp) is not supported" -.endif - -.if (((flags) & FLAG_DST_READWRITE) != 0) - .set dst_r_bpp, dst_w_bpp -.else - .set dst_r_bpp, 0 -.endif -.if (((flags) & FLAG_DEINTERLEAVE_32BPP) != 0) - .set DEINTERLEAVE_32BPP_ENABLED, 1 -.else - .set DEINTERLEAVE_32BPP_ENABLED, 0 -.endif - -.if prefetch_distance < 0 || prefetch_distance > 15 - .error "invalid prefetch distance (prefetch_distance)" -.endif - - PF mov PF_X, #0 - mov DST_R, DST_W - -.if src_bpp == 24 - sub SRC_STRIDE, SRC_STRIDE, W - sub SRC_STRIDE, SRC_STRIDE, W, lsl #1 -.endif -.if mask_bpp == 24 - sub MASK_STRIDE, MASK_STRIDE, W - sub MASK_STRIDE, MASK_STRIDE, W, lsl #1 -.endif -.if dst_w_bpp == 24 - sub DST_STRIDE, DST_STRIDE, W - sub DST_STRIDE, DST_STRIDE, W, lsl #1 -.endif - -/* - * Setup advanced prefetcher initial state - */ - PF mov PF_SRC, SRC - PF mov PF_DST, DST_R - PF mov PF_MASK, MASK - /* PF_CTL = prefetch_distance | ((h - 1) << 4) */ - PF lsl DUMMY, H, #4 - PF mov PF_CTL, DUMMY - PF add PF_CTL, PF_CTL, #(prefetch_distance - 0x10) - - init - subs H, H, #1 - mov ORIG_W, W - blt 9f - cmp W, #(pixblock_size * 2) - blt 800f -/* - * This is the start of the pipelined loop, which if optimized for - * long scanlines - */ -0: - ensure_destination_ptr_alignment process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - - /* Implement "head (tail_head) ... (tail_head) tail" loop pattern */ - pixld_a pixblock_size, dst_r_bpp, \ - (dst_r_basereg - pixblock_size * dst_r_bpp / 64), DST_R - fetch_src_pixblock - pixld pixblock_size, mask_bpp, \ - (mask_basereg - pixblock_size * mask_bpp / 64), MASK - PF add PF_X, PF_X, #pixblock_size - process_pixblock_head - cache_preload 0, pixblock_size - cache_preload_simple - subs W, W, #(pixblock_size * 2) - blt 200f - -100: - process_pixblock_tail_head - cache_preload_simple - subs W, W, #pixblock_size - bge 100b - -200: - process_pixblock_tail - pixst_a pixblock_size, dst_w_bpp, \ - (dst_w_basereg - pixblock_size * dst_w_bpp / 64), DST_W - - /* Process the remaining trailing pixels in the scanline */ - process_trailing_pixels 1, 1, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - advance_to_next_scanline 0b - - cleanup -1000: - /* pop all registers */ - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - ldp x8, x9, [x29, -80] - ldp x10, x11, [x29, -96] - ldp x12, x13, [x29, -112] - ldp x14, x15, [x29, -128] - ldp x16, x17, [x29, -144] - ldp x18, x19, [x29, -160] - ldp x20, x21, [x29, -176] - ldp x22, x23, [x29, -192] - ldp x24, x25, [x29, -208] - ldp x26, x27, [x29, -224] - ldr x28, [x29, -232] - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ -/* - * This is the start of the loop, designed to process images with small width - * (less than pixblock_size * 2 pixels). In this case neither pipelining - * nor prefetch are used. - */ -800: - /* Process exactly pixblock_size pixels if needed */ - tst W, #pixblock_size - beq 100f - pixld pixblock_size, dst_r_bpp, \ - (dst_r_basereg - pixblock_size * dst_r_bpp / 64), DST_R - fetch_src_pixblock - pixld pixblock_size, mask_bpp, \ - (mask_basereg - pixblock_size * mask_bpp / 64), MASK - process_pixblock_head - process_pixblock_tail - pixst pixblock_size, dst_w_bpp, \ - (dst_w_basereg - pixblock_size * dst_w_bpp / 64), DST_W -100: - /* Process the remaining trailing pixels in the scanline */ - process_trailing_pixels 0, 0, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - advance_to_next_scanline 800b -9: - cleanup - /* pop all registers */ - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - ldp x8, x9, [x29, -80] - ldp x10, x11, [x29, -96] - ldp x12, x13, [x29, -112] - ldp x14, x15, [x29, -128] - ldp x16, x17, [x29, -144] - ldp x18, x19, [x29, -160] - ldp x20, x21, [x29, -176] - ldp x22, x23, [x29, -192] - ldp x24, x25, [x29, -208] - ldp x26, x27, [x29, -224] - ldr x28, [x29, -232] - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ - - .purgem fetch_src_pixblock - .purgem pixld_src - - .unreq SRC - .unreq MASK - .unreq DST_R - .unreq DST_W - .unreq ORIG_W - .unreq W - .unreq H - .unreq SRC_STRIDE - .unreq DST_STRIDE - .unreq MASK_STRIDE - .unreq PF_CTL - .unreq PF_X - .unreq PF_SRC - .unreq PF_DST - .unreq PF_MASK - .unreq DUMMY - .endfunc -.endm - -/* - * A simplified variant of function generation template for a single - * scanline processing (for implementing pixman combine functions) - */ -.macro generate_composite_function_scanline use_nearest_scaling, \ - fname, \ - src_bpp_, \ - mask_bpp_, \ - dst_w_bpp_, \ - flags, \ - pixblock_size_, \ - init, \ - cleanup, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head, \ - dst_w_basereg_ = 28, \ - dst_r_basereg_ = 4, \ - src_basereg_ = 0, \ - mask_basereg_ = 24 - - pixman_asm_function fname - .set PREFETCH_TYPE_CURRENT, PREFETCH_TYPE_NONE - -/* - * Make some macro arguments globally visible and accessible - * from other macros - */ - .set src_bpp, src_bpp_ - .set mask_bpp, mask_bpp_ - .set dst_w_bpp, dst_w_bpp_ - .set pixblock_size, pixblock_size_ - .set dst_w_basereg, dst_w_basereg_ - .set dst_r_basereg, dst_r_basereg_ - .set src_basereg, src_basereg_ - .set mask_basereg, mask_basereg_ - -.if use_nearest_scaling != 0 - /* - * Assign symbolic names to registers for nearest scaling - */ - W .req x0 - DST_W .req x1 - SRC .req x2 - VX .req x3 - UNIT_X .req x4 - SRC_WIDTH_FIXED .req x5 - MASK .req x6 - TMP1 .req x8 - TMP2 .req x9 - DST_R .req x10 - DUMMY .req x30 - - .macro pixld_src x:vararg - pixld_s x - .endm - - sxtw x0, w0 - sxtw x3, w3 - sxtw x4, w4 - sxtw x5, w5 - - stp x29, x30, [sp, -16]! - mov x29, sp - sub sp, sp, 88 - sub x29, x29, 64 - st1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - st1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - stp x8, x9, [x29, -80] - str x10, [x29, -88] -.else - /* - * Assign symbolic names to registers - */ - W .req x0 /* width (is updated during processing) */ - DST_W .req x1 /* destination buffer pointer for writes */ - SRC .req x2 /* source buffer pointer */ - MASK .req x3 /* mask pointer */ - DST_R .req x4 /* destination buffer pointer for reads */ - DUMMY .req x30 - - .macro pixld_src x:vararg - pixld x - .endm - - sxtw x0, w0 - - stp x29, x30, [sp, -16]! - mov x29, sp - sub sp, sp, 64 - sub x29, x29, 64 - st1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - st1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 -.endif - -.if (((flags) & FLAG_DST_READWRITE) != 0) - .set dst_r_bpp, dst_w_bpp -.else - .set dst_r_bpp, 0 -.endif -.if (((flags) & FLAG_DEINTERLEAVE_32BPP) != 0) - .set DEINTERLEAVE_32BPP_ENABLED, 1 -.else - .set DEINTERLEAVE_32BPP_ENABLED, 0 -.endif - - .macro fetch_src_pixblock - pixld_src pixblock_size, src_bpp, \ - (src_basereg - pixblock_size * src_bpp / 64), SRC - .endm - - init - mov DST_R, DST_W - - cmp W, #pixblock_size - blt 800f - - ensure_destination_ptr_alignment process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - - subs W, W, #pixblock_size - blt 700f - - /* Implement "head (tail_head) ... (tail_head) tail" loop pattern */ - pixld_a pixblock_size, dst_r_bpp, \ - (dst_r_basereg - pixblock_size * dst_r_bpp / 64), DST_R - fetch_src_pixblock - pixld pixblock_size, mask_bpp, \ - (mask_basereg - pixblock_size * mask_bpp / 64), MASK - process_pixblock_head - subs W, W, #pixblock_size - blt 200f -100: - process_pixblock_tail_head - subs W, W, #pixblock_size - bge 100b -200: - process_pixblock_tail - pixst_a pixblock_size, dst_w_bpp, \ - (dst_w_basereg - pixblock_size * dst_w_bpp / 64), DST_W -700: - /* Process the remaining trailing pixels in the scanline (dst aligned) */ - process_trailing_pixels 0, 1, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - - cleanup -.if use_nearest_scaling != 0 - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - ldp x8, x9, [x29, -80] - ldr x10, [x29, -96] - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ -.else - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ -.endif -800: - /* Process the remaining trailing pixels in the scanline (dst unaligned) */ - process_trailing_pixels 0, 0, \ - process_pixblock_head, \ - process_pixblock_tail, \ - process_pixblock_tail_head - - cleanup -.if use_nearest_scaling != 0 - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - ldp x8, x9, [x29, -80] - ldr x10, [x29, -88] - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ - - .unreq DUMMY - .unreq DST_R - .unreq SRC - .unreq W - .unreq VX - .unreq UNIT_X - .unreq TMP1 - .unreq TMP2 - .unreq DST_W - .unreq MASK - .unreq SRC_WIDTH_FIXED - -.else - sub x29, x29, 64 - ld1 {v8.8b, v9.8b, v10.8b, v11.8b}, [x29], 32 - ld1 {v12.8b, v13.8b, v14.8b, v15.8b}, [x29], 32 - mov sp, x29 - ldp x29, x30, [sp], 16 - ret /* exit */ - - .unreq DUMMY - .unreq SRC - .unreq MASK - .unreq DST_R - .unreq DST_W - .unreq W -.endif - - .purgem fetch_src_pixblock - .purgem pixld_src - - .endfunc -.endm - -.macro generate_composite_function_single_scanline x:vararg - generate_composite_function_scanline 0, x -.endm - -.macro generate_composite_function_nearest_scanline x:vararg - generate_composite_function_scanline 1, x -.endm - -/* Default prologue/epilogue, nothing special needs to be done */ - -.macro default_init -.endm - -.macro default_cleanup -.endm - -/* - * Prologue/epilogue variant which additionally saves/restores v8-v15 - * registers (they need to be saved/restored by callee according to ABI). - * This is required if the code needs to use all the NEON registers. - */ - -.macro default_init_need_all_regs -.endm - -.macro default_cleanup_need_all_regs -.endm - -/******************************************************************************/ diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/vregion.cpp b/AXrLottie/src/main/cpp/src/vector/pixman/vregion.cpp deleted file mode 100755 index 5944b63..0000000 --- a/AXrLottie/src/main/cpp/src/vector/pixman/vregion.cpp +++ /dev/null @@ -1,2086 +0,0 @@ -/* - * Copyright 1987, 1988, 1989, 1998 The Open Group - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of The Open Group shall not be - * used in advertising or otherwise to promote the sale, use or other dealings - * in this Software without prior written authorization from The Open Group. - * - * Copyright 1987, 1988, 1989 by - * Digital Equipment Corporation, Maynard, Massachusetts. - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appear in all copies and that - * both that copyright notice and this permission notice appear in - * supporting documentation, and that the name of Digital not be - * used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING - * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL - * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR - * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, - * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - * - * Copyright © 1998 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#define critical_if_fail assert -#define PIXMAN_EXPORT static -#define FALSE 0 -#define TRUE 1 -#define FUNC "" -#define MIN(a, b) (a) < (b) ? (a) : (b) -#define MAX(a, b) (a) > (b) ? (a) : (b) - -typedef int pixman_bool_t; - -typedef struct pixman_rectangle pixman_rectangle_t; - -typedef struct pixman_box box_type_t; -typedef struct pixman_region_data region_data_type_t; -typedef struct pixman_region region_type_t; -typedef int64_t overflow_int_t; - -#define PREFIX(x) pixman_region##x - -#define PIXMAN_REGION_MAX INT32_MAX -#define PIXMAN_REGION_MIN INT32_MIN - -typedef struct { - int x, y; -} point_type_t; - -struct pixman_region_data { - long size; - long numRects; - /* box_type_t rects[size]; in memory but not explicitly declared */ -}; - -struct pixman_rectangle { - int32_t x, y; - uint32_t width, height; -}; - -struct pixman_box { - int32_t x1, y1, x2, y2; -}; - -struct pixman_region { - box_type_t extents; - region_data_type_t *data; -}; - -typedef enum { - PIXMAN_REGION_OUT, - PIXMAN_REGION_IN, - PIXMAN_REGION_PART -} pixman_region_overlap_t; - -static void _pixman_log_error(const char *function, const char *message) -{ - fprintf(stderr, - "*** BUG ***\n" - "In %s: %s\n" - "Set a breakpoint on '_pixman_log_error' to debug\n\n", - function, message); -} - -#define PIXREGION_NIL(reg) ((reg)->data && !(reg)->data->numRects) -/* not a region */ -#define PIXREGION_NAR(reg) ((reg)->data == pixman_broken_data) -#define PIXREGION_NUMRECTS(reg) ((reg)->data ? (reg)->data->numRects : 1) -#define PIXREGION_SIZE(reg) ((reg)->data ? (reg)->data->size : 0) -#define PIXREGION_RECTS(reg) \ - ((reg)->data ? (box_type_t *)((reg)->data + 1) : &(reg)->extents) -#define PIXREGION_BOXPTR(reg) ((box_type_t *)((reg)->data + 1)) -#define PIXREGION_BOX(reg, i) (&PIXREGION_BOXPTR(reg)[i]) -#define PIXREGION_TOP(reg) PIXREGION_BOX(reg, (reg)->data->numRects) -#define PIXREGION_END(reg) PIXREGION_BOX(reg, (reg)->data->numRects - 1) - -#define GOOD_RECT(rect) ((rect)->x1 < (rect)->x2 && (rect)->y1 < (rect)->y2) -#define BAD_RECT(rect) ((rect)->x1 > (rect)->x2 || (rect)->y1 > (rect)->y2) - -#ifdef DEBUG - -#define GOOD(reg) \ - do { \ - if (!PREFIX(_selfcheck(reg))) \ - _pixman_log_error(FUNC, "Malformed region " #reg); \ - } while (0) - -#else - -#define GOOD(reg) - -#endif - -static const box_type_t PREFIX(_empty_box_) = {0, 0, 0, 0}; -static const region_data_type_t PREFIX(_empty_data_) = {0, 0}; -#if defined(__llvm__) && !defined(__clang__) -static const volatile region_data_type_t PREFIX(_broken_data_) = {0, 0}; -#else -static const region_data_type_t PREFIX(_broken_data_) = {0, 0}; -#endif - -static box_type_t *pixman_region_empty_box = (box_type_t *)&PREFIX(_empty_box_); -static region_data_type_t *pixman_region_empty_data = - (region_data_type_t *)&PREFIX(_empty_data_); -static region_data_type_t *pixman_broken_data = - (region_data_type_t *)&PREFIX(_broken_data_); - -static pixman_bool_t pixman_break(region_type_t *region); - -/* - * The functions in this file implement the Region abstraction used extensively - * throughout the X11 sample server. A Region is simply a set of disjoint - * (non-overlapping) rectangles, plus an "extent" rectangle which is the - * smallest single rectangle that contains all the non-overlapping rectangles. - * - * A Region is implemented as a "y-x-banded" array of rectangles. This array - * imposes two degrees of order. First, all rectangles are sorted by top side - * y coordinate first (y1), and then by left side x coordinate (x1). - * - * Furthermore, the rectangles are grouped into "bands". Each rectangle in a - * band has the same top y coordinate (y1), and each has the same bottom y - * coordinate (y2). Thus all rectangles in a band differ only in their left - * and right side (x1 and x2). Bands are implicit in the array of rectangles: - * there is no separate list of band start pointers. - * - * The y-x band representation does not minimize rectangles. In particular, - * if a rectangle vertically crosses a band (the rectangle has scanlines in - * the y1 to y2 area spanned by the band), then the rectangle may be broken - * down into two or more smaller rectangles stacked one atop the other. - * - * ----------- ----------- - * | | | | band 0 - * | | -------- ----------- -------- - * | | | | in y-x banded | | | | band 1 - * | | | | form is | | | | - * ----------- | | ----------- -------- - * | | | | band 2 - * -------- -------- - * - * An added constraint on the rectangles is that they must cover as much - * horizontal area as possible: no two rectangles within a band are allowed - * to touch. - * - * Whenever possible, bands will be merged together to cover a greater vertical - * distance (and thus reduce the number of rectangles). Two bands can be merged - * only if the bottom of one touches the top of the other and they have - * rectangles in the same places (of the same width, of course). - * - * Adam de Boor wrote most of the original region code. Joel McCormack - * substantially modified or rewrote most of the core arithmetic routines, and - * added pixman_region_validate in order to support several speed improvements - * to pixman_region_validate_tree. Bob Scheifler changed the representation - * to be more compact when empty or a single rectangle, and did a bunch of - * gratuitous reformatting. Carl Worth did further gratuitous reformatting - * while re-merging the server and client region code into libpixregion. - * Soren Sandmann did even more gratuitous reformatting. - */ - -/* true iff two Boxes overlap */ -#define EXTENTCHECK(r1, r2) \ - (!(((r1)->x2 <= (r2)->x1) || ((r1)->x1 >= (r2)->x2) || \ - ((r1)->y2 <= (r2)->y1) || ((r1)->y1 >= (r2)->y2))) - -/* true iff (x,y) is in Box */ -#define INBOX(r, x, y) \ - (((r)->x2 > x) && ((r)->x1 <= x) && ((r)->y2 > y) && ((r)->y1 <= y)) - -/* true iff Box r1 contains Box r2 */ -#define SUBSUMES(r1, r2) \ - (((r1)->x1 <= (r2)->x1) && ((r1)->x2 >= (r2)->x2) && \ - ((r1)->y1 <= (r2)->y1) && ((r1)->y2 >= (r2)->y2)) - -static size_t PIXREGION_SZOF(size_t n) -{ - size_t size = n * sizeof(box_type_t); - - if (n > UINT32_MAX / sizeof(box_type_t)) return 0; - - if (sizeof(region_data_type_t) > UINT32_MAX - size) return 0; - - return size + sizeof(region_data_type_t); -} - -static region_data_type_t *alloc_data(size_t n) -{ - size_t sz = PIXREGION_SZOF(n); - - if (!sz) return NULL; - - return (region_data_type_t *)malloc(sz); -} - -#define FREE_DATA(reg) \ - if ((reg)->data && (reg)->data->size) free((reg)->data) - -#define RECTALLOC_BAIL(region, n, bail) \ - do { \ - if (!(region)->data || \ - (((region)->data->numRects + (n)) > (region)->data->size)) { \ - if (!pixman_rect_alloc(region, n)) goto bail; \ - } \ - } while (0) - -#define RECTALLOC(region, n) \ - do { \ - if (!(region)->data || \ - (((region)->data->numRects + (n)) > (region)->data->size)) { \ - if (!pixman_rect_alloc(region, n)) { \ - return FALSE; \ - } \ - } \ - } while (0) - -#define ADDRECT(next_rect, nx1, ny1, nx2, ny2) \ - do { \ - next_rect->x1 = nx1; \ - next_rect->y1 = ny1; \ - next_rect->x2 = nx2; \ - next_rect->y2 = ny2; \ - next_rect++; \ - } while (0) - -#define NEWRECT(region, next_rect, nx1, ny1, nx2, ny2) \ - do { \ - if (!(region)->data || \ - ((region)->data->numRects == (region)->data->size)) { \ - if (!pixman_rect_alloc(region, 1)) return FALSE; \ - next_rect = PIXREGION_TOP(region); \ - } \ - ADDRECT(next_rect, nx1, ny1, nx2, ny2); \ - region->data->numRects++; \ - critical_if_fail(region->data->numRects <= region->data->size); \ - } while (0) - -#define DOWNSIZE(reg, numRects) \ - do { \ - if (((numRects) < ((reg)->data->size >> 1)) && \ - ((reg)->data->size > 50)) { \ - region_data_type_t *new_data; \ - size_t data_size = PIXREGION_SZOF(numRects); \ - \ - if (!data_size) { \ - new_data = NULL; \ - } else { \ - new_data = \ - (region_data_type_t *)realloc((reg)->data, data_size); \ - } \ - \ - if (new_data) { \ - new_data->size = (numRects); \ - (reg)->data = new_data; \ - } \ - } \ - } while (0) - -PIXMAN_EXPORT pixman_bool_t PREFIX(_equal)(region_type_t *reg1, - region_type_t *reg2) -{ - int i; - box_type_t *rects1; - box_type_t *rects2; - - if (reg1->extents.x1 != reg2->extents.x1) return FALSE; - - if (reg1->extents.x2 != reg2->extents.x2) return FALSE; - - if (reg1->extents.y1 != reg2->extents.y1) return FALSE; - - if (reg1->extents.y2 != reg2->extents.y2) return FALSE; - - if (PIXREGION_NUMRECTS(reg1) != PIXREGION_NUMRECTS(reg2)) return FALSE; - - rects1 = PIXREGION_RECTS(reg1); - rects2 = PIXREGION_RECTS(reg2); - - for (i = 0; i != PIXREGION_NUMRECTS(reg1); i++) { - if (rects1[i].x1 != rects2[i].x1) return FALSE; - - if (rects1[i].x2 != rects2[i].x2) return FALSE; - - if (rects1[i].y1 != rects2[i].y1) return FALSE; - - if (rects1[i].y2 != rects2[i].y2) return FALSE; - } - - return TRUE; -} - -// returns true if both region intersects -PIXMAN_EXPORT pixman_bool_t PREFIX(_intersects)(region_type_t *reg1, - region_type_t *reg2) -{ - box_type_t *rects1 = PIXREGION_RECTS(reg1); - box_type_t *rects2 = PIXREGION_RECTS(reg2); - for (int i = 0; i != PIXREGION_NUMRECTS(reg1); i++) { - for (int j = 0; j != PIXREGION_NUMRECTS(reg2); j++) { - if (EXTENTCHECK(rects1 + i, rects2 + j)) return TRUE; - } - } - return FALSE; -} - -int PREFIX(_print)(region_type_t *rgn) -{ - int num, size; - int i; - box_type_t *rects; - - num = PIXREGION_NUMRECTS(rgn); - size = PIXREGION_SIZE(rgn); - rects = PIXREGION_RECTS(rgn); - - fprintf(stderr, "num: %d size: %d\n", num, size); - fprintf(stderr, "extents: %d %d %d %d\n", rgn->extents.x1, rgn->extents.y1, - rgn->extents.x2, rgn->extents.y2); - - for (i = 0; i < num; i++) { - fprintf(stderr, "%d %d %d %d \n", rects[i].x1, rects[i].y1, rects[i].x2, - rects[i].y2); - } - - fprintf(stderr, "\n"); - - return (num); -} - -PIXMAN_EXPORT void PREFIX(_init)(region_type_t *region) -{ - region->extents = *pixman_region_empty_box; - region->data = pixman_region_empty_data; -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_union_rect)(region_type_t *dest, - region_type_t *source, int x, - int y, unsigned int width, - unsigned int height); -PIXMAN_EXPORT void PREFIX(_init_rect)(region_type_t *region, int x, int y, - unsigned int width, unsigned int height) -{ - PREFIX(_init)(region); - PREFIX(_union_rect)(region, region, x, y, width, height); -} - -PIXMAN_EXPORT void PREFIX(_fini)(region_type_t *region) -{ - GOOD(region); - FREE_DATA(region); -} - -PIXMAN_EXPORT int PREFIX(_n_rects)(region_type_t *region) -{ - return PIXREGION_NUMRECTS(region); -} - -static pixman_bool_t pixman_break(region_type_t *region) -{ - FREE_DATA(region); - - region->extents = *pixman_region_empty_box; - region->data = pixman_broken_data; - - return FALSE; -} - -static pixman_bool_t pixman_rect_alloc(region_type_t *region, int n) -{ - region_data_type_t *data; - - if (!region->data) { - n++; - region->data = alloc_data(n); - - if (!region->data) return pixman_break(region); - - region->data->numRects = 1; - *PIXREGION_BOXPTR(region) = region->extents; - } else if (!region->data->size) { - region->data = alloc_data(n); - - if (!region->data) return pixman_break(region); - - region->data->numRects = 0; - } else { - size_t data_size; - - if (n == 1) { - n = region->data->numRects; - if (n > 500) /* XXX pick numbers out of a hat */ - n = 250; - } - - n += region->data->numRects; - data_size = PIXREGION_SZOF(n); - - if (!data_size) { - data = NULL; - } else { - data = - (region_data_type_t *)realloc(region->data, PIXREGION_SZOF(n)); - } - - if (!data) return pixman_break(region); - - region->data = data; - } - - region->data->size = n; - - return TRUE; -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_copy)(region_type_t *dst, - region_type_t *src) -{ - GOOD(dst); - GOOD(src); - - if (dst == src) return TRUE; - - dst->extents = src->extents; - - if (!src->data || !src->data->size) { - FREE_DATA(dst); - dst->data = src->data; - return TRUE; - } - - if (!dst->data || (dst->data->size < src->data->numRects)) { - FREE_DATA(dst); - - dst->data = alloc_data(src->data->numRects); - - if (!dst->data) return pixman_break(dst); - - dst->data->size = src->data->numRects; - } - - dst->data->numRects = src->data->numRects; - - memmove((char *)PIXREGION_BOXPTR(dst), (char *)PIXREGION_BOXPTR(src), - dst->data->numRects * sizeof(box_type_t)); - - return TRUE; -} - -/*====================================================================== - * Generic Region Operator - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * pixman_coalesce -- - * Attempt to merge the boxes in the current band with those in the - * previous one. We are guaranteed that the current band extends to - * the end of the rects array. Used only by pixman_op. - * - * Results: - * The new index for the previous band. - * - * Side Effects: - * If coalescing takes place: - * - rectangles in the previous band will have their y2 fields - * altered. - * - region->data->numRects will be decreased. - * - *----------------------------------------------------------------------- - */ -static inline int pixman_coalesce( - region_type_t *region, /* Region to coalesce */ - int prev_start, /* Index of start of previous band */ - int cur_start) /* Index of start of current band */ -{ - box_type_t *prev_box; /* Current box in previous band */ - box_type_t *cur_box; /* Current box in current band */ - int numRects; /* Number rectangles in both bands */ - int y2; /* Bottom of current band */ - - /* - * Figure out how many rectangles are in the band. - */ - numRects = cur_start - prev_start; - critical_if_fail(numRects == region->data->numRects - cur_start); - - if (!numRects) return cur_start; - - /* - * The bands may only be coalesced if the bottom of the previous - * matches the top scanline of the current. - */ - prev_box = PIXREGION_BOX(region, prev_start); - cur_box = PIXREGION_BOX(region, cur_start); - if (prev_box->y2 != cur_box->y1) return cur_start; - - /* - * Make sure the bands have boxes in the same places. This - * assumes that boxes have been added in such a way that they - * cover the most area possible. I.e. two boxes in a band must - * have some horizontal space between them. - */ - y2 = cur_box->y2; - - do { - if ((prev_box->x1 != cur_box->x1) || (prev_box->x2 != cur_box->x2)) - return (cur_start); - - prev_box++; - cur_box++; - numRects--; - } while (numRects); - - /* - * The bands may be merged, so set the bottom y of each box - * in the previous band to the bottom y of the current band. - */ - numRects = cur_start - prev_start; - region->data->numRects -= numRects; - - do { - prev_box--; - prev_box->y2 = y2; - numRects--; - } while (numRects); - - return prev_start; -} - -/* Quicky macro to avoid trivial reject procedure calls to pixman_coalesce */ - -#define COALESCE(new_reg, prev_band, cur_band) \ - do { \ - if (cur_band - prev_band == new_reg->data->numRects - cur_band) \ - prev_band = pixman_coalesce(new_reg, prev_band, cur_band); \ - else \ - prev_band = cur_band; \ - } while (0) - -/*- - *----------------------------------------------------------------------- - * pixman_region_append_non_o -- - * Handle a non-overlapping band for the union and subtract operations. - * Just adds the (top/bottom-clipped) rectangles into the region. - * Doesn't have to check for subsumption or anything. - * - * Results: - * None. - * - * Side Effects: - * region->data->numRects is incremented and the rectangles overwritten - * with the rectangles we're passed. - * - *----------------------------------------------------------------------- - */ -static inline pixman_bool_t pixman_region_append_non_o(region_type_t *region, - box_type_t * r, - box_type_t * r_end, - int y1, int y2) -{ - box_type_t *next_rect; - int new_rects; - - new_rects = r_end - r; - - critical_if_fail(y1 < y2); - critical_if_fail(new_rects != 0); - - /* Make sure we have enough space for all rectangles to be added */ - RECTALLOC(region, new_rects); - next_rect = PIXREGION_TOP(region); - region->data->numRects += new_rects; - - do { - critical_if_fail(r->x1 < r->x2); - ADDRECT(next_rect, r->x1, y1, r->x2, y2); - r++; - } while (r != r_end); - - return TRUE; -} - -#define FIND_BAND(r, r_band_end, r_end, ry1) \ - do { \ - ry1 = r->y1; \ - r_band_end = r + 1; \ - while ((r_band_end != r_end) && (r_band_end->y1 == ry1)) { \ - r_band_end++; \ - } \ - } while (0) - -#define APPEND_REGIONS(new_reg, r, r_end) \ - do { \ - int new_rects; \ - if ((new_rects = r_end - r)) { \ - RECTALLOC_BAIL(new_reg, new_rects, bail); \ - memmove((char *)PIXREGION_TOP(new_reg), (char *)r, \ - new_rects * sizeof(box_type_t)); \ - new_reg->data->numRects += new_rects; \ - } \ - } while (0) - -/*- - *----------------------------------------------------------------------- - * pixman_op -- - * Apply an operation to two regions. Called by pixman_region_union, - *pixman_region_inverse, pixman_region_subtract, pixman_region_intersect.... - *Both regions MUST have at least one rectangle, and cannot be the same object. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * The new region is overwritten. - * overlap set to TRUE if overlap_func ever returns TRUE. - * - * Notes: - * The idea behind this function is to view the two regions as sets. - * Together they cover a rectangle of area that this function divides - * into horizontal bands where points are covered only by one region - * or by both. For the first case, the non_overlap_func is called with - * each the band and the band's upper and lower extents. For the - * second, the overlap_func is called to process the entire band. It - * is responsible for clipping the rectangles in the band, though - * this function provides the boundaries. - * At the end of each band, the new region is coalesced, if possible, - * to reduce the number of rectangles in the region. - * - *----------------------------------------------------------------------- - */ - -typedef pixman_bool_t (*overlap_proc_ptr)(region_type_t *region, box_type_t *r1, - box_type_t *r1_end, box_type_t *r2, - box_type_t *r2_end, int y1, int y2); - -static pixman_bool_t pixman_op( - region_type_t * new_reg, /* Place to store result */ - region_type_t * reg1, /* First region in operation */ - region_type_t * reg2, /* 2d region in operation */ - overlap_proc_ptr overlap_func, /* Function to call for over- - * lapping bands */ - int append_non1, /* Append non-overlapping bands - * in region 1 ? - */ - int append_non2 /* Append non-overlapping bands - * in region 2 ? - */ -) -{ - box_type_t * r1; /* Pointer into first region */ - box_type_t * r2; /* Pointer into 2d region */ - box_type_t * r1_end; /* End of 1st region */ - box_type_t * r2_end; /* End of 2d region */ - int ybot; /* Bottom of intersection */ - int ytop; /* Top of intersection */ - region_data_type_t *old_data; /* Old data for new_reg */ - int prev_band; /* Index of start of - * previous band in new_reg */ - int cur_band; /* Index of start of current - * band in new_reg */ - box_type_t *r1_band_end; /* End of current band in r1 */ - box_type_t *r2_band_end; /* End of current band in r2 */ - int top; /* Top of non-overlapping band */ - int bot; /* Bottom of non-overlapping band*/ - int r1y1; /* Temps for r1->y1 and r2->y1 */ - int r2y1; - int new_size; - int numRects; - - /* - * Break any region computed from a broken region - */ - if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2)) - return pixman_break(new_reg); - - /* - * Initialization: - * set r1, r2, r1_end and r2_end appropriately, save the rectangles - * of the destination region until the end in case it's one of - * the two source regions, then mark the "new" region empty, allocating - * another array of rectangles for it to use. - */ - - r1 = PIXREGION_RECTS(reg1); - new_size = PIXREGION_NUMRECTS(reg1); - r1_end = r1 + new_size; - - numRects = PIXREGION_NUMRECTS(reg2); - r2 = PIXREGION_RECTS(reg2); - r2_end = r2 + numRects; - - critical_if_fail(r1 != r1_end); - critical_if_fail(r2 != r2_end); - - old_data = (region_data_type_t *)NULL; - - if (((new_reg == reg1) && (new_size > 1)) || - ((new_reg == reg2) && (numRects > 1))) { - old_data = new_reg->data; - new_reg->data = pixman_region_empty_data; - } - - /* guess at new size */ - if (numRects > new_size) new_size = numRects; - - new_size <<= 1; - - if (!new_reg->data) - new_reg->data = pixman_region_empty_data; - else if (new_reg->data->size) - new_reg->data->numRects = 0; - - if (new_size > new_reg->data->size) { - if (!pixman_rect_alloc(new_reg, new_size)) { - free(old_data); - return FALSE; - } - } - - /* - * Initialize ybot. - * In the upcoming loop, ybot and ytop serve different functions depending - * on whether the band being handled is an overlapping or non-overlapping - * band. - * In the case of a non-overlapping band (only one of the regions - * has points in the band), ybot is the bottom of the most recent - * intersection and thus clips the top of the rectangles in that band. - * ytop is the top of the next intersection between the two regions and - * serves to clip the bottom of the rectangles in the current band. - * For an overlapping band (where the two regions intersect), ytop clips - * the top of the rectangles of both regions and ybot clips the bottoms. - */ - - ybot = MIN(r1->y1, r2->y1); - - /* - * prev_band serves to mark the start of the previous band so rectangles - * can be coalesced into larger rectangles. qv. pixman_coalesce, above. - * In the beginning, there is no previous band, so prev_band == cur_band - * (cur_band is set later on, of course, but the first band will always - * start at index 0). prev_band and cur_band must be indices because of - * the possible expansion, and resultant moving, of the new region's - * array of rectangles. - */ - prev_band = 0; - - do { - /* - * This algorithm proceeds one source-band (as opposed to a - * destination band, which is determined by where the two regions - * intersect) at a time. r1_band_end and r2_band_end serve to mark the - * rectangle after the last one in the current band for their - * respective regions. - */ - critical_if_fail(r1 != r1_end); - critical_if_fail(r2 != r2_end); - - FIND_BAND(r1, r1_band_end, r1_end, r1y1); - FIND_BAND(r2, r2_band_end, r2_end, r2y1); - - /* - * First handle the band that doesn't intersect, if any. - * - * Note that attention is restricted to one band in the - * non-intersecting region at once, so if a region has n - * bands between the current position and the next place it overlaps - * the other, this entire loop will be passed through n times. - */ - if (r1y1 < r2y1) { - if (append_non1) { - top = MAX(r1y1, ybot); - bot = MIN(r1->y2, r2y1); - if (top != bot) { - cur_band = new_reg->data->numRects; - if (!pixman_region_append_non_o(new_reg, r1, r1_band_end, - top, bot)) - goto bail; - COALESCE(new_reg, prev_band, cur_band); - } - } - ytop = r2y1; - } else if (r2y1 < r1y1) { - if (append_non2) { - top = MAX(r2y1, ybot); - bot = MIN(r2->y2, r1y1); - - if (top != bot) { - cur_band = new_reg->data->numRects; - - if (!pixman_region_append_non_o(new_reg, r2, r2_band_end, - top, bot)) - goto bail; - - COALESCE(new_reg, prev_band, cur_band); - } - } - ytop = r1y1; - } else { - ytop = r1y1; - } - - /* - * Now see if we've hit an intersecting band. The two bands only - * intersect if ybot > ytop - */ - ybot = MIN(r1->y2, r2->y2); - if (ybot > ytop) { - cur_band = new_reg->data->numRects; - - if (!(*overlap_func)(new_reg, r1, r1_band_end, r2, r2_band_end, - ytop, ybot)) { - goto bail; - } - - COALESCE(new_reg, prev_band, cur_band); - } - - /* - * If we've finished with a band (y2 == ybot) we skip forward - * in the region to the next band. - */ - if (r1->y2 == ybot) r1 = r1_band_end; - - if (r2->y2 == ybot) r2 = r2_band_end; - - } while (r1 != r1_end && r2 != r2_end); - - /* - * Deal with whichever region (if any) still has rectangles left. - * - * We only need to worry about banding and coalescing for the very first - * band left. After that, we can just group all remaining boxes, - * regardless of how many bands, into one final append to the list. - */ - - if ((r1 != r1_end) && append_non1) { - /* Do first non_overlap1Func call, which may be able to coalesce */ - FIND_BAND(r1, r1_band_end, r1_end, r1y1); - - cur_band = new_reg->data->numRects; - - if (!pixman_region_append_non_o(new_reg, r1, r1_band_end, - MAX(r1y1, ybot), r1->y2)) { - goto bail; - } - - COALESCE(new_reg, prev_band, cur_band); - - /* Just append the rest of the boxes */ - APPEND_REGIONS(new_reg, r1_band_end, r1_end); - } else if ((r2 != r2_end) && append_non2) { - /* Do first non_overlap2Func call, which may be able to coalesce */ - FIND_BAND(r2, r2_band_end, r2_end, r2y1); - - cur_band = new_reg->data->numRects; - - if (!pixman_region_append_non_o(new_reg, r2, r2_band_end, - MAX(r2y1, ybot), r2->y2)) { - goto bail; - } - - COALESCE(new_reg, prev_band, cur_band); - - /* Append rest of boxes */ - APPEND_REGIONS(new_reg, r2_band_end, r2_end); - } - - free(old_data); - - if (!(numRects = new_reg->data->numRects)) { - FREE_DATA(new_reg); - new_reg->data = pixman_region_empty_data; - } else if (numRects == 1) { - new_reg->extents = *PIXREGION_BOXPTR(new_reg); - FREE_DATA(new_reg); - new_reg->data = (region_data_type_t *)NULL; - } else { - DOWNSIZE(new_reg, numRects); - } - - return TRUE; - -bail: - free(old_data); - - return pixman_break(new_reg); -} - -/*- - *----------------------------------------------------------------------- - * pixman_set_extents -- - * Reset the extents of a region to what they should be. Called by - * pixman_region_subtract and pixman_region_intersect as they can't - * figure it out along the way or do so easily, as pixman_region_union can. - * - * Results: - * None. - * - * Side Effects: - * The region's 'extents' structure is overwritten. - * - *----------------------------------------------------------------------- - */ -static void pixman_set_extents(region_type_t *region) -{ - box_type_t *box, *box_end; - - if (!region->data) return; - - if (!region->data->size) { - region->extents.x2 = region->extents.x1; - region->extents.y2 = region->extents.y1; - return; - } - - box = PIXREGION_BOXPTR(region); - box_end = PIXREGION_END(region); - - /* - * Since box is the first rectangle in the region, it must have the - * smallest y1 and since box_end is the last rectangle in the region, - * it must have the largest y2, because of banding. Initialize x1 and - * x2 from box and box_end, resp., as good things to initialize them - * to... - */ - region->extents.x1 = box->x1; - region->extents.y1 = box->y1; - region->extents.x2 = box_end->x2; - region->extents.y2 = box_end->y2; - - critical_if_fail(region->extents.y1 < region->extents.y2); - - while (box <= box_end) { - if (box->x1 < region->extents.x1) region->extents.x1 = box->x1; - if (box->x2 > region->extents.x2) region->extents.x2 = box->x2; - box++; - } - - critical_if_fail(region->extents.x1 < region->extents.x2); -} - -/*====================================================================== - * Region Intersection - *====================================================================*/ -/*- - *----------------------------------------------------------------------- - * pixman_region_intersect_o -- - * Handle an overlapping band for pixman_region_intersect. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * Rectangles may be added to the region. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static pixman_bool_t pixman_region_intersect_o( - region_type_t *region, box_type_t *r1, box_type_t *r1_end, box_type_t *r2, - box_type_t *r2_end, int y1, int y2) -{ - int x1; - int x2; - box_type_t *next_rect; - - next_rect = PIXREGION_TOP(region); - - critical_if_fail(y1 < y2); - critical_if_fail(r1 != r1_end && r2 != r2_end); - - do { - x1 = MAX(r1->x1, r2->x1); - x2 = MIN(r1->x2, r2->x2); - - /* - * If there's any overlap between the two rectangles, add that - * overlap to the new region. - */ - if (x1 < x2) NEWRECT(region, next_rect, x1, y1, x2, y2); - - /* - * Advance the pointer(s) with the leftmost right side, since the next - * rectangle on that list may still overlap the other region's - * current rectangle. - */ - if (r1->x2 == x2) { - r1++; - } - if (r2->x2 == x2) { - r2++; - } - } while ((r1 != r1_end) && (r2 != r2_end)); - - return TRUE; -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect)(region_type_t *new_reg, - region_type_t *reg1, - region_type_t *reg2) -{ - GOOD(reg1); - GOOD(reg2); - GOOD(new_reg); - - /* check for trivial reject */ - if (PIXREGION_NIL(reg1) || PIXREGION_NIL(reg2) || - !EXTENTCHECK(®1->extents, ®2->extents)) { - /* Covers about 20% of all cases */ - FREE_DATA(new_reg); - new_reg->extents.x2 = new_reg->extents.x1; - new_reg->extents.y2 = new_reg->extents.y1; - if (PIXREGION_NAR(reg1) || PIXREGION_NAR(reg2)) { - new_reg->data = pixman_broken_data; - return FALSE; - } else { - new_reg->data = pixman_region_empty_data; - } - } else if (!reg1->data && !reg2->data) { - /* Covers about 80% of cases that aren't trivially rejected */ - new_reg->extents.x1 = MAX(reg1->extents.x1, reg2->extents.x1); - new_reg->extents.y1 = MAX(reg1->extents.y1, reg2->extents.y1); - new_reg->extents.x2 = MIN(reg1->extents.x2, reg2->extents.x2); - new_reg->extents.y2 = MIN(reg1->extents.y2, reg2->extents.y2); - - FREE_DATA(new_reg); - - new_reg->data = (region_data_type_t *)NULL; - } else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) { - return PREFIX(_copy)(new_reg, reg1); - } else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) { - return PREFIX(_copy)(new_reg, reg2); - } else if (reg1 == reg2) { - return PREFIX(_copy)(new_reg, reg1); - } else { - /* General purpose intersection */ - - if (!pixman_op(new_reg, reg1, reg2, pixman_region_intersect_o, FALSE, - FALSE)) - return FALSE; - - pixman_set_extents(new_reg); - } - - GOOD(new_reg); - return (TRUE); -} - -#define MERGERECT(r) \ - do { \ - if (r->x1 <= x2) { \ - /* Merge with current rectangle */ \ - if (x2 < r->x2) x2 = r->x2; \ - } else { \ - /* Add current rectangle, start new one */ \ - NEWRECT(region, next_rect, x1, y1, x2, y2); \ - x1 = r->x1; \ - x2 = r->x2; \ - } \ - r++; \ - } while (0) - -/*====================================================================== - * Region Union - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * pixman_region_union_o -- - * Handle an overlapping band for the union operation. Picks the - * left-most rectangle each time and merges it into the region. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * region is overwritten. - * overlap is set to TRUE if any boxes overlap. - * - *----------------------------------------------------------------------- - */ -static pixman_bool_t pixman_region_union_o(region_type_t *region, - box_type_t *r1, box_type_t *r1_end, - box_type_t *r2, box_type_t *r2_end, - int y1, int y2) -{ - box_type_t *next_rect; - int x1; /* left and right side of current union */ - int x2; - - critical_if_fail(y1 < y2); - critical_if_fail(r1 != r1_end && r2 != r2_end); - - next_rect = PIXREGION_TOP(region); - - /* Start off current rectangle */ - if (r1->x1 < r2->x1) { - x1 = r1->x1; - x2 = r1->x2; - r1++; - } else { - x1 = r2->x1; - x2 = r2->x2; - r2++; - } - while (r1 != r1_end && r2 != r2_end) { - if (r1->x1 < r2->x1) - MERGERECT(r1); - else - MERGERECT(r2); - } - - /* Finish off whoever (if any) is left */ - if (r1 != r1_end) { - do { - MERGERECT(r1); - } while (r1 != r1_end); - } else if (r2 != r2_end) { - do { - MERGERECT(r2); - } while (r2 != r2_end); - } - - /* Add current rectangle */ - NEWRECT(region, next_rect, x1, y1, x2, y2); - - return TRUE; -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_intersect_rect)(region_type_t *dest, - region_type_t *source, - int x, int y, - unsigned int width, - unsigned int height) -{ - region_type_t region; - - region.data = NULL; - region.extents.x1 = x; - region.extents.y1 = y; - region.extents.x2 = x + width; - region.extents.y2 = y + height; - - return PREFIX(_intersect)(dest, source, ®ion); -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg, - region_type_t *reg1, - region_type_t *reg2); - -/* Convenience function for performing union of region with a - * single rectangle - */ -PIXMAN_EXPORT pixman_bool_t PREFIX(_union_rect)(region_type_t *dest, - region_type_t *source, int x, - int y, unsigned int width, - unsigned int height) -{ - region_type_t region; - - region.extents.x1 = x; - region.extents.y1 = y; - region.extents.x2 = x + width; - region.extents.y2 = y + height; - - if (!GOOD_RECT(®ion.extents)) { - if (BAD_RECT(®ion.extents)) - _pixman_log_error(FUNC, "Invalid rectangle passed"); - return PREFIX(_copy)(dest, source); - } - - region.data = NULL; - - return PREFIX(_union)(dest, source, ®ion); -} - -PIXMAN_EXPORT pixman_bool_t PREFIX(_union)(region_type_t *new_reg, - region_type_t *reg1, - region_type_t *reg2) -{ - /* Return TRUE if some overlap - * between reg1, reg2 - */ - GOOD(reg1); - GOOD(reg2); - GOOD(new_reg); - - /* checks all the simple cases */ - - /* - * Region 1 and 2 are the same - */ - if (reg1 == reg2) return PREFIX(_copy)(new_reg, reg1); - - /* - * Region 1 is empty - */ - if (PIXREGION_NIL(reg1)) { - if (PIXREGION_NAR(reg1)) return pixman_break(new_reg); - - if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2); - - return TRUE; - } - - /* - * Region 2 is empty - */ - if (PIXREGION_NIL(reg2)) { - if (PIXREGION_NAR(reg2)) return pixman_break(new_reg); - - if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1); - - return TRUE; - } - - /* - * Region 1 completely subsumes region 2 - */ - if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) { - if (new_reg != reg1) return PREFIX(_copy)(new_reg, reg1); - - return TRUE; - } - - /* - * Region 2 completely subsumes region 1 - */ - if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) { - if (new_reg != reg2) return PREFIX(_copy)(new_reg, reg2); - - return TRUE; - } - - if (!pixman_op(new_reg, reg1, reg2, pixman_region_union_o, TRUE, TRUE)) - return FALSE; - - new_reg->extents.x1 = MIN(reg1->extents.x1, reg2->extents.x1); - new_reg->extents.y1 = MIN(reg1->extents.y1, reg2->extents.y1); - new_reg->extents.x2 = MAX(reg1->extents.x2, reg2->extents.x2); - new_reg->extents.y2 = MAX(reg1->extents.y2, reg2->extents.y2); - - GOOD(new_reg); - - return TRUE; -} - -/*====================================================================== - * Region Subtraction - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * pixman_region_subtract_o -- - * Overlapping band subtraction. x1 is the left-most point not yet - * checked. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * region may have rectangles added to it. - * - *----------------------------------------------------------------------- - */ -/*ARGSUSED*/ -static pixman_bool_t pixman_region_subtract_o( - region_type_t *region, box_type_t *r1, box_type_t *r1_end, box_type_t *r2, - box_type_t *r2_end, int y1, int y2) -{ - box_type_t *next_rect; - int x1; - - x1 = r1->x1; - - critical_if_fail(y1 < y2); - critical_if_fail(r1 != r1_end && r2 != r2_end); - - next_rect = PIXREGION_TOP(region); - - do { - if (r2->x2 <= x1) { - /* - * Subtrahend entirely to left of minuend: go to next subtrahend. - */ - r2++; - } else if (r2->x1 <= x1) { - /* - * Subtrahend precedes minuend: nuke left edge of minuend. - */ - x1 = r2->x2; - if (x1 >= r1->x2) { - /* - * Minuend completely covered: advance to next minuend and - * reset left fence to edge of new minuend. - */ - r1++; - if (r1 != r1_end) x1 = r1->x1; - } else { - /* - * Subtrahend now used up since it doesn't extend beyond - * minuend - */ - r2++; - } - } else if (r2->x1 < r1->x2) { - /* - * Left part of subtrahend covers part of minuend: add uncovered - * part of minuend to region and skip to next subtrahend. - */ - critical_if_fail(x1 < r2->x1); - NEWRECT(region, next_rect, x1, y1, r2->x1, y2); - - x1 = r2->x2; - if (x1 >= r1->x2) { - /* - * Minuend used up: advance to new... - */ - r1++; - if (r1 != r1_end) x1 = r1->x1; - } else { - /* - * Subtrahend used up - */ - r2++; - } - } else { - /* - * Minuend used up: add any remaining piece before advancing. - */ - if (r1->x2 > x1) NEWRECT(region, next_rect, x1, y1, r1->x2, y2); - - r1++; - - if (r1 != r1_end) x1 = r1->x1; - } - } while ((r1 != r1_end) && (r2 != r2_end)); - - /* - * Add remaining minuend rectangles to region. - */ - while (r1 != r1_end) { - critical_if_fail(x1 < r1->x2); - - NEWRECT(region, next_rect, x1, y1, r1->x2, y2); - - r1++; - if (r1 != r1_end) x1 = r1->x1; - } - return TRUE; -} - -/*- - *----------------------------------------------------------------------- - * pixman_region_subtract -- - * Subtract reg_s from reg_m and leave the result in reg_d. - * S stands for subtrahend, M for minuend and D for difference. - * - * Results: - * TRUE if successful. - * - * Side Effects: - * reg_d is overwritten. - * - *----------------------------------------------------------------------- - */ -PIXMAN_EXPORT pixman_bool_t PREFIX(_subtract)(region_type_t *reg_d, - region_type_t *reg_m, - region_type_t *reg_s) -{ - GOOD(reg_m); - GOOD(reg_s); - GOOD(reg_d); - - /* check for trivial rejects */ - if (PIXREGION_NIL(reg_m) || PIXREGION_NIL(reg_s) || - !EXTENTCHECK(®_m->extents, ®_s->extents)) { - if (PIXREGION_NAR(reg_s)) return pixman_break(reg_d); - - return PREFIX(_copy)(reg_d, reg_m); - } else if (reg_m == reg_s) { - FREE_DATA(reg_d); - reg_d->extents.x2 = reg_d->extents.x1; - reg_d->extents.y2 = reg_d->extents.y1; - reg_d->data = pixman_region_empty_data; - - return TRUE; - } - - /* Add those rectangles in region 1 that aren't in region 2, - do yucky subtraction for overlaps, and - just throw away rectangles in region 2 that aren't in region 1 */ - if (!pixman_op(reg_d, reg_m, reg_s, pixman_region_subtract_o, TRUE, FALSE)) - return FALSE; - - /* - * Can't alter reg_d's extents before we call pixman_op because - * it might be one of the source regions and pixman_op depends - * on the extents of those regions being unaltered. Besides, this - * way there's no checking against rectangles that will be nuked - * due to coalescing, so we have to examine fewer rectangles. - */ - pixman_set_extents(reg_d); - GOOD(reg_d); - return TRUE; -} -#if 0 -/*====================================================================== - * Region Inversion - *====================================================================*/ - -/*- - *----------------------------------------------------------------------- - * pixman_region_inverse -- - * Take a region and a box and return a region that is everything - * in the box but not in the region. The careful reader will note - * that this is the same as subtracting the region from the box... - * - * Results: - * TRUE. - * - * Side Effects: - * new_reg is overwritten. - * - *----------------------------------------------------------------------- - */ -PIXMAN_EXPORT pixman_bool_t -PREFIX (_inverse) (region_type_t *new_reg, /* Destination region */ - region_type_t *reg1, /* Region to invert */ - box_type_t * inv_rect) /* Bounding box for inversion */ -{ - region_type_t inv_reg; /* Quick and dirty region made from the - * bounding box */ - GOOD (reg1); - GOOD (new_reg); - - /* check for trivial rejects */ - if (PIXREGION_NIL (reg1) || !EXTENTCHECK (inv_rect, ®1->extents)) - { - if (PIXREGION_NAR (reg1)) - return pixman_break (new_reg); - - new_reg->extents = *inv_rect; - FREE_DATA (new_reg); - new_reg->data = (region_data_type_t *)NULL; - - return TRUE; - } - - /* Add those rectangles in region 1 that aren't in region 2, - * do yucky subtraction for overlaps, and - * just throw away rectangles in region 2 that aren't in region 1 - */ - inv_reg.extents = *inv_rect; - inv_reg.data = (region_data_type_t *)NULL; - if (!pixman_op (new_reg, &inv_reg, reg1, pixman_region_subtract_o, TRUE, FALSE)) - return FALSE; - - /* - * Can't alter new_reg's extents before we call pixman_op because - * it might be one of the source regions and pixman_op depends - * on the extents of those regions being unaltered. Besides, this - * way there's no checking against rectangles that will be nuked - * due to coalescing, so we have to examine fewer rectangles. - */ - pixman_set_extents (new_reg); - GOOD (new_reg); - return TRUE; -} -#endif -/* In time O(log n), locate the first box whose y2 is greater than y. - * Return @end if no such box exists. - */ -static box_type_t *find_box_for_y(box_type_t *begin, box_type_t *end, int y) -{ - box_type_t *mid; - - if (end == begin) return end; - - if (end - begin == 1) { - if (begin->y2 > y) - return begin; - else - return end; - } - - mid = begin + (end - begin) / 2; - if (mid->y2 > y) { - /* If no box is found in [begin, mid], the function - * will return @mid, which is then known to be the - * correct answer. - */ - return find_box_for_y(begin, mid, y); - } else { - return find_box_for_y(mid, end, y); - } -} - -/* - * rect_in(region, rect) - * This routine takes a pointer to a region and a pointer to a box - * and determines if the box is outside/inside/partly inside the region. - * - * The idea is to travel through the list of rectangles trying to cover the - * passed box with them. Anytime a piece of the rectangle isn't covered - * by a band of rectangles, part_out is set TRUE. Any time a rectangle in - * the region covers part of the box, part_in is set TRUE. The process ends - * when either the box has been completely covered (we reached a band that - * doesn't overlap the box, part_in is TRUE and part_out is false), the - * box has been partially covered (part_in == part_out == TRUE -- because of - * the banding, the first time this is true we know the box is only - * partially in the region) or is outside the region (we reached a band - * that doesn't overlap the box at all and part_in is false) - */ -PIXMAN_EXPORT pixman_region_overlap_t - PREFIX(_contains_rectangle)(region_type_t *region, box_type_t *prect) -{ - box_type_t *pbox; - box_type_t *pbox_end; - int part_in, part_out; - int numRects; - int x, y; - - GOOD(region); - - numRects = PIXREGION_NUMRECTS(region); - - /* useful optimization */ - if (!numRects || !EXTENTCHECK(®ion->extents, prect)) - return (PIXMAN_REGION_OUT); - - if (numRects == 1) { - /* We know that it must be PIXMAN_REGION_IN or PIXMAN_REGION_PART */ - if (SUBSUMES(®ion->extents, prect)) - return (PIXMAN_REGION_IN); - else - return (PIXMAN_REGION_PART); - } - - part_out = FALSE; - part_in = FALSE; - - /* (x,y) starts at upper left of rect, moving to the right and down */ - x = prect->x1; - y = prect->y1; - - /* can stop when both part_out and part_in are TRUE, or we reach prect->y2 - */ - for (pbox = PIXREGION_BOXPTR(region), pbox_end = pbox + numRects; - pbox != pbox_end; pbox++) { - /* getting up to speed or skipping remainder of band */ - if (pbox->y2 <= y) { - if ((pbox = find_box_for_y(pbox, pbox_end, y)) == pbox_end) break; - } - - if (pbox->y1 > y) { - part_out = TRUE; /* missed part of rectangle above */ - if (part_in || (pbox->y1 >= prect->y2)) break; - y = pbox->y1; /* x guaranteed to be == prect->x1 */ - } - - if (pbox->x2 <= x) continue; /* not far enough over yet */ - - if (pbox->x1 > x) { - part_out = TRUE; /* missed part of rectangle to left */ - if (part_in) break; - } - - if (pbox->x1 < prect->x2) { - part_in = TRUE; /* definitely overlap */ - if (part_out) break; - } - - if (pbox->x2 >= prect->x2) { - y = pbox->y2; /* finished with this band */ - if (y >= prect->y2) break; - x = prect->x1; /* reset x out to left again */ - } else { - /* - * Because boxes in a band are maximal width, if the first box - * to overlap the rectangle doesn't completely cover it in that - * band, the rectangle must be partially out, since some of it - * will be uncovered in that band. part_in will have been set true - * by now... - */ - part_out = TRUE; - break; - } - } - - if (part_in) { - if (y < prect->y2) - return PIXMAN_REGION_PART; - else - return PIXMAN_REGION_IN; - } else { - return PIXMAN_REGION_OUT; - } -} - -/* PREFIX(_translate) (region, x, y) - * translates in place - */ - -PIXMAN_EXPORT void PREFIX(_translate)(region_type_t *region, int x, int y) -{ - overflow_int_t x1, x2, y1, y2; - int nbox; - box_type_t * pbox; - - GOOD(region); - region->extents.x1 = x1 = region->extents.x1 + x; - region->extents.y1 = y1 = region->extents.y1 + y; - region->extents.x2 = x2 = region->extents.x2 + x; - region->extents.y2 = y2 = region->extents.y2 + y; - - if (((x1 - PIXMAN_REGION_MIN) | (y1 - PIXMAN_REGION_MIN) | - (PIXMAN_REGION_MAX - x2) | (PIXMAN_REGION_MAX - y2)) >= 0) { - if (region->data && (nbox = region->data->numRects)) { - for (pbox = PIXREGION_BOXPTR(region); nbox--; pbox++) { - pbox->x1 += x; - pbox->y1 += y; - pbox->x2 += x; - pbox->y2 += y; - } - } - return; - } - - if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | - (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) { - region->extents.x2 = region->extents.x1; - region->extents.y2 = region->extents.y1; - FREE_DATA(region); - region->data = pixman_region_empty_data; - return; - } - - if (x1 < PIXMAN_REGION_MIN) - region->extents.x1 = PIXMAN_REGION_MIN; - else if (x2 > PIXMAN_REGION_MAX) - region->extents.x2 = PIXMAN_REGION_MAX; - - if (y1 < PIXMAN_REGION_MIN) - region->extents.y1 = PIXMAN_REGION_MIN; - else if (y2 > PIXMAN_REGION_MAX) - region->extents.y2 = PIXMAN_REGION_MAX; - - if (region->data && (nbox = region->data->numRects)) { - box_type_t *pbox_out; - - for (pbox_out = pbox = PIXREGION_BOXPTR(region); nbox--; pbox++) { - pbox_out->x1 = x1 = pbox->x1 + x; - pbox_out->y1 = y1 = pbox->y1 + y; - pbox_out->x2 = x2 = pbox->x2 + x; - pbox_out->y2 = y2 = pbox->y2 + y; - - if (((x2 - PIXMAN_REGION_MIN) | (y2 - PIXMAN_REGION_MIN) | - (PIXMAN_REGION_MAX - x1) | (PIXMAN_REGION_MAX - y1)) <= 0) { - region->data->numRects--; - continue; - } - - if (x1 < PIXMAN_REGION_MIN) - pbox_out->x1 = PIXMAN_REGION_MIN; - else if (x2 > PIXMAN_REGION_MAX) - pbox_out->x2 = PIXMAN_REGION_MAX; - - if (y1 < PIXMAN_REGION_MIN) - pbox_out->y1 = PIXMAN_REGION_MIN; - else if (y2 > PIXMAN_REGION_MAX) - pbox_out->y2 = PIXMAN_REGION_MAX; - - pbox_out++; - } - - if (pbox_out != pbox) { - if (region->data->numRects == 1) { - region->extents = *PIXREGION_BOXPTR(region); - FREE_DATA(region); - region->data = (region_data_type_t *)NULL; - } else { - pixman_set_extents(region); - } - } - } - - GOOD(region); -} - -PIXMAN_EXPORT int PREFIX(_not_empty)(region_type_t *region) -{ - GOOD(region); - - return (!PIXREGION_NIL(region)); -} - -PIXMAN_EXPORT box_type_t *PREFIX(_extents)(region_type_t *region) -{ - GOOD(region); - - return (®ion->extents); -} - -typedef region_type_t VRegionPrivate; - -#include "vregion.h" - -V_BEGIN_NAMESPACE - -static VRegionPrivate regionPrivate = {{0, 0, 0, 0}, NULL}; - -struct VRegionData { - VRegionData() : ref(-1), rgn(®ionPrivate) {} - RefCount ref; - VRegionPrivate *rgn; -}; - -const VRegionData shared_empty; - -inline VRect box_to_rect(box_type_t *box) -{ - return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1}; -} - -void VRegion::cleanUp(VRegionData *x) -{ - if (x->rgn) { - PREFIX(_fini)(x->rgn); - delete x->rgn; - } - delete x; -} - -void VRegion::detach() -{ - if (d->ref.isShared()) *this = copy(); -} - -VRegion VRegion::copy() const -{ - VRegion r; - - r.d = new VRegionData; - r.d->rgn = new VRegionPrivate; - r.d->ref.setOwned(); - PREFIX(_init)(r.d->rgn); - if (d != &shared_empty) PREFIX(_copy)(r.d->rgn, d->rgn); - return r; -} - -VRegion::VRegion() : d(const_cast(&shared_empty)) {} - -VRegion::VRegion(int x, int y, int w, int h) -{ - VRegion tmp(VRect(x, y, w, h)); - tmp.d->ref.ref(); - d = tmp.d; -} - -VRegion::VRegion(const VRect &r) -{ - if (r.empty()) { - d = const_cast(&shared_empty); - } else { - d = new VRegionData; - d->rgn = new VRegionPrivate; - d->ref.setOwned(); - PREFIX(_init_rect)(d->rgn, r.left(), r.top(), r.width(), r.height()); - } -} - -VRegion::VRegion(const VRegion &r) -{ - d = r.d; - d->ref.ref(); -} - -VRegion::VRegion(VRegion &&other) : d(other.d) -{ - other.d = const_cast(&shared_empty); -} - -VRegion &VRegion::operator=(const VRegion &r) -{ - r.d->ref.ref(); - if (!d->ref.deref()) cleanUp(d); - - d = r.d; - return *this; -} - -inline VRegion &VRegion::operator=(VRegion &&other) -{ - if (!d->ref.deref()) cleanUp(d); - d = other.d; - other.d = const_cast(&shared_empty); - return *this; -} - -VRegion::~VRegion() -{ - if (!d->ref.deref()) cleanUp(d); -} - -bool VRegion::empty() const -{ - return d == &shared_empty || !PREFIX(_not_empty)(d->rgn); -} - -void VRegion::translate(const VPoint &p) -{ - if (p == VPoint() || empty()) return; - - detach(); - PREFIX(_translate)(d->rgn, p.x(), p.y()); -} - -VRegion VRegion::translated(const VPoint &p) const -{ - VRegion ret(*this); - ret.translate(p); - return ret; -} - -/* - * Returns \c true if this region is guaranteed to be fully contained in r. - */ -bool VRegion::within(const VRect &r1) const -{ - box_type_t *r2 = PREFIX(_extents)(d->rgn); - - return r2->x1 >= r1.left() && r2->x2 <= r1.right() && r2->y1 >= r1.top() && - r2->y2 <= r1.bottom(); -} - -bool VRegion::contains(const VRect &r) const -{ - box_type_t box = {r.left(), r.top(), r.right(), r.bottom()}; - - pixman_region_overlap_t res = PREFIX(_contains_rectangle)(d->rgn, &box); - if (res == PIXMAN_REGION_IN) return true; - return false; -} - -VRegion VRegion::united(const VRect &r) const -{ - if (empty()) return r; - - if (contains(r)) { - return *this; - } else if (within(r)) { - return r; - } else { - VRegion result; - result.detach(); - PREFIX(_union_rect) - (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height()); - return result; - } -} - -VRegion VRegion::united(const VRegion &r) const -{ - if (empty()) return r; - if (r.empty()) return *this; - if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return *this; - VRegion result; - result.detach(); - PREFIX(_union)(result.d->rgn, d->rgn, r.d->rgn); - return result; -} - -VRegion VRegion::intersected(const VRect &r) const -{ - if (empty() || r.empty()) return VRegion(); - - /* this is fully contained in r */ - if (within(r)) return *this; - - /* r is fully contained in this */ - if (contains(r)) return r; - - VRegion result; - result.detach(); - PREFIX(_intersect_rect) - (result.d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height()); - return result; -} - -VRegion VRegion::intersected(const VRegion &r) const -{ - if (empty() || r.empty()) return VRegion(); - - VRegion result; - result.detach(); - PREFIX(_intersect)(result.d->rgn, d->rgn, r.d->rgn); - - return result; -} - -VRegion VRegion::subtracted(const VRegion &r) const -{ - if (empty() || r.empty()) return *this; - if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return VRegion(); - - VRegion result; - result.detach(); - PREFIX(_subtract)(result.d->rgn, d->rgn, r.d->rgn); - return result; -} - -int VRegion::rectCount() const -{ - if (empty()) return 0; - return PREFIX(_n_rects)(d->rgn); -} - -VRect VRegion::rectAt(int index) const -{ - VRegionPrivate *reg = d->rgn; - if (!reg) return {}; - - box_type_t *box = PIXREGION_RECTS(reg) + index; - - return box_to_rect(box); -} - -VRegion VRegion::operator+(const VRect &r) const -{ - return united(r); -} - -VRegion VRegion::operator+(const VRegion &r) const -{ - return united(r); -} - -VRegion VRegion::operator-(const VRegion &r) const -{ - return subtracted(r); -} - -VRegion &VRegion::operator+=(const VRect &r) -{ - if (empty()) return *this = r; - if (r.empty()) return *this; - - if (contains(r)) { - return *this; - } else if (within(r)) { - return *this = r; - } else { - detach(); - PREFIX(_union_rect) - (d->rgn, d->rgn, r.left(), r.top(), r.width(), r.height()); - return *this; - } -} - -VRegion &VRegion::operator+=(const VRegion &r) -{ - if (empty()) return *this = r; - if (r.empty()) return *this; - if (d == r.d || PREFIX(_equal)(d->rgn, r.d->rgn)) return *this; - - detach(); - PREFIX(_union)(d->rgn, d->rgn, r.d->rgn); - return *this; -} - -VRegion &VRegion::operator-=(const VRegion &r) -{ - return *this = *this - r; -} - -bool VRegion::operator==(const VRegion &r) const -{ - if (empty()) return r.empty(); - if (r.empty()) return empty(); - - if (d == r.d) - return true; - else - return PREFIX(_equal)(d->rgn, r.d->rgn); -} - -VRect VRegion::boundingRect() const noexcept -{ - if (empty()) return {}; - return box_to_rect(&d->rgn->extents); -} - -inline bool rect_intersects(const VRect &r1, const VRect &r2) -{ - return (r1.right() >= r2.left() && r1.left() <= r2.right() && - r1.bottom() >= r2.top() && r1.top() <= r2.bottom()); -} - -bool VRegion::intersects(const VRegion &r) const -{ - if (empty() || r.empty()) return false; - - return PREFIX(_intersects)(d->rgn, r.d->rgn); -} - -VDebug &operator<<(VDebug &os, const VRegion &o) -{ - os << "[REGION: " - << "[bbox = " << o.boundingRect() << "]"; - os << "[rectCount = " << o.rectCount() << "]"; - os << "[rects = "; - for (int i = 0; i < o.rectCount(); i++) { - os << o.rectAt(i); - } - os << "]" - << "]"; - return os; -} - -V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/pixman/vregion.h b/AXrLottie/src/main/cpp/src/vector/pixman/vregion.h deleted file mode 100755 index ecb17f2..0000000 --- a/AXrLottie/src/main/cpp/src/vector/pixman/vregion.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef VREGION_H -#define VREGION_H -#include -#include -#include -#include -#include "vdebug.h" - -V_BEGIN_NAMESPACE - -struct VRegionData; - -class VRegion { -public: - VRegion(); - VRegion(int x, int y, int w, int h); - VRegion(const VRect &r); - VRegion(const VRegion ®ion); - VRegion(VRegion &&other); - ~VRegion(); - VRegion & operator=(const VRegion &); - VRegion & operator=(VRegion &&); - bool empty() const; - bool contains(const VRect &r) const; - VRegion united(const VRect &r) const; - VRegion united(const VRegion &r) const; - VRegion intersected(const VRect &r) const; - VRegion intersected(const VRegion &r) const; - VRegion subtracted(const VRegion &r) const; - void translate(const VPoint &p); - inline void translate(int dx, int dy); - VRegion translated(const VPoint &p) const; - inline VRegion translated(int dx, int dy) const; - int rectCount() const; - VRect rectAt(int index) const; - - VRegion operator+(const VRect &r) const; - VRegion operator+(const VRegion &r) const; - VRegion operator-(const VRegion &r) const; - VRegion &operator+=(const VRect &r); - VRegion &operator+=(const VRegion &r); - VRegion &operator-=(const VRegion &r); - - VRect boundingRect() const noexcept; - bool intersects(const VRegion ®ion) const; - - bool operator==(const VRegion &r) const; - inline bool operator!=(const VRegion &r) const { return !(operator==(r)); } - friend VDebug &operator<<(VDebug &os, const VRegion &o); - -private: - bool within(const VRect &r) const; - VRegion copy() const; - void detach(); - void cleanUp(VRegionData *x); - - struct VRegionData *d; -}; -inline void VRegion::translate(int dx, int dy) -{ - translate(VPoint(dx, dy)); -} - -inline VRegion VRegion::translated(int dx, int dy) const -{ - return translated(VPoint(dx, dy)); -} - -V_END_NAMESPACE - -#endif // VREGION_H diff --git a/AXrLottie/src/main/cpp/src/vector/stb/CMakeLists.txt b/AXrLottie/src/main/cpp/src/vector/stb/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/stb/stb_image.cpp b/AXrLottie/src/main/cpp/src/vector/stb/stb_image.cpp old mode 100755 new mode 100644 index 985b058..2c4933e --- a/AXrLottie/src/main/cpp/src/vector/stb/stb_image.cpp +++ b/AXrLottie/src/main/cpp/src/vector/stb/stb_image.cpp @@ -1,23 +1,30 @@ -#ifdef _WIN32 -#ifdef LOT_BUILD -#ifdef DLL_EXPORT -#define LOT_EXPORT __declspec(dllexport) -#else -#define LOT_EXPORT -#endif -#else -#define LOT_EXPORT __declspec(dllimport) -#endif -#else -#ifdef __GNUC__ -#if __GNUC__ >= 4 -#define LOT_EXPORT __attribute__((visibility("default"))) -#else -#define LOT_EXPORT -#endif +/* + * configure stb_image about + * the image we will support + */ +#define STB_IMAGE_IMPLEMENTATION + +#define STBI_ONLY_JPEG +#define STBI_ONLY_PNG +#define STBI_NO_HDR +#define STBI_NO_LINEAR +#define STBI_NO_GIF +#define STBI_NO_PIC + +#include "stb_image.h" + +#if defined _WIN32 || defined __CYGWIN__ + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __declspec(dllexport) + #else + #define RLOTTIE_API __declspec(dllimport) + #endif #else -#define LOT_EXPORT -#endif + #ifdef RLOTTIE_BUILD + #define RLOTTIE_API __attribute__ ((visibility ("default"))) + #else + #define RLOTTIE_API + #endif #endif #ifdef __cplusplus @@ -28,22 +35,23 @@ extern "C" { * exported function wrapper from the library */ -LOT_EXPORT unsigned char *lottie_image_load(char const *filename, int *x, +RLOTTIE_API unsigned char *lottie_image_load(char const *filename, int *x, int *y, int *comp, int req_comp) { - return nullptr; + return stbi_load(filename, x, y, comp, req_comp); } -LOT_EXPORT unsigned char *lottie_image_load_from_data(const char *imageData, +RLOTTIE_API unsigned char *lottie_image_load_from_data(const char *imageData, int len, int *x, int *y, int *comp, int req_comp) { - return nullptr; + unsigned char *data = (unsigned char *)imageData; + return stbi_load_from_memory(data, len, x, y, comp, req_comp); } -LOT_EXPORT void lottie_image_free(unsigned char *data) +RLOTTIE_API void lottie_image_free(unsigned char *data) { - + stbi_image_free(data); } #ifdef __cplusplus diff --git a/AXrLottie/src/main/cpp/src/vector/stb/stb_image.h b/AXrLottie/src/main/cpp/src/vector/stb/stb_image.h old mode 100755 new mode 100644 index b8ab055..ae0c1e5 --- a/AXrLottie/src/main/cpp/src/vector/stb/stb_image.h +++ b/AXrLottie/src/main/cpp/src/vector/stb/stb_image.h @@ -728,6 +728,26 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * s->img_buffer_original_end = s->img_buffer_end; } +// this is not threadsafe +static const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + + #ifndef STBI_NO_STDIO static int stbi__stdio_read(void *user, char *data, int size) @@ -737,7 +757,8 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { - fseek((FILE*) user, n, SEEK_CUR); + if (fseek((FILE*) user, n, SEEK_CUR) == -1) + stbi__err("fseek() error"); } static int stbi__stdio_eof(void *user) @@ -840,25 +861,6 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif -// this is not threadsafe -static const char *stbi__g_failure_reason; - -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} - -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; -} - -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} - // stb_image uses ints pervasively, including for offset calculations. // therefore the largest decoded image size we can support with the // current code, even on 64-bit targets, is INT_MAX. this is not a @@ -1078,8 +1080,8 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; } } #endif @@ -1176,7 +1178,10 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + if (fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR) == -1) { + stbi_image_free(result); + return stbi__errpuc("fseek() error", "File Seek Fail"); + } } return result; } @@ -1189,7 +1194,10 @@ STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + if (fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR) == -1) { + stbi_image_free(result); + return (stbi__uint16 *) stbi__errpuc("fseek() error", "File Seek Fail"); + } } return result; } @@ -1239,15 +1247,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - + stbi__context s; + stbi__start_mem(&s,buffer,len); + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } - return result; + return result; } #endif @@ -1342,7 +1350,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f) stbi__context s; stbi__start_file(&s,f); res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); + if (fseek(f, pos, SEEK_SET) == -1) return stbi__err("fseek() error", "File Seek Fail"); return res; #else STBI_NOTUSED(f); @@ -4580,6 +4588,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 } } STBI_FREE(a->out); + a->out = NULL; image_data += img_len; image_data_len -= img_len; } @@ -6133,7 +6142,7 @@ typedef struct int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; + stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; @@ -6221,7 +6230,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6230,12 +6239,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; + idx = g->cur_x + g->cur_y; p = &g->out[idx]; - g->history[idx / 4] = 1; + g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6344,31 +6353,31 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int dispose; - int first_frame; - int pi; - int pcount; + int dispose; + int first_frame; + int pi; + int pcount; // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; + first_frame = 0; if (g->out == 0) { if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->history = (stbi_uc *) stbi__malloc(g->w * g->h); + g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *) stbi__malloc(g->w * g->h); if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); - // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to teh color that was there the previous frame. - memset( g->out, 0x00, 4 * g->w * g->h ); + // color refers to teh color that was there the previous frame. + memset( g->out, 0x00, 4 * g->w * g->h ); memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - first_frame = 1; + first_frame = 1; } else { // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background @@ -6377,32 +6386,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { - // This is a non-disposal case eithe way, so just + // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } - // clear my history; + // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { - int tag = stbi__get8(s); + int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { @@ -6440,19 +6449,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - + return stbi__errpuc("missing color table", "Corrupt GIF"); + o = stbi__process_gif_raster(s, g); if (o == NULL) return NULL; - // if this was the first frame, - pcount = g->w * g->h; + // if this was the first frame, + pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } @@ -6463,7 +6472,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); + int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { @@ -6472,23 +6481,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // unset old transparent if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } + g->pal[g->transparent][3] = 255; + } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; + g->pal[g->transparent][3] = 0; } } else { // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; + stbi__skip(s, 1); + g->transparent = -1; } } else { stbi__skip(s, len); break; } - } + } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } @@ -6507,15 +6516,15 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { - int layers = 0; + int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; - stbi_uc *two_back = 0; + stbi_uc *two_back = 0; stbi__gif g; - int stride; + int stride; memset(&g, 0, sizeof(g)); if (delays) { - *delays = 0; + *delays = 0; } do { @@ -6525,44 +6534,44 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (u) { *x = g.w; *y = g.h; - ++layers; - stride = g.w * g.h * 4; - + ++layers; + stride = g.w * g.h * 4; + if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); } } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); + out = (stbi_uc*)stbi__malloc( layers * stride ); if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); + *delays = (int*) stbi__malloc( layers * sizeof(int) ); } } - memcpy( out + ((layers - 1) * stride), u, stride ); + memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out - 2 * stride; } if (delays) { - (*delays)[layers - 1U] = g.delay; + (*delays)[layers - 1U] = g.delay; } } - } while (u != 0); + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; + // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; + *z = layers; return out; } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); + return stbi__errpuc("not GIF", "Image was not as a gif type."); } } @@ -6579,14 +6588,14 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req *y = g.h; // moved conversion to after successful load so that the same - // can be done for multiple frames. + // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } - // free buffers needed for multiple frame loading; + // free buffers needed for multiple frame loading; STBI_FREE(g.history); - STBI_FREE(g.background); + STBI_FREE(g.background); return u; } @@ -7186,7 +7195,9 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) long pos = ftell(f); stbi__start_file(&s, f); r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); + if (pos >= 0) { + if (fseek(f,pos,SEEK_SET) == -1) return stbi__err("fseek() error", "File Seek Fail"); + } return r; } @@ -7207,7 +7218,9 @@ STBIDEF int stbi_is_16_bit_from_file(FILE *f) long pos = ftell(f); stbi__start_file(&s, f); r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); + if (pos >= 0) { + if (fseek(f,pos,SEEK_SET) == -1) return stbi__err("fseek() error", "File Seek Fail"); + } return r; } #endif // !STBI_NO_STDIO diff --git a/AXrLottie/src/main/cpp/src/vector/varenaalloc.cpp b/AXrLottie/src/main/cpp/src/vector/varenaalloc.cpp old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/varenaalloc.h b/AXrLottie/src/main/cpp/src/vector/varenaalloc.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/vbezier.cpp b/AXrLottie/src/main/cpp/src/vector/vbezier.cpp old mode 100755 new mode 100644 index c5d7a17..797d564 --- a/AXrLottie/src/main/cpp/src/vector/vbezier.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vbezier.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vbezier.h" @@ -39,23 +43,16 @@ VBezier VBezier::fromPoints(const VPointF &p1, const VPointF &p2, float VBezier::length() const { - VBezier left, right; /* bez poly splits */ - float len = 0.0; /* arc length */ - float chord; /* chord length */ - float length; + const auto len = VLine::length(x1, y1, x2, y2) + + VLine::length(x2, y2, x3, y3) + + VLine::length(x3, y3, x4, y4); - len = len + VLine::length(x1, y1, x2, y2); - len = len + VLine::length(x2, y2, x3, y3); - len = len + VLine::length(x3, y3, x4, y4); - - chord = VLine::length(x1, y1, x4, y4); + const auto chord = VLine::length(x1, y1, x4, y4); if ((len - chord) > 0.01) { - split(&left, &right); /* split in two */ - length = left.length() + /* try left side */ - right.length(); /* try right side */ - - return length; + VBezier left, right; + split(&left, &right); + return left.length() + right.length(); } return len; @@ -75,12 +72,11 @@ VBezier VBezier::onInterval(float t0, float t1) const return result; } -float VBezier::tAtLength(float l) const +float VBezier::tAtLength(float l, float totalLength) const { - float len = length(); float t = 1.0; - const float error = 0.01; - if (l > len || vCompare(l, len)) return t; + const float error = 0.01f; + if (l > totalLength || vCompare(l, totalLength)) return t; t *= 0.5; @@ -93,10 +89,10 @@ float VBezier::tAtLength(float l) const if (fabs(lLen - l) < error) break; if (lLen < l) { - t += (lastBigger - t) * 0.5; + t += (lastBigger - t) * 0.5f; } else { lastBigger = t; - t -= t * 0.5; + t -= t * 0.5f; } } return t; @@ -116,7 +112,7 @@ VPointF VBezier::derivative(float t) const // p'(t) = 3 * (-(1-2t+t^2) * p0 + (1 - 4 * t + 3 * t^2) * p1 + (2 * t - 3 * // t^2) * p2 + t^2 * p3) - float m_t = 1. - t; + float m_t = 1.0f - t; float d = t * t; float a = -m_t * m_t; diff --git a/AXrLottie/src/main/cpp/src/vector/vbezier.h b/AXrLottie/src/main/cpp/src/vector/vbezier.h old mode 100755 new mode 100644 index b07e782..18b7c59 --- a/AXrLottie/src/main/cpp/src/vector/vbezier.h +++ b/AXrLottie/src/main/cpp/src/vector/vbezier.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VBEZIER_H @@ -35,7 +39,8 @@ class VBezier { const VPointF &cp2, const VPointF &end); inline void parameterSplitLeft(float t, VBezier *left); inline void split(VBezier *firstHalf, VBezier *secondHalf) const; - float tAtLength(float len) const; + float tAtLength(float len) const { return tAtLength(len , length());} + float tAtLength(float len, float totalLength) const; void splitAtLength(float len, VBezier *left, VBezier *right); VPointF pt1() const { return {x1, y1}; } VPointF pt2() const { return {x2, y2}; } @@ -50,13 +55,13 @@ class VBezier { inline void VBezier::coefficients(float t, float &a, float &b, float &c, float &d) { - float m_t = 1. - t; + float m_t = 1.0f - t; b = m_t * m_t; c = t * t; d = c * t; a = b * m_t; - b *= 3. * t; - c *= 3. * m_t; + b *= 3.0f * t; + c *= 3.0f * m_t; } inline VPointF VBezier::pointAt(float t) const @@ -64,7 +69,7 @@ inline VPointF VBezier::pointAt(float t) const // numerically more stable: float x, y; - float m_t = 1. - t; + float m_t = 1.0f - t; { float a = x1 * m_t + x2 * t; float b = x2 * m_t + x3 * t; @@ -110,23 +115,23 @@ inline void VBezier::parameterSplitLeft(float t, VBezier *left) inline void VBezier::split(VBezier *firstHalf, VBezier *secondHalf) const { - float c = (x2 + x3) * .5; - firstHalf->x2 = (x1 + x2) * .5; - secondHalf->x3 = (x3 + x4) * .5; + float c = (x2 + x3) * 0.5f; + firstHalf->x2 = (x1 + x2) * 0.5f; + secondHalf->x3 = (x3 + x4) * 0.5f; firstHalf->x1 = x1; secondHalf->x4 = x4; - firstHalf->x3 = (firstHalf->x2 + c) * .5; - secondHalf->x2 = (secondHalf->x3 + c) * .5; - firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2) * .5; + firstHalf->x3 = (firstHalf->x2 + c) * 0.5f; + secondHalf->x2 = (secondHalf->x3 + c) * 0.5f; + firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2) * 0.5f; c = (y2 + y3) / 2; - firstHalf->y2 = (y1 + y2) * .5; - secondHalf->y3 = (y3 + y4) * .5; + firstHalf->y2 = (y1 + y2) * 0.5f; + secondHalf->y3 = (y3 + y4) * 0.5f; firstHalf->y1 = y1; secondHalf->y4 = y4; - firstHalf->y3 = (firstHalf->y2 + c) * .5; - secondHalf->y2 = (secondHalf->y3 + c) * .5; - firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2) * .5; + firstHalf->y3 = (firstHalf->y2 + c) * 0.5f; + secondHalf->y2 = (secondHalf->y3 + c) * 0.5f; + firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2) * 0.5f; } V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vbitmap.cpp b/AXrLottie/src/main/cpp/src/vector/vbitmap.cpp old mode 100755 new mode 100644 index 20963a6..22cb243 --- a/AXrLottie/src/main/cpp/src/vector/vbitmap.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vbitmap.cpp @@ -1,156 +1,138 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vbitmap.h" -#include +#include +#include #include "vdrawhelper.h" #include "vglobal.h" V_BEGIN_NAMESPACE -struct VBitmap::Impl { - uchar * mData{nullptr}; - uint mWidth{0}; - uint mHeight{0}; - uint mStride{0}; - uint mBytes{0}; - uint mDepth{0}; - VBitmap::Format mFormat{VBitmap::Format::Invalid}; - bool mOwnData; - bool mRoData; - - Impl() = delete; - - Impl(uint width, uint height, VBitmap::Format format) - : mOwnData(true), mRoData(false) - { - reset(width, height, format); - } - - void reset(uint width, uint height, VBitmap::Format format) - { - if (mOwnData && mData) delete (mData); +void VBitmap::Impl::reset(size_t width, size_t height, VBitmap::Format format) +{ + mRoData = nullptr; + mWidth = uint(width); + mHeight = uint(height); + mFormat = format; + + mDepth = depth(format); + mStride = ((mWidth * mDepth + 31) >> 5) + << 2; // bytes per scanline (must be multiple of 4) + mOwnData = std::make_unique(mStride * mHeight); +} - mDepth = depth(format); - uint stride = ((width * mDepth + 31) >> 5) - << 2; // bytes per scanline (must be multiple of 4) +void VBitmap::Impl::reset(uchar *data, size_t width, size_t height, size_t bytesPerLine, + VBitmap::Format format) +{ + mRoData = data; + mWidth = uint(width); + mHeight = uint(height); + mStride = uint(bytesPerLine); + mFormat = format; + mDepth = depth(format); + mOwnData = nullptr; +} - mWidth = width; - mHeight = height; - mFormat = format; - mStride = stride; - mBytes = mStride * mHeight; - mData = reinterpret_cast(::operator new(mBytes)); +uchar VBitmap::Impl::depth(VBitmap::Format format) +{ + uchar depth = 1; + switch (format) { + case VBitmap::Format::Alpha8: + depth = 8; + break; + case VBitmap::Format::ARGB32: + case VBitmap::Format::ARGB32_Premultiplied: + depth = 32; + break; + default: + break; } + return depth; +} - Impl(uchar *data, uint w, uint h, uint bytesPerLine, VBitmap::Format format) - : mOwnData(false), mRoData(false) - { - mWidth = w; - mHeight = h; - mFormat = format; - mStride = bytesPerLine; - mBytes = mStride * mHeight; - mData = data; - mDepth = depth(format); - } +void VBitmap::Impl::fill(uint /*pixel*/) +{ + //@TODO +} - ~Impl() - { - if (mOwnData && mData) ::operator delete(mData); - } +void VBitmap::Impl::updateLuma() +{ + if (mFormat != VBitmap::Format::ARGB32_Premultiplied) return; + auto dataPtr = data(); + for (uint col = 0; col < mHeight; col++) { + uint *pixel = (uint *)(dataPtr + mStride * col); + for (uint row = 0; row < mWidth; row++) { + int alpha = vAlpha(*pixel); + if (alpha == 0) { + pixel++; + continue; + } - uint stride() const { return mStride; } - uint width() const { return mWidth; } - uint height() const { return mHeight; } - VBitmap::Format format() const { return mFormat; } - uchar * data() { return mData; } - - static uint depth(VBitmap::Format format) - { - uint depth = 1; - switch (format) { - case VBitmap::Format::Alpha8: - depth = 8; - break; - case VBitmap::Format::ARGB32: - case VBitmap::Format::ARGB32_Premultiplied: - depth = 32; - break; - default: - break; - } - return depth; - } - void fill(uint /*pixel*/) - { - //@TODO - } + int red = vRed(*pixel); + int green = vGreen(*pixel); + int blue = vBlue(*pixel); - void updateLuma() - { - if (mFormat != VBitmap::Format::ARGB32_Premultiplied) return; - - for (uint col = 0; col < mHeight; col++) { - uint *pixel = (uint *)(mData + mStride * col); - for (uint row = 0; row < mWidth; row++) { - int alpha = vAlpha(*pixel); - if (alpha == 0) { - pixel++; - continue; - } - - int red = vRed(*pixel); - int green = vGreen(*pixel); - int blue = vBlue(*pixel); - - if (alpha != 255) { - // un multiply - red = (red * 255) / alpha; - green = (green * 255) / alpha; - blue = (blue * 255) / alpha; - } - int luminosity = (0.299 * red + 0.587 * green + 0.114 * blue); - *pixel = luminosity << 24; - pixel++; + if (alpha != 255) { + // un multiply + red = (red * 255) / alpha; + green = (green * 255) / alpha; + blue = (blue * 255) / alpha; } + int luminosity = int(0.299f * red + 0.587f * green + 0.114f * blue); + *pixel = luminosity << 24; + pixel++; } } -}; +} -VBitmap::VBitmap(uint width, uint height, VBitmap::Format format) +VBitmap::VBitmap(size_t width, size_t height, VBitmap::Format format) { if (width <= 0 || height <= 0 || format == Format::Invalid) return; - mImpl = std::make_shared(width, height, format); + mImpl = rc_ptr(width, height, format); } -VBitmap::VBitmap(uchar *data, uint width, uint height, uint bytesPerLine, +VBitmap::VBitmap(uchar *data, size_t width, size_t height, size_t bytesPerLine, VBitmap::Format format) { if (!data || width <= 0 || height <= 0 || bytesPerLine <= 0 || format == Format::Invalid) return; - mImpl = std::make_shared(data, width, height, bytesPerLine, format); + mImpl = rc_ptr(data, width, height, bytesPerLine, format); +} + +void VBitmap::reset(uchar *data, size_t w, size_t h, size_t bytesPerLine, + VBitmap::Format format) +{ + if (mImpl) { + mImpl->reset(data, w, h, bytesPerLine, format); + } else { + mImpl = rc_ptr(data, w, h, bytesPerLine, format); + } } -void VBitmap::reset(uint w, uint h, VBitmap::Format format) +void VBitmap::reset(size_t w, size_t h, VBitmap::Format format) { if (mImpl) { if (w == mImpl->width() && h == mImpl->height() && @@ -159,26 +141,26 @@ void VBitmap::reset(uint w, uint h, VBitmap::Format format) } mImpl->reset(w, h, format); } else { - mImpl = std::make_shared(w, h, format); + mImpl = rc_ptr(w, h, format); } } -uint VBitmap::stride() const +size_t VBitmap::stride() const { return mImpl ? mImpl->stride() : 0; } -uint VBitmap::width() const +size_t VBitmap::width() const { return mImpl ? mImpl->width() : 0; } -uint VBitmap::height() const +size_t VBitmap::height() const { return mImpl ? mImpl->height() : 0; } -uint VBitmap::depth() const +size_t VBitmap::depth() const { return mImpl ? mImpl->mDepth : 0; } @@ -193,9 +175,19 @@ uchar *VBitmap::data() const return mImpl ? mImpl->data() : nullptr; } +VRect VBitmap::rect() const +{ + return mImpl ? mImpl->rect() : VRect(); +} + +VSize VBitmap::size() const +{ + return mImpl ? mImpl->size() : VSize(); +} + bool VBitmap::valid() const { - return mImpl ? true : false; + return mImpl; } VBitmap::Format VBitmap::format() const diff --git a/AXrLottie/src/main/cpp/src/vector/vbitmap.h b/AXrLottie/src/main/cpp/src/vector/vbitmap.h old mode 100755 new mode 100644 index 8c49102..a068d74 --- a/AXrLottie/src/main/cpp/src/vector/vbitmap.h +++ b/AXrLottie/src/main/cpp/src/vector/vbitmap.h @@ -1,26 +1,30 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VBITMAP_H #define VBITMAP_H #include "vrect.h" -#include +#include V_BEGIN_NAMESPACE @@ -34,24 +38,55 @@ class VBitmap { }; VBitmap() = default; - VBitmap(uint w, uint h, VBitmap::Format format); - VBitmap(uchar *data, uint w, uint h, uint bytesPerLine, VBitmap::Format format); - - void reset(uint w, uint h, VBitmap::Format format=Format::ARGB32); - uint stride() const; - uint width() const; - uint height() const; - uint depth() const; + VBitmap(size_t w, size_t h, VBitmap::Format format); + VBitmap(uchar *data, size_t w, size_t h, size_t bytesPerLine, VBitmap::Format format); + void reset(uchar *data, size_t w, size_t h, size_t stride, VBitmap::Format format); + void reset(size_t w, size_t h, VBitmap::Format format=Format::ARGB32_Premultiplied); + size_t stride() const; + size_t width() const; + size_t height() const; + size_t depth() const; VBitmap::Format format() const; bool valid() const; uchar * data(); uchar * data() const; - + VRect rect() const; + VSize size() const; void fill(uint pixel); void updateLuma(); private: - struct Impl; - std::shared_ptr mImpl; + struct Impl { + std::unique_ptr mOwnData{nullptr}; + uchar * mRoData{nullptr}; + uint mWidth{0}; + uint mHeight{0}; + uint mStride{0}; + uchar mDepth{0}; + VBitmap::Format mFormat{VBitmap::Format::Invalid}; + + explicit Impl(size_t width, size_t height, VBitmap::Format format) + { + reset(width, height, format); + } + explicit Impl(uchar *data, size_t w, size_t h, size_t bytesPerLine, VBitmap::Format format) + { + reset(data, w, h, bytesPerLine, format); + } + VRect rect() const { return VRect(0, 0, mWidth, mHeight);} + VSize size() const { return VSize(mWidth, mHeight); } + size_t stride() const { return mStride; } + size_t width() const { return mWidth; } + size_t height() const { return mHeight; } + uchar * data() { return mRoData ? mRoData : mOwnData.get(); } + VBitmap::Format format() const { return mFormat; } + void reset(uchar *, size_t, size_t, size_t, VBitmap::Format); + void reset(size_t, size_t, VBitmap::Format); + static uchar depth(VBitmap::Format format); + void fill(uint); + void updateLuma(); + }; + + rc_ptr mImpl; }; V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vbrush.cpp b/AXrLottie/src/main/cpp/src/vector/vbrush.cpp old mode 100755 new mode 100644 index cdc114e..fc0902b --- a/AXrLottie/src/main/cpp/src/vector/vbrush.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vbrush.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vbrush.h" @@ -21,10 +25,13 @@ V_BEGIN_NAMESPACE VGradient::VGradient(VGradient::Type type) - : mType(type), - mSpread(VGradient::Spread::Pad), - mMode(VGradient::Mode::Absolute) + : mType(type) { + if (mType == Type::Linear) + linear.x1 = linear.y1 = linear.x2 = linear.y2 = 0.0f; + else + radial.cx = radial.cy = radial.fx = + radial.fy = radial.cradius = radial.fradius = 0.0f; } void VGradient::setStops(const VGradientStops &stops) @@ -32,54 +39,11 @@ void VGradient::setStops(const VGradientStops &stops) mStops = stops; } -VLinearGradient::VLinearGradient(const VPointF &start, const VPointF &stop) - : VGradient(VGradient::Type::Linear) -{ - linear.x1 = start.x(); - linear.y1 = start.y(); - linear.x1 = stop.x(); - linear.y1 = stop.y(); -} - -VLinearGradient::VLinearGradient(float xStart, float yStart, float xStop, - float yStop) - : VGradient(VGradient::Type::Linear) -{ - linear.x1 = xStart; - linear.y1 = yStart; - linear.x1 = xStop; - linear.y1 = yStop; -} - -VRadialGradient::VRadialGradient(const VPointF ¢er, float cradius, - const VPointF &focalPoint, float fradius) - : VGradient(VGradient::Type::Radial) -{ - radial.cx = center.x(); - radial.cy = center.y(); - radial.fx = focalPoint.x(); - radial.fy = focalPoint.y(); - radial.cradius = cradius; - radial.fradius = fradius; -} - -VRadialGradient::VRadialGradient(float cx, float cy, float cradius, float fx, - float fy, float fradius) - : VGradient(VGradient::Type::Radial) -{ - radial.cx = cx; - radial.cy = cy; - radial.fx = fx; - radial.fy = fy; - radial.cradius = cradius; - radial.fradius = fradius; -} - VBrush::VBrush(const VColor &color) : mType(VBrush::Type::Solid), mColor(color) { } -VBrush::VBrush(int r, int g, int b, int a) +VBrush::VBrush(uchar r, uchar g, uchar b, uchar a) : mType(VBrush::Type::Solid), mColor(r, g, b, a) { @@ -98,17 +62,8 @@ VBrush::VBrush(const VGradient *gradient) } } -VBrush::VBrush(const VBitmap &texture) -{ - if (!texture.valid()) return; - - mType = VBrush::Type::Texture; - mTexture = texture; -} - -void VBrush::setMatrix(const VMatrix &m) +VBrush::VBrush(const VTexture *texture):mType(VBrush::Type::Texture), mTexture(texture) { - mMatrix = m; } V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vbrush.h b/AXrLottie/src/main/cpp/src/vector/vbrush.h old mode 100755 new mode 100644 index 348e2ec..74f8dca --- a/AXrLottie/src/main/cpp/src/vector/vbrush.h +++ b/AXrLottie/src/main/cpp/src/vector/vbrush.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VBRUSH_H @@ -27,67 +31,60 @@ V_BEGIN_NAMESPACE -typedef std::pair VGradientStop; -typedef std::vector VGradientStops; +using VGradientStop = std::pair; +using VGradientStops = std::vector; class VGradient { public: enum class Mode { Absolute, Relative }; enum class Spread { Pad, Repeat, Reflect }; enum class Type { Linear, Radial }; - VGradient(VGradient::Type type); + explicit VGradient(VGradient::Type type); void setStops(const VGradientStops &stops); void setAlpha(float alpha) {mAlpha = alpha;} float alpha() const {return mAlpha;} - VGradient() = default; public: static constexpr int colorTableSize = 1024; - VGradient::Type mType; - VGradient::Spread mSpread; - VGradient::Mode mMode; + VGradient::Type mType{Type::Linear}; + VGradient::Spread mSpread{Spread::Pad}; + VGradient::Mode mMode{Mode::Absolute}; VGradientStops mStops; float mAlpha{1.0}; + struct Linear{ + float x1{0}, y1{0}, x2{0}, y2{0}; + }; + struct Radial{ + float cx{0}, cy{0}, fx{0}, fy{0}, cradius{0}, fradius{0}; + }; union { - struct { - float x1, y1, x2, y2; - } linear; - struct { - float cx, cy, fx, fy, cradius, fradius; - } radial; + Linear linear; + Radial radial; }; VMatrix mMatrix; }; -class VLinearGradient : public VGradient { -public: - VLinearGradient(const VPointF &start, const VPointF &stop); - VLinearGradient(float xStart, float yStart, float xStop, float yStop); -}; - -class VRadialGradient : public VGradient { -public: - VRadialGradient(const VPointF ¢er, float cradius, - const VPointF &focalPoint, float fradius); - VRadialGradient(float cx, float cy, float cradius, float fx, float fy, - float fradius); +struct VTexture { + VBitmap mBitmap; + VMatrix mMatrix; + int mAlpha{255}; }; class VBrush { public: enum class Type { NoBrush, Solid, LinearGradient, RadialGradient, Texture }; - VBrush() = default; - VBrush(const VColor &color); - VBrush(const VGradient *gradient); - VBrush(int r, int g, int b, int a); - VBrush(const VBitmap &texture); + VBrush():mType(Type::NoBrush),mColor(){}; + explicit VBrush(const VColor &color); + explicit VBrush(const VGradient *gradient); + explicit VBrush(uchar r, uchar g, uchar b, uchar a); + explicit VBrush(const VTexture *texture); inline VBrush::Type type() const { return mType; } - void setMatrix(const VMatrix &m); public: VBrush::Type mType{Type::NoBrush}; - VColor mColor; - const VGradient *mGradient{nullptr}; - VBitmap mTexture; - VMatrix mMatrix; + union { + VColor mColor{}; + const VGradient *mGradient; + const VTexture *mTexture; + }; }; V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vcompositionfunctions.cpp b/AXrLottie/src/main/cpp/src/vector/vcompositionfunctions.cpp deleted file mode 100755 index 52ac0db..0000000 --- a/AXrLottie/src/main/cpp/src/vector/vcompositionfunctions.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "vdrawhelper.h" - -/* - result = s - dest = s * ca + d * cia -*/ -void comp_func_solid_Source(uint32_t *dest, int length, uint32_t color, - uint32_t const_alpha) -{ - int ialpha, i; - - if (const_alpha == 255) { - memfill32(dest, color, length); - } else { - ialpha = 255 - const_alpha; - color = BYTE_MUL(color, const_alpha); - for (i = 0; i < length; ++i) - dest[i] = color + BYTE_MUL(dest[i], ialpha); - } -} - -/* - r = s + d * sia - dest = r * ca + d * cia - = (s + d * sia) * ca + d * cia - = s * ca + d * (sia * ca + cia) - = s * ca + d * (1 - sa*ca) - = s' + d ( 1 - s'a) -*/ -void comp_func_solid_SourceOver(uint32_t *dest, int length, uint32_t color, - uint32_t const_alpha) -{ - int ialpha, i; - - if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); - ialpha = 255 - vAlpha(color); - for (i = 0; i < length; ++i) dest[i] = color + BYTE_MUL(dest[i], ialpha); -} - -/* - result = d * sa - dest = d * sa * ca + d * cia - = d * (sa * ca + cia) -*/ -static void comp_func_solid_DestinationIn(uint *dest, int length, uint color, - uint const_alpha) -{ - uint a = vAlpha(color); - if (const_alpha != 255) { - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - } - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], a); - } -} - -/* - result = d * sia - dest = d * sia * ca + d * cia - = d * (sia * ca + cia) -*/ -static void comp_func_solid_DestinationOut(uint *dest, int length, uint color, - uint const_alpha) -{ - uint a = vAlpha(~color); - if (const_alpha != 255) a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void comp_func_Source(uint32_t *dest, const uint32_t *src, int length, - uint32_t const_alpha) -{ - if (const_alpha == 255) { - memcpy(dest, src, size_t(length) * sizeof(uint)); - } else { - uint ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = - INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -/* s' = s * ca - * d' = s' + d (1 - s'a) - */ -void comp_func_SourceOver(uint32_t *dest, const uint32_t *src, int length, - uint32_t const_alpha) -{ - uint s, sia; - - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - s = src[i]; - if (s >= 0xff000000) - dest[i] = s; - else if (s != 0) { - sia = vAlpha(~s); - dest[i] = s + BYTE_MUL(dest[i], sia); - } - } - } else { - /* source' = source * const_alpha - * dest = source' + dest ( 1- source'a) - */ - for (int i = 0; i < length; ++i) { - uint s = BYTE_MUL(src[i], const_alpha); - sia = vAlpha(~s); - dest[i] = s + BYTE_MUL(dest[i], sia); - } - } -} - -void comp_func_DestinationIn(uint *dest, const uint *src, int length, - uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], vAlpha(src[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - uint a = BYTE_MUL(vAlpha(src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], a); - } - } -} - -void comp_func_DestinationOut(uint *dest, const uint *src, int length, - uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = BYTE_MUL(dest[i], vAlpha(~src[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - uint sia = BYTE_MUL(vAlpha(~src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], sia); - } - } -} - -CompositionFunctionSolid COMP_functionForModeSolid_C[] = { - comp_func_solid_Source, comp_func_solid_SourceOver, - comp_func_solid_DestinationIn, comp_func_solid_DestinationOut}; - -CompositionFunction COMP_functionForMode_C[] = { - comp_func_Source, comp_func_SourceOver, comp_func_DestinationIn, - comp_func_DestinationOut}; - -void vInitBlendFunctions() {} diff --git a/AXrLottie/src/main/cpp/src/vector/vcowptr.h b/AXrLottie/src/main/cpp/src/vector/vcowptr.h old mode 100755 new mode 100644 index dcc283a..af2c7f2 --- a/AXrLottie/src/main/cpp/src/vector/vcowptr.h +++ b/AXrLottie/src/main/cpp/src/vector/vcowptr.h @@ -1,26 +1,30 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VCOWPTR_H #define VCOWPTR_H -#include -#include "vglobal.h" +#include +#include template class vcow_ptr { @@ -30,9 +34,8 @@ class vcow_ptr { model() = default; template - explicit model(Args&&... args) : mValue(std::forward(args)...) - { - } + explicit model(Args&&... args) : mValue(std::forward(args)...){} + explicit model(const T& other) : mValue(other){} T mValue; }; @@ -54,7 +57,7 @@ class vcow_ptr { } template - vcow_ptr(Args&&... args) : mModel(new model(std::forward(args)...)) + explicit vcow_ptr(Args&&... args) : mModel(new model(std::forward(args)...)) { } @@ -71,7 +74,8 @@ class vcow_ptr { auto operator=(const vcow_ptr& x) noexcept -> vcow_ptr& { - return *this = vcow_ptr(x); + *this = vcow_ptr(x); + return *this; } auto operator=(vcow_ptr&& x) noexcept -> vcow_ptr& @@ -85,7 +89,7 @@ class vcow_ptr { auto operator-> () const noexcept -> const element_type* { return &read(); } - int refCount() const noexcept + std::size_t refCount() const noexcept { assert(mModel); diff --git a/AXrLottie/src/main/cpp/src/vector/vdasher.cpp b/AXrLottie/src/main/cpp/src/vector/vdasher.cpp old mode 100755 new mode 100644 index 6134fa0..759e30a --- a/AXrLottie/src/main/cpp/src/vector/vdasher.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vdasher.cpp @@ -1,21 +1,24 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - #include "vbezier.h" #include @@ -25,6 +28,7 @@ V_BEGIN_NAMESPACE +static constexpr float tolerance = 0.1f; VDasher::VDasher(const float *dashArray, size_t size) { mDashArray = reinterpret_cast(dashArray); @@ -33,6 +37,15 @@ VDasher::VDasher(const float *dashArray, size_t size) mIndex = 0; mCurrentLength = 0; mDiscard = false; + //if the dash array contains ZERO length + // segments or ZERO lengths gaps we could + // optimize those usecase. + for (size_t i = 0; i < mArraySize; i++) { + if (!vCompare(mDashArray[i].length, 0.0f)) + mNoLength = false; + if (!vCompare(mDashArray[i].gap, 0.0f)) + mNoGap = false; + } } void VDasher::moveTo(const VPointF &p) @@ -80,10 +93,10 @@ void VDasher::addLine(const VPointF &p) if (mDiscard) return; if (mStartNewSegment) { - mResult.moveTo(mCurPt); + mResult->moveTo(mCurPt); mStartNewSegment = false; } - mResult.lineTo(p); + mResult->lineTo(p); } void VDasher::updateActiveSegment() @@ -122,13 +135,13 @@ void VDasher::lineTo(const VPointF &p) mCurPt = line.p1(); } // handle remainder - if (length > 1.0f) { + if (length > tolerance) { mCurrentLength -= length; addLine(line.p2()); } } - if (mCurrentLength < 1.0f) updateActiveSegment(); + if (mCurrentLength < tolerance) updateActiveSegment(); mCurPt = p; } @@ -138,10 +151,10 @@ void VDasher::addCubic(const VPointF &cp1, const VPointF &cp2, const VPointF &e) if (mDiscard) return; if (mStartNewSegment) { - mResult.moveTo(mCurPt); + mResult->moveTo(mCurPt); mStartNewSegment = false; } - mResult.cubicTo(cp1, cp2, e); + mResult->cubicTo(cp1, cp2, e); } void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e) @@ -165,23 +178,21 @@ void VDasher::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF &e) mCurPt = b.pt1(); } // handle remainder - if (bezLen > 1.0f) { + if (bezLen > tolerance) { mCurrentLength -= bezLen; addCubic(b.pt2(), b.pt3(), b.pt4()); } } - if (mCurrentLength < 1.0f) updateActiveSegment(); + if (mCurrentLength < tolerance) updateActiveSegment(); mCurPt = e; } -VPath VDasher::dashed(const VPath &path) +void VDasher::dashHelper(const VPath &path, VPath &result) { - if (path.empty()) return VPath(); - - mResult = {}; - mResult.reserve(path.points().size(), path.elements().size()); + mResult = &result; + mResult->reserve(path.points().size(), path.elements().size()); mIndex = 0; const std::vector &elms = path.elements(); const std::vector & pts = path.points(); @@ -209,10 +220,35 @@ VPath VDasher::dashed(const VPath &path) } } } - if (mResult.points().size() > SHRT_MAX) { - mResult.reset(); - } - return std::move(mResult); + mResult = nullptr; +} + +void VDasher::dashed(const VPath &path, VPath &result) +{ + if (mNoLength && mNoGap) return result.reset(); + + if (path.empty() || mNoLength) return result.reset(); + + if (mNoGap) return result.clone(path); + + result.reset(); + + dashHelper(path, result); +} + +VPath VDasher::dashed(const VPath &path) +{ + if (mNoLength && mNoGap) return path; + + if (path.empty() || mNoLength) return VPath(); + + if (mNoGap) return path; + + VPath result; + + dashHelper(path, result); + + return result; } V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vdasher.h b/AXrLottie/src/main/cpp/src/vector/vdasher.h old mode 100755 new mode 100644 index 224a2a8..d9d62c2 --- a/AXrLottie/src/main/cpp/src/vector/vdasher.h +++ b/AXrLottie/src/main/cpp/src/vector/vdasher.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VDASHER_H @@ -26,6 +30,7 @@ class VDasher { public: VDasher(const float *dashArray, size_t size); VPath dashed(const VPath &path); + void dashed(const VPath &path, VPath &result); private: void moveTo(const VPointF &p); @@ -37,6 +42,7 @@ class VDasher { void updateActiveSegment(); private: + void dashHelper(const VPath &path, VPath &result); struct Dash { float length; float gap; @@ -46,10 +52,12 @@ class VDasher { VPointF mCurPt; size_t mIndex{0}; /* index to the dash Array */ float mCurrentLength; - bool mDiscard; float mDashOffset{0}; - VPath mResult; - bool mStartNewSegment=true; + VPath *mResult{nullptr}; + bool mDiscard{false}; + bool mStartNewSegment{true}; + bool mNoLength{true}; + bool mNoGap{true}; }; V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vdebug.cpp b/AXrLottie/src/main/cpp/src/vector/vdebug.cpp old mode 100755 new mode 100644 index 8a0c19c..03196ef --- a/AXrLottie/src/main/cpp/src/vector/vdebug.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vdebug.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vdebug.h" diff --git a/AXrLottie/src/main/cpp/src/vector/vdebug.h b/AXrLottie/src/main/cpp/src/vector/vdebug.h old mode 100755 new mode 100644 index 83ffdb0..5b6bef5 --- a/AXrLottie/src/main/cpp/src/vector/vdebug.h +++ b/AXrLottie/src/main/cpp/src/vector/vdebug.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VDEBUG_H diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawable.cpp b/AXrLottie/src/main/cpp/src/vector/vdrawable.cpp old mode 100755 new mode 100644 index 946054f..c8ff02b --- a/AXrLottie/src/main/cpp/src/vector/vdrawable.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vdrawable.cpp @@ -1,37 +1,75 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vdrawable.h" #include "vdasher.h" #include "vraster.h" +VDrawable::VDrawable(VDrawable::Type type) +{ + setType(type); +} + +VDrawable::~VDrawable() noexcept +{ + if (mStrokeInfo) { + if (mType == Type::StrokeWithDash) { + delete static_cast(mStrokeInfo); + } else { + delete mStrokeInfo; + } + } +} + +void VDrawable::setType(VDrawable::Type type) +{ + mType = type; + if (mType == VDrawable::Type::Stroke) { + mStrokeInfo = new StrokeInfo(); + } else if (mType == VDrawable::Type::StrokeWithDash) { + mStrokeInfo = new StrokeWithDashInfo(); + } +} + +void VDrawable::applyDashOp() +{ + if (mStrokeInfo && (mType == Type::StrokeWithDash)) { + auto obj = static_cast(mStrokeInfo); + if (!obj->mDash.empty()) { + VDasher dasher(obj->mDash.data(), obj->mDash.size()); + mPath.clone(dasher.dashed(mPath)); + } + } +} + void VDrawable::preprocess(const VRect &clip) { if (mFlag & (DirtyState::Path)) { - if (mStroke.enable) { - if (mStroke.mDash.size()) { - VDasher dasher(mStroke.mDash.data(), mStroke.mDash.size()); - mPath = dasher.dashed(mPath); - } - mRasterizer.rasterize(std::move(mPath), mStroke.cap, mStroke.join, - mStroke.width, mStroke.meterLimit, clip); - } else { + if (mType == Type::Fill) { mRasterizer.rasterize(std::move(mPath), mFillRule, clip); + } else { + applyDashOp(); + mRasterizer.rasterize(std::move(mPath), mStrokeInfo->cap, mStrokeInfo->join, + mStrokeInfo->width, mStrokeInfo->miterLimit, clip); } mPath = {}; mFlag &= ~DirtyFlag(DirtyState::Path); @@ -43,29 +81,33 @@ VRle VDrawable::rle() return mRasterizer.rle(); } -void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, +void VDrawable::setStrokeInfo(CapStyle cap, JoinStyle join, float miterLimit, float strokeWidth) { - if ((mStroke.cap == cap) && (mStroke.join == join) && - vCompare(mStroke.meterLimit, meterLimit) && - vCompare(mStroke.width, strokeWidth)) + assert(mStrokeInfo); + if ((mStrokeInfo->cap == cap) && (mStrokeInfo->join == join) && + vCompare(mStrokeInfo->miterLimit, miterLimit) && + vCompare(mStrokeInfo->width, strokeWidth)) return; - mStroke.enable = true; - mStroke.cap = cap; - mStroke.join = join; - mStroke.meterLimit = meterLimit; - mStroke.width = strokeWidth; + mStrokeInfo->cap = cap; + mStrokeInfo->join = join; + mStrokeInfo->miterLimit = miterLimit; + mStrokeInfo->width = strokeWidth; mFlag |= DirtyState::Path; } -void VDrawable::setDashInfo(float *array, uint size) +void VDrawable::setDashInfo(std::vector &dashInfo) { + assert(mStrokeInfo); + assert(mType == VDrawable::Type::StrokeWithDash); + + auto obj = static_cast(mStrokeInfo); bool hasChanged = false; - if (mStroke.mDash.size() == size) { - for (uint i = 0; i < size; i++) { - if (!vCompare(mStroke.mDash[i], array[i])) { + if (obj->mDash.size() == dashInfo.size()) { + for (uint i = 0; i < dashInfo.size(); ++i) { + if (!vCompare(obj->mDash[i], dashInfo[i])) { hasChanged = true; break; } @@ -76,11 +118,8 @@ void VDrawable::setDashInfo(float *array, uint size) if (!hasChanged) return; - mStroke.mDash.clear(); + obj->mDash = dashInfo; - for (uint i = 0; i < size; i++) { - mStroke.mDash.push_back(array[i]); - } mFlag |= DirtyState::Path; } diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawable.h b/AXrLottie/src/main/cpp/src/vector/vdrawable.h old mode 100755 new mode 100644 index e6553e5..357a69f --- a/AXrLottie/src/main/cpp/src/vector/vdrawable.h +++ b/AXrLottie/src/main/cpp/src/vector/vdrawable.h @@ -1,24 +1,29 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VDRAWABLE_H #define VDRAWABLE_H #include +#include #include "vbrush.h" #include "vpath.h" #include "vrle.h" @@ -26,44 +31,63 @@ class VDrawable { public: - enum class DirtyState { - None = 0x00000000, - Path = 0x00000001, - Stroke = 0x00000010, - Brush = 0x00000100, - All = (None | Path | Stroke | Brush) + enum class DirtyState : unsigned char { + None = 1<<0, + Path = 1<<1, + Stroke = 1<<2, + Brush = 1<<3, + All = (Path | Stroke | Brush) }; + enum class Type : unsigned char{ Fill, Stroke, + StrokeWithDash }; + + explicit VDrawable(VDrawable::Type type = Type::Fill); + void setType(VDrawable::Type type); + ~VDrawable() noexcept; + typedef vFlag DirtyFlag; void setPath(const VPath &path); void setFillRule(FillRule rule) { mFillRule = rule; } void setBrush(const VBrush &brush) { mBrush = brush; } - void setStrokeInfo(CapStyle cap, JoinStyle join, float meterLimit, + void setStrokeInfo(CapStyle cap, JoinStyle join, float miterLimit, float strokeWidth); - void setDashInfo(float *array, uint size); + void setDashInfo(std::vector &dashInfo); void preprocess(const VRect &clip); + void applyDashOp(); VRle rle(); + void setName(const char *name) + { + mName = name; + } + const char* name() const { return mName; } public: struct StrokeInfo { - std::vector mDash; float width{0.0}; - float meterLimit{10}; - bool enable{false}; + float miterLimit{10}; CapStyle cap{CapStyle::Flat}; JoinStyle join{JoinStyle::Bevel}; }; - VRasterizer mRasterizer; - VBrush mBrush; - VPath mPath; - StrokeInfo mStroke; - DirtyFlag mFlag{DirtyState::All}; - FillRule mFillRule{FillRule::Winding}; - VDrawable::Type mType{Type::Fill}; - VMatrix loadTransformMatrix; + + struct StrokeWithDashInfo : public StrokeInfo{ + std::vector mDash; + }; + +public: + VPath mPath; + VBrush mBrush; + VRasterizer mRasterizer; + StrokeInfo *mStrokeInfo{nullptr}; + + DirtyFlag mFlag{DirtyState::All}; + FillRule mFillRule{FillRule::Winding}; + VDrawable::Type mType{Type::Fill}; + + const char *mName{nullptr}; }; #endif // VDRAWABLE_H diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawhelper.cpp b/AXrLottie/src/main/cpp/src/vector/vdrawhelper.cpp old mode 100755 new mode 100644 index 2bc7fc7..b14146d --- a/AXrLottie/src/main/cpp/src/vector/vdrawhelper.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vdrawhelper.cpp @@ -1,61 +1,42 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - #include "vdrawhelper.h" #include #include #include #include #include +#include + +static RenderFuncTable RenderTable; + +void VTextureData::setClip(const VRect &clip) +{ + left = clip.left(); + top = clip.top(); + right = std::min(clip.right(), int(width())) - 1; + bottom = std::min(clip.bottom(), int(height())) - 1; +} class VGradientCache { public: @@ -76,7 +57,8 @@ class VGradientCache { VCacheData info; const VGradientStops &stops = gradient.mStops; for (uint i = 0; i < stops.size() && i <= 2; i++) - hash_val += (stops[i].second.premulARGB() * gradient.alpha()); + hash_val += + VCacheKey(stops[i].second.premulARGB() * gradient.alpha()); { std::lock_guard guard(mMutex); @@ -111,6 +93,12 @@ class VGradientCache { return info; } + static VGradientCache &instance() + { + static VGradientCache CACHE; + return CACHE; + } + protected: uint maxCacheSize() const { return 60; } VCacheData addCacheElement(VCacheKey hash_val, const VGradient &gradient) @@ -129,6 +117,9 @@ class VGradientCache { return cache_entry; } +private: + VGradientCache() = default; + VGradientColorTableHash mCache; std::mutex mMutex; }; @@ -137,9 +128,10 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, float opacity, uint32_t *colorTable, int size) { - int dist, idist, pos = 0, i; + int dist, idist, pos = 0; + size_t i; bool alpha = false; - int stopCount = stops.size(); + size_t stopCount = stops.size(); const VGradientStop *curr, *next, *start; uint32_t curColor, nextColor; float delta, t, incr, fpos; @@ -150,12 +142,12 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, curr = start; if (!curr->second.isOpaque()) alpha = true; curColor = curr->second.premulARGB(opacity); - incr = 1.0 / (float)size; - fpos = 1.5 * incr; + incr = 1.0f / (float)size; + fpos = 1.5f * incr; colorTable[pos++] = curColor; - while (fpos <= curr->first && pos < size) { + while (fpos <= curr->first) { colorTable[pos] = colorTable[pos - 1]; pos++; fpos += incr; @@ -172,7 +164,7 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, dist = (int)(255 * t); idist = 255 - dist; colorTable[pos] = - INTERPOLATE_PIXEL_255(curColor, idist, nextColor, dist); + interpolate_pixel(curColor, idist, nextColor, dist); ++pos; fpos += incr; } @@ -186,14 +178,12 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, return alpha; } -static VGradientCache VGradientCacheInstance; - void VRasterBuffer::clear() { memset(mBuffer, 0, mHeight * mBytesPerLine); } -VBitmap::Format VRasterBuffer::prepare(VBitmap *image) +VBitmap::Format VRasterBuffer::prepare(const VBitmap *image) { mBuffer = image->data(); mWidth = image->width(); @@ -208,18 +198,12 @@ VBitmap::Format VRasterBuffer::prepare(VBitmap *image) void VSpanData::init(VRasterBuffer *image) { mRasterBuffer = image; - setDrawRegion(VRect(0, 0, image->width(), image->height())); + setDrawRegion(VRect(0, 0, int(image->width()), int(image->height()))); mType = VSpanData::Type::None; mBlendFunc = nullptr; mUnclippedBlendFunc = nullptr; } -extern CompositionFunction COMP_functionForMode_C[]; -extern CompositionFunctionSolid COMP_functionForModeSolid_C[]; -static const CompositionFunction * functionForMode = COMP_functionForMode_C; -static const CompositionFunctionSolid *functionForModeSolid = - COMP_functionForModeSolid_C; - /* * Gradient Draw routines * @@ -348,9 +332,9 @@ void fetch_linear_gradient(uint32_t *buffer, const Operator *op, float rw = data->m23 * (y + float(0.5)) + data->m13 * (x + float(0.5)) + data->m33; while (buffer < end) { - float x = rx / rw; - float y = ry / rw; - t = (op->linear.dx * x + op->linear.dy * y) + op->linear.off; + float xt = rx / rw; + float yt = ry / rw; + t = (op->linear.dx * xt + op->linear.dy * yt) + op->linear.off; *buffer = gradientPixel(gradient, t); rx += data->m11; @@ -497,8 +481,7 @@ void fetch_radial_gradient(uint32_t *buffer, const Operator *op, } } -static inline Operator getOperator(const VSpanData *data, const VRle::Span *, - size_t) +static inline Operator getOperator(const VSpanData *data) { Operator op; bool solidSource = false; @@ -523,70 +506,61 @@ static inline Operator getOperator(const VSpanData *data, const VRle::Span *, break; } - op.mode = data->mCompositionMode; - if (op.mode == VPainter::CompModeSrcOver && solidSource) - op.mode = VPainter::CompModeSrc; + op.mode = data->mBlendMode; + if (op.mode == BlendMode::SrcOver && solidSource) op.mode = BlendMode::Src; - op.funcSolid = functionForModeSolid[op.mode]; - op.func = functionForMode[op.mode]; + op.funcSolid = RenderTable.color(op.mode); + op.func = RenderTable.src(op.mode); return op; } -static void blendColorARGB(size_t count, const VRle::Span *spans, - void *userData) +static void blend_color(size_t size, const VRle::Span *array, void *userData) { VSpanData *data = (VSpanData *)(userData); - Operator op = getOperator(data, spans, count); + Operator op = getOperator(data); const uint color = data->mSolid; - if (op.mode == VPainter::CompModeSrc) { - // inline for performance - while (count--) { - uint *target = data->buffer(spans->x, spans->y); - if (spans->coverage == 255) { - memfill32(target, color, spans->len); - } else { - uint c = BYTE_MUL(color, spans->coverage); - int ialpha = 255 - spans->coverage; - for (int i = 0; i < spans->len; ++i) - target[i] = c + BYTE_MUL(target[i], ialpha); - } - ++spans; - } - return; + for (size_t i = 0 ; i < size; ++i) { + const auto &span = array[i]; + op.funcSolid(data->buffer(span.x, span.y), span.len, color, span.coverage); } +} - while (count--) { - uint *target = data->buffer(spans->x, spans->y); - op.funcSolid(target, spans->len, color, spans->coverage); - ++spans; +// Signature of Process Object +// void Pocess(uint* scratchBuffer, size_t x, size_t y, uchar cov) +template +static inline void process_in_chunk(const VRle::Span *array, size_t size, + Process process) +{ + std::array buf; + for (size_t i = 0; i < size; i++) { + const auto &span = array[i]; + size_t len = span.len; + auto x = span.x; + while (len) { + auto l = std::min(len, buf.size()); + process(buf.data(), x, span.y, l, span.coverage); + x += l; + len -= l; + } } } -#define BLEND_GRADIENT_BUFFER_SIZE 2048 -static void blendGradientARGB(size_t count, const VRle::Span *spans, - void *userData) +static void blend_gradient(size_t size, const VRle::Span *array, + void *userData) { VSpanData *data = (VSpanData *)(userData); - Operator op = getOperator(data, spans, count); - - unsigned int buffer[BLEND_GRADIENT_BUFFER_SIZE]; + Operator op = getOperator(data); if (!op.srcFetch) return; - while (count--) { - uint *target = data->buffer(spans->x, spans->y); - int length = spans->len; - while (length) { - int l = std::min(length, BLEND_GRADIENT_BUFFER_SIZE); - op.srcFetch(buffer, &op, data, spans->y, spans->x, l); - op.func(target, buffer, l, spans->coverage); - target += l; - length -= l; - } - ++spans; - } + process_in_chunk( + array, size, + [&](uint *scratch, size_t x, size_t y, size_t len, uchar cov) { + op.srcFetch(scratch, &op, data, (int)y, (int)x, (int)len); + op.func(data->buffer((int)x, (int)y), (int)len, scratch, cov); + }); } template @@ -595,156 +569,82 @@ constexpr const T &clamp(const T &v, const T &lo, const T &hi) return v < lo ? lo : hi < v ? hi : v; } -static const int buffer_size = 1024; -static const int fixed_scale = 1 << 16; -static void blend_transformed_argb(size_t count, const VRle::Span *spans, - void *userData) +static constexpr inline uchar alpha_mul(uchar a, uchar b) +{ + return ((a * b) >> 8); +} + +static void blend_image_xform(size_t size, const VRle::Span *array, + void *userData) { - VSpanData *data = reinterpret_cast(userData); - if (data->mBitmap.format != VBitmap::Format::ARGB32_Premultiplied && - data->mBitmap.format != VBitmap::Format::ARGB32) { + const auto data = reinterpret_cast(userData); + const auto &src = data->texture(); + + if (src.format() != VBitmap::Format::ARGB32_Premultiplied && + src.format() != VBitmap::Format::ARGB32) { //@TODO other formats not yet handled. return; } - Operator op = getOperator(data, spans, count); - uint buffer[buffer_size]; - - const int image_x1 = data->mBitmap.x1; - const int image_y1 = data->mBitmap.y1; - const int image_x2 = data->mBitmap.x2 - 1; - const int image_y2 = data->mBitmap.y2 - 1; - - if (data->fast_matrix) { - // The increment pr x in the scanline - int fdx = (int)(data->m11 * fixed_scale); - int fdy = (int)(data->m12 * fixed_scale); - - while (count--) { - uint *target = data->buffer(spans->x, spans->y); - - const float cx = spans->x + float(0.5); - const float cy = spans->y + float(0.5); - - int x = - int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); - int y = - int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale); - - int length = spans->len; - const int coverage = - (spans->coverage * data->mBitmap.const_alpha) >> 8; - while (length) { - int l = std::min(length, buffer_size); - const uint *end = buffer + l; - uint * b = buffer; - while (b < end) { - int px = clamp(x >> 16, image_x1, image_x2); - int py = clamp(y >> 16, image_y1, image_y2); - *b = reinterpret_cast( - data->mBitmap.scanLine(py))[px]; - - x += fdx; - y += fdy; - ++b; - } - op.func(target, buffer, l, coverage); - target += l; - length -= l; - } - ++spans; - } - } else { - const float fdx = data->m11; - const float fdy = data->m12; - const float fdw = data->m13; - while (count--) { - uint *target = data->buffer(spans->x, spans->y); - - const float cx = spans->x + float(0.5); - const float cy = spans->y + float(0.5); - - float x = data->m21 * cy + data->m11 * cx + data->dx; - float y = data->m22 * cy + data->m12 * cx + data->dy; - float w = data->m23 * cy + data->m13 * cx + data->m33; - - int length = spans->len; - const int coverage = - (spans->coverage * data->mBitmap.const_alpha) >> 8; - while (length) { - int l = std::min(length, buffer_size); - const uint *end = buffer + l; - uint * b = buffer; - while (b < end) { - const float iw = w == 0 ? 1 : 1 / w; - const float tx = x * iw; - const float ty = y * iw; - const int px = - clamp(int(tx) - (tx < 0), image_x1, image_x2); - const int py = - clamp(int(ty) - (ty < 0), image_y1, image_y2); - - *b = reinterpret_cast( - data->mBitmap.scanLine(py))[px]; - x += fdx; - y += fdy; - w += fdw; - - ++b; - } - op.func(target, buffer, l, coverage); - target += l; - length -= l; + Operator op = getOperator(data); + + process_in_chunk( + array, size, + [&](uint *scratch, size_t x, size_t y, size_t len, uchar cov) { + const auto coverage = (cov * src.alpha()) >> 8; + const float xfactor = y * data->m21 + data->dx + data->m11; + const float yfactor = y * data->m22 + data->dy + data->m12; + for (size_t i = 0; i < len; i++) { + const float fx = (x + i) * data->m11 + xfactor; + const float fy = (x + i) * data->m12 + yfactor; + const int px = clamp(int(fx), src.left, src.right); + const int py = clamp(int(fy), src.top, src.bottom); + scratch[i] = src.pixel(px, py); } - ++spans; - } - } + op.func(data->buffer((int)x, (int)y), (int)len, scratch, coverage); + }); } -static void blend_untransformed_argb(size_t count, const VRle::Span *spans, - void *userData) +static void blend_image(size_t size, const VRle::Span *array, void *userData) { - VSpanData *data = reinterpret_cast(userData); - if (data->mBitmap.format != VBitmap::Format::ARGB32_Premultiplied && - data->mBitmap.format != VBitmap::Format::ARGB32) { + const auto data = reinterpret_cast(userData); + const auto &src = data->texture(); + + if (src.format() != VBitmap::Format::ARGB32_Premultiplied && + src.format() != VBitmap::Format::ARGB32) { //@TODO other formats not yet handled. return; } - Operator op = getOperator(data, spans, count); - - const int image_width = data->mBitmap.width; - const int image_height = data->mBitmap.height; - - int xoff = data->dx; - int yoff = data->dy; - - while (count--) { - int x = spans->x; - int length = spans->len; - int sx = xoff + x; - int sy = yoff + spans->y; - if (sy >= 0 && sy < image_height && sx < image_width) { - if (sx < 0) { - x -= sx; - length += sx; - sx = 0; - } - if (sx + length > image_width) length = image_width - sx; - if (length > 0) { - const int coverage = - (spans->coverage * data->mBitmap.const_alpha) >> 8; - const uint *src = (const uint *)data->mBitmap.scanLine(sy) + sx; - uint * dest = data->buffer(x, spans->y); - op.func(dest, src, length, coverage); - } + Operator op = getOperator(data); + + for (size_t i = 0; i < size; i++) { + const auto &span = array[i]; + int x = span.x; + int length = span.len; + int sx = x + int(data->dx); + int sy = span.y + int(data->dy); + + // notyhing to copy. + if (sy < 0 || sy >= int(src.height()) || sx >= int(src.width()) || + (sx + length) <= 0) + continue; + + // intersecting left edge of image + if (sx < 0) { + x -= sx; + length += sx; + sx = 0; } - ++spans; + // intersecting right edge of image + if (sx + length > int(src.width())) length = (int)src.width() - sx; + + op.func(data->buffer(x, span.y), length, src.pixelRef(sx, sy), + alpha_mul(span.coverage, src.alpha())); } } -void VSpanData::setup(const VBrush &brush, VPainter::CompositionMode /*mode*/, - int /*alpha*/) +void VSpanData::setup(const VBrush &brush, BlendMode /*mode*/, int /*alpha*/) { transformType = VMatrix::MatrixType::None; @@ -758,7 +658,7 @@ void VSpanData::setup(const VBrush &brush, VPainter::CompositionMode /*mode*/, break; case VBrush::Type::LinearGradient: { mType = VSpanData::Type::LinearGradient; - mColorTable = VGradientCacheInstance.getBuffer(*brush.mGradient); + mColorTable = VGradientCache::instance().getBuffer(*brush.mGradient); mGradient.mColorTable = mColorTable->buffer32; mGradient.mColorTableAlpha = mColorTable->alpha; mGradient.linear.x1 = brush.mGradient->linear.x1; @@ -771,7 +671,7 @@ void VSpanData::setup(const VBrush &brush, VPainter::CompositionMode /*mode*/, } case VBrush::Type::RadialGradient: { mType = VSpanData::Type::RadialGradient; - mColorTable = VGradientCacheInstance.getBuffer(*brush.mGradient); + mColorTable = VGradientCache::instance().getBuffer(*brush.mGradient); mGradient.mColorTable = mColorTable->buffer32; mGradient.mColorTableAlpha = mColorTable->alpha; mGradient.radial.cx = brush.mGradient->radial.cx; @@ -786,10 +686,9 @@ void VSpanData::setup(const VBrush &brush, VPainter::CompositionMode /*mode*/, } case VBrush::Type::Texture: { mType = VSpanData::Type::Texture; - initTexture( - &brush.mTexture, 255, VBitmapData::Plain, - VRect(0, 0, brush.mTexture.width(), brush.mTexture.height())); - setupMatrix(brush.mMatrix); + initTexture(&brush.mTexture->mBitmap, brush.mTexture->mAlpha, + brush.mTexture->mBitmap.rect()); + setupMatrix(brush.mTexture->mMatrix); break; } default: @@ -820,23 +719,12 @@ void VSpanData::setupMatrix(const VMatrix &matrix) } void VSpanData::initTexture(const VBitmap *bitmap, int alpha, - VBitmapData::Type type, const VRect &sourceRect) + const VRect &sourceRect) { mType = VSpanData::Type::Texture; - - mBitmap.imageData = bitmap->data(); - mBitmap.width = bitmap->width(); - mBitmap.height = bitmap->height(); - mBitmap.bytesPerLine = bitmap->stride(); - mBitmap.format = bitmap->format(); - mBitmap.x1 = sourceRect.x(); - mBitmap.y1 = sourceRect.y(); - mBitmap.x2 = std::min(mBitmap.x1 + sourceRect.width(), mBitmap.width); - mBitmap.y2 = std::min(mBitmap.y1 + sourceRect.height(), mBitmap.height); - - mBitmap.const_alpha = alpha; - mBitmap.type = type; - + mTexture.prepare(bitmap); + mTexture.setClip(sourceRect); + mTexture.setAlpha(alpha); updateSpanFunc(); } @@ -847,79 +735,32 @@ void VSpanData::updateSpanFunc() mUnclippedBlendFunc = nullptr; break; case VSpanData::Type::Solid: - mUnclippedBlendFunc = &blendColorARGB; + mUnclippedBlendFunc = &blend_color; break; case VSpanData::Type::LinearGradient: case VSpanData::Type::RadialGradient: { - mUnclippedBlendFunc = &blendGradientARGB; + mUnclippedBlendFunc = &blend_gradient; break; } case VSpanData::Type::Texture: { //@TODO update proper image function. if (transformType <= VMatrix::MatrixType::Translate) { - mUnclippedBlendFunc = &blend_untransformed_argb; + mUnclippedBlendFunc = &blend_image; } else { - mUnclippedBlendFunc = &blend_transformed_argb; + mUnclippedBlendFunc = &blend_image_xform; } break; } } } -#if !defined(__ARM_NEON__) && !defined(__ARM64_NEON__) - +#if !defined(__SSE2__) && !defined(__ARM_NEON__) void memfill32(uint32_t *dest, uint32_t value, int length) { - int n; - - if (length <= 0) return; - - // Cute hack to align future memcopy operation - // and do unroll the loop a bit. Not sure it is - // the most efficient, but will do for now. - n = (length + 7) / 8; - switch (length & 0x07) { - case 0: - do { - *dest++ = value; - VECTOR_FALLTHROUGH; - case 7: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 6: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 5: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 4: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 3: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 2: - *dest++ = value; - VECTOR_FALLTHROUGH; - case 1: - *dest++ = value; - } while (--n > 0); + // let compiler do the auto vectorization. + for (int i = 0 ; i < length; i++) { + *dest++ = value; } } #endif -void vInitDrawhelperFunctions() -{ - vInitBlendFunctions(); - -#if defined(__ARM_NEON__) || defined(__ARM64_NEON__) - // update fast path for NEON - extern void comp_func_solid_SourceOver_neon( - uint32_t * dest, int length, uint32_t color, uint32_t const_alpha); - - COMP_functionForModeSolid_C[VPainter::CompModeSrcOver] = - comp_func_solid_SourceOver_neon; -#endif -} - -V_CONSTRUCTOR_FUNCTION(vInitDrawhelperFunctions) diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawhelper.h b/AXrLottie/src/main/cpp/src/vector/vdrawhelper.h old mode 100755 new mode 100644 index 55e182f..e654e93 --- a/AXrLottie/src/main/cpp/src/vector/vdrawhelper.h +++ b/AXrLottie/src/main/cpp/src/vector/vdrawhelper.h @@ -1,30 +1,33 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VDRAWHELPER_H #define VDRAWHELPER_H -#include #include +#include #include "assert.h" #include "vbitmap.h" #include "vbrush.h" -#include "vpainter.h" #include "vrect.h" #include "vrle.h" @@ -33,10 +36,54 @@ V_USE_NAMESPACE struct VSpanData; struct Operator; -typedef void (*CompositionFunctionSolid)(uint32_t *dest, int length, - uint32_t color, uint32_t const_alpha); -typedef void (*CompositionFunction)(uint32_t *dest, const uint32_t *src, - int length, uint32_t const_alpha); +struct RenderFunc +{ + using Color = void (*)(uint32_t *dest, int length, uint32_t color, uint32_t alpha); + using Src = void (*)(uint32_t *dest, int length, const uint32_t *src, uint32_t alpha); + enum class Type { + Invalid, + Color, + Src, + }; + RenderFunc() = default; + RenderFunc(Type t, Color f):type_(t), color_(f){assert(t == Type::Color);} + RenderFunc(Type t, Src f):type_(t), src_(f){ assert(t == Type::Src);} + + Type type_{Type::Invalid}; + union { + Color color_; + Src src_; + }; +}; + +class RenderFuncTable +{ +public: + RenderFuncTable(); + RenderFunc::Color color(BlendMode mode) const + { + return colorTable[uint32_t(mode)].color_; + } + RenderFunc::Src src(BlendMode mode) const + { + return srcTable[uint32_t(mode)].src_; + } +private: + void neon(); + void sse(); + void updateColor(BlendMode mode, RenderFunc::Color f) + { + colorTable[uint32_t(mode)] = {RenderFunc::Type::Color, f}; + } + void updateSrc(BlendMode mode, RenderFunc::Src f) + { + srcTable[uint32_t(mode)] = {RenderFunc::Type::Src, f}; + } +private: + std::array colorTable; + std::array srcTable; +}; + typedef void (*SourceFetchProc)(uint32_t *buffer, const Operator *o, const VSpanData *data, int y, int x, int length); @@ -63,10 +110,10 @@ struct RadialGradientValues { }; struct Operator { - VPainter::CompositionMode mode; - SourceFetchProc srcFetch; - CompositionFunctionSolid funcSolid; - CompositionFunction func; + BlendMode mode; + SourceFetchProc srcFetch; + RenderFunc::Color funcSolid; + RenderFunc::Src func; union { LinearGradientValues linear; RadialGradientValues radial; @@ -75,7 +122,7 @@ struct Operator { class VRasterBuffer { public: - VBitmap::Format prepare(VBitmap *image); + VBitmap::Format prepare(const VBitmap *image); void clear(); void resetBuffer(int val = 0); @@ -83,63 +130,60 @@ class VRasterBuffer { inline uchar *scanLine(int y) { assert(y >= 0); - assert(y < mHeight); + assert(size_t(y) < mHeight); return mBuffer + y * mBytesPerLine; } + uint32_t *pixelRef(int x, int y) const + { + return (uint32_t *)(mBuffer + y * mBytesPerLine + x * mBytesPerPixel); + } - int width() const { return mWidth; } - int height() const { return mHeight; } - int bytesPerLine() const { return mBytesPerLine; } - int bytesPerPixel() const { return mBytesPerPixel; } + size_t width() const { return mWidth; } + size_t height() const { return mHeight; } + size_t bytesPerLine() const { return mBytesPerLine; } + size_t bytesPerPixel() const { return mBytesPerPixel; } + VBitmap::Format format() const { return mFormat; } - VBitmap::Format mFormat{VBitmap::Format::ARGB32}; private: - int mWidth{0}; - int mHeight{0}; - int mBytesPerLine{0}; - int mBytesPerPixel{0}; - uchar *mBuffer{nullptr}; + VBitmap::Format mFormat{VBitmap::Format::ARGB32_Premultiplied}; + size_t mWidth{0}; + size_t mHeight{0}; + size_t mBytesPerLine{0}; + size_t mBytesPerPixel{0}; + mutable uchar * mBuffer{nullptr}; }; struct VGradientData { VGradient::Spread mSpread; + struct Linear { + float x1, y1, x2, y2; + }; + struct Radial { + float cx, cy, fx, fy, cradius, fradius; + }; union { - struct { - float x1, y1, x2, y2; - } linear; - struct { - float cx, cy, fx, fy, cradius, fradius; - } radial; + Linear linear; + Radial radial; }; const uint32_t *mColorTable; bool mColorTableAlpha; }; -struct VBitmapData -{ - const uchar *imageData; - const uchar *scanLine(int y) const { return imageData + y*bytesPerLine; } - - int width; - int height; +struct VTextureData : public VRasterBuffer { + uint32_t pixel(int x, int y) const { return *pixelRef(x, y); }; + uchar alpha() const { return mAlpha; } + void setAlpha(uchar alpha) { mAlpha = alpha; } + void setClip(const VRect &clip); // clip rect - int x1; - int y1; - int x2; - int y2; - uint bytesPerLine; - VBitmap::Format format; - bool hasAlpha; - enum Type { - Plain, - Tiled - }; - Type type; - int const_alpha; + int left; + int right; + int top; + int bottom; + bool hasAlpha; + uchar mAlpha; }; -struct VColorTable -{ +struct VColorTable { uint32_t buffer32[VGradient::colorTableSize]; bool alpha{true}; }; @@ -147,12 +191,11 @@ struct VColorTable struct VSpanData { enum class Type { None, Solid, LinearGradient, RadialGradient, Texture }; - void updateSpanFunc(); - void init(VRasterBuffer *image); - void setup(const VBrush & brush, - VPainter::CompositionMode mode = VPainter::CompModeSrcOver, - int alpha = 255); - void setupMatrix(const VMatrix &matrix); + void updateSpanFunc(); + void init(VRasterBuffer *image); + void setup(const VBrush &brush, BlendMode mode = BlendMode::SrcOver, + int alpha = 255); + void setupMatrix(const VMatrix &matrix); VRect clipRect() const { @@ -167,31 +210,28 @@ struct VSpanData { uint *buffer(int x, int y) const { - return (uint *)(mRasterBuffer->scanLine(y + mOffset.y())) + x + mOffset.x(); + return mRasterBuffer->pixelRef(x + mOffset.x(), y + mOffset.y()); } - void initTexture(const VBitmap *image, int alpha, VBitmapData::Type type, const VRect &sourceRect); - - VPainter::CompositionMode mCompositionMode{VPainter::CompositionMode::CompModeSrcOver}; - VRasterBuffer * mRasterBuffer; - ProcessRleSpan mBlendFunc; - ProcessRleSpan mUnclippedBlendFunc; - VSpanData::Type mType; - std::shared_ptr mColorTable{nullptr}; - VPoint mOffset; // offset to the subsurface - VSize mDrawableSize;// suburface size - union { - uint32_t mSolid; - VGradientData mGradient; - VBitmapData mBitmap; - }; + void initTexture(const VBitmap *image, int alpha, const VRect &sourceRect); + const VTextureData &texture() const { return mTexture; } + + BlendMode mBlendMode{BlendMode::SrcOver}; + VRasterBuffer * mRasterBuffer; + ProcessRleSpan mBlendFunc; + ProcessRleSpan mUnclippedBlendFunc; + VSpanData::Type mType; + std::shared_ptr mColorTable{nullptr}; + VPoint mOffset; // offset to the subsurface + VSize mDrawableSize; // suburface size + uint32_t mSolid; + VGradientData mGradient; + VTextureData mTexture; + float m11, m12, m13, m21, m22, m23, m33, dx, dy; // inverse xform matrix - bool fast_matrix{true}; - VMatrix::MatrixType transformType{VMatrix::MatrixType::None}; + bool fast_matrix{true}; + VMatrix::MatrixType transformType{VMatrix::MatrixType::None}; }; -void vInitDrawhelperFunctions(); -extern void vInitBlendFunctions(); - #define BYTE_MUL(c, a) \ ((((((c) >> 8) & 0x00ff00ff) * (a)) & 0xff00ff00) + \ (((((c)&0x00ff00ff) * (a)) >> 8) & 0x00ff00ff)) @@ -216,7 +256,7 @@ inline constexpr int vAlpha(uint32_t c) return c >> 24; } -static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) +static inline uint32_t interpolate_pixel(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t >>= 8; @@ -227,22 +267,4 @@ static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) return x; } -#define LOOP_ALIGNED_U1_A4(DEST, LENGTH, UOP, A4OP) \ - { \ - while ((uintptr_t)DEST & 0xF && LENGTH) \ - UOP \ - \ - while (LENGTH) \ - { \ - switch (LENGTH) { \ - case 3: \ - case 2: \ - case 1: \ - UOP break; \ - default: \ - A4OP break; \ - } \ - } \ - } - #endif // QDRAWHELPER_P_H diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawhelper_common.cpp b/AXrLottie/src/main/cpp/src/vector/vdrawhelper_common.cpp old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawhelper_neon.cpp b/AXrLottie/src/main/cpp/src/vector/vdrawhelper_neon.cpp old mode 100755 new mode 100644 index 2ef56ef..681eabb --- a/AXrLottie/src/main/cpp/src/vector/vdrawhelper_neon.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vdrawhelper_neon.cpp @@ -1,4 +1,4 @@ -#if defined(__ARM_NEON__) || defined(__ARM64_NEON__) +#if defined(__ARM_NEON__) #include "vdrawhelper.h" @@ -17,11 +17,17 @@ void memfill32(uint32_t *dest, uint32_t value, int length) pixman_composite_src_n_8888_asm_neon(length, 1, dest, length, value); } -void comp_func_solid_SourceOver_neon(uint32_t *dest, int length, uint32_t color, +static void color_SourceOver(uint32_t *dest, int length, + uint32_t color, uint32_t const_alpha) { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); pixman_composite_over_n_8888_asm_neon(length, 1, dest, length, color); } + +void RenderFuncTable::neon() +{ + updateColor(BlendMode::Src , color_SourceOver); +} #endif diff --git a/AXrLottie/src/main/cpp/src/vector/vdrawhelper_sse2.cpp b/AXrLottie/src/main/cpp/src/vector/vdrawhelper_sse2.cpp old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/velapsedtimer.cpp b/AXrLottie/src/main/cpp/src/vector/velapsedtimer.cpp old mode 100755 new mode 100644 index 4c74027..42aa452 --- a/AXrLottie/src/main/cpp/src/vector/velapsedtimer.cpp +++ b/AXrLottie/src/main/cpp/src/vector/velapsedtimer.cpp @@ -1,21 +1,24 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ #include "velapsedtimer.h" void VElapsedTimer::start() diff --git a/AXrLottie/src/main/cpp/src/vector/velapsedtimer.h b/AXrLottie/src/main/cpp/src/vector/velapsedtimer.h old mode 100755 new mode 100644 index 108fd66..d53d38a --- a/AXrLottie/src/main/cpp/src/vector/velapsedtimer.h +++ b/AXrLottie/src/main/cpp/src/vector/velapsedtimer.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VELAPSEDTIMER_H diff --git a/AXrLottie/src/main/cpp/src/vector/vglobal.h b/AXrLottie/src/main/cpp/src/vector/vglobal.h old mode 100755 new mode 100644 index 98837fd..45e95e3 --- a/AXrLottie/src/main/cpp/src/vector/vglobal.h +++ b/AXrLottie/src/main/cpp/src/vector/vglobal.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VGLOBAL_H @@ -25,9 +29,9 @@ #include #include -typedef uint32_t uint; -typedef uint16_t ushort; -typedef uint8_t uchar; +using uint = uint32_t; +using ushort = uint16_t; +using uchar = uint8_t; #if !defined(V_NAMESPACE) @@ -70,46 +74,17 @@ typedef uint8_t uchar; #define VECTOR_FALLTHROUGH #endif -#include -class RefCount { -public: - inline RefCount(int i) : atomic(i) {} - inline bool ref() - { - int count = atomic.load(); - if (count == 0) // !isSharable - return false; - if (count != -1) // !isStatic - atomic.fetch_add(1); - return true; - } - inline bool deref() - { - int count = atomic.load(); - if (count == 0) // !isSharable - return false; - if (count == -1) // isStatic - return true; - atomic.fetch_sub(1); - return --count; - } - bool isShared() const - { - int count = atomic.load(); - return (count != 1) && (count != 0); - } - bool isStatic() const - { - // Persistent object, never deleted - int count = atomic.load(); - return count == -1; - } - inline int count() const { return atomic; } - void setOwned() { atomic.store(1); } +#ifdef LOTTIE_THREAD_SUPPORT +#define vthread_local thread_local +#else +#define vthread_local +#endif -private: - std::atomic atomic; -}; +#if defined(_MSC_VER) + #define V_ALWAYS_INLINE __forceinline +#else + #define V_ALWAYS_INLINE __attribute__((always_inline)) +#endif template V_CONSTEXPR inline const T &vMin(const T &a, const T &b) @@ -144,12 +119,12 @@ class vFlagHelper { int i; public: - constexpr inline vFlagHelper(int ai) noexcept : i(ai) {} + explicit constexpr inline vFlagHelper(int ai) noexcept : i(ai) {} constexpr inline operator int() const noexcept { return i; } - constexpr inline vFlagHelper(uint ai) noexcept : i(int(ai)) {} - constexpr inline vFlagHelper(short ai) noexcept : i(int(ai)) {} - constexpr inline vFlagHelper(ushort ai) noexcept : i(int(uint(ai))) {} + explicit constexpr inline vFlagHelper(uint ai) noexcept : i(int(ai)) {} + explicit constexpr inline vFlagHelper(short ai) noexcept : i(int(ai)) {} + explicit constexpr inline vFlagHelper(ushort ai) noexcept : i(int(uint(ai))) {} constexpr inline operator uint() const noexcept { return uint(i); } }; @@ -162,16 +137,16 @@ class vFlag { static_assert((std::is_enum::value), "vFlag is only usable on enumeration types."); - typedef typename std::conditional< + using Int = typename std::conditional< std::is_unsigned::type>::value, - unsigned int, signed int>::type Int; + unsigned int, signed int>::type; - typedef Enum enum_type; + using enum_type = Enum; // compiler-generated copy/move ctor/assignment operators are fine! - constexpr inline vFlag(Enum f) noexcept : i(Int(f)) {} - constexpr inline vFlag() noexcept : i(0) {} - constexpr inline vFlag(vFlagHelper f) noexcept : i(f) {} + vFlag() = default; + constexpr vFlag(Enum f) noexcept : i(Int(f)) {} + explicit constexpr vFlag(vFlagHelper f) noexcept : i(f) {} inline vFlag &operator&=(int mask) noexcept { @@ -255,28 +230,24 @@ class vFlag { return on ? (*this |= f) : (*this &= ~f); } - Int i; + Int i{0}; }; class VColor { public: - inline VColor() noexcept { a = r = g = b = 0; } - inline VColor(int red, int green, int blue, int alpha = 255) noexcept - { - r = red; - g = green; - b = blue; - a = alpha; - } - inline int red() const noexcept { return r; } - inline int green() const noexcept { return g; } - inline int blue() const noexcept { return b; } - inline int alpha() const noexcept { return a; } - inline void setRed(int red) noexcept { r = red; } - inline void setGreen(int green) noexcept { g = green; } - inline void setBlue(int blue) noexcept { b = blue; } - inline void setAlpha(int alpha) noexcept { a = alpha; } + VColor() = default; + explicit VColor(uchar red, uchar green, uchar blue, uchar alpha = 255) noexcept + :a(alpha), r(red), g(green), b(blue){} + inline uchar red() const noexcept { return r; } + inline uchar green() const noexcept { return g; } + inline uchar blue() const noexcept { return b; } + inline uchar alpha() const noexcept { return a; } + inline void setRed(uchar red) noexcept { r = red; } + inline void setGreen(uchar green) noexcept { g = green; } + inline void setBlue(uchar blue) noexcept { b = blue; } + inline void setAlpha(uchar alpha) noexcept { a = alpha; } inline bool isOpaque() const { return a == 255; } + inline bool isTransparent() const { return a == 0; } inline bool operator==(const VColor &o) const { return ((a == o.a) && (r == o.r) && (g == o.g) && (b == o.b)); @@ -291,7 +262,7 @@ class VColor { uint premulARGB(float opacity) const { - int alpha = a * opacity; + int alpha = int(a * opacity); int pr = (r * alpha) / 255; int pg = (g * alpha) / 255; int pb = (b * alpha) / 255; @@ -299,16 +270,24 @@ class VColor { } public: - uchar a; - uchar r; - uchar g; - uchar b; + uchar a{0}; + uchar r{0}; + uchar g{0}; + uchar b{0}; }; enum class FillRule: unsigned char { EvenOdd, Winding }; enum class JoinStyle: unsigned char { Miter, Bevel, Round }; enum class CapStyle: unsigned char { Flat, Square, Round }; +enum class BlendMode { + Src, + SrcOver, + DestIn, + DestOut, + Last, +}; + #ifndef V_CONSTRUCTOR_FUNCTION #define V_CONSTRUCTOR_FUNCTION0(AFUNC) \ namespace { \ diff --git a/AXrLottie/src/main/cpp/src/vector/vimageloader.cpp b/AXrLottie/src/main/cpp/src/vector/vimageloader.cpp old mode 100755 new mode 100644 index 79d7de2..c2446be --- a/AXrLottie/src/main/cpp/src/vector/vimageloader.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vimageloader.cpp @@ -1,13 +1,14 @@ #include "vimageloader.h" #include "config.h" #include "vdebug.h" -#ifndef WIN32 -#include -#else -#include -#endif #include +#ifdef _WIN32 +# include +#else +# include +#endif // _WIN32 + using lottie_image_load_f = unsigned char *(*)(const char *filename, int *x, int *y, int *comp, int req_comp); using lottie_image_load_data_f = unsigned char *(*)(const char *data, int len, @@ -35,12 +36,12 @@ struct VImageLoader::Impl { lottie_image_free_f imageFree{nullptr}; lottie_image_load_data_f imageFromData{nullptr}; -#ifndef LOTTIE_STATIC_IMAGE_LOADER -#ifdef WIN32 +#ifdef LOTTIE_IMAGE_MODULE_SUPPORT +# ifdef _WIN32 HMODULE dl_handle{nullptr}; bool moduleLoad() { - dl_handle = LoadLibraryA("librlottie-image-loader.dll"); + dl_handle = LoadLibraryA(LOTTIE_IMAGE_MODULE_PLUGIN); return (dl_handle == nullptr); } void moduleFree() @@ -49,43 +50,36 @@ struct VImageLoader::Impl { } void init() { - imageLoad = - (lottie_image_load_f)GetProcAddress(dl_handle, "lottie_image_load"); - imageFree = - (lottie_image_free_f)GetProcAddress(dl_handle, "lottie_image_free"); - imageFromData = (lottie_image_load_data_f)GetProcAddress( - dl_handle, "lottie_image_load_from_data"); + imageLoad = reinterpret_cast( + GetProcAddress(dl_handle, "lottie_image_load")); + imageFree = reinterpret_cast( + GetProcAddress(dl_handle, "lottie_image_free")); + imageFromData = reinterpret_cast( + GetProcAddress(dl_handle, "lottie_image_load_from_data")); } -#else +# else // _WIN32 void *dl_handle{nullptr}; void init() { - imageLoad = (lottie_image_load_f)dlsym(dl_handle, "lottie_image_load"); - imageFree = (lottie_image_free_f)dlsym(dl_handle, "lottie_image_free"); - imageFromData = (lottie_image_load_data_f)dlsym( - dl_handle, "lottie_image_load_from_data"); + imageLoad = reinterpret_cast( + dlsym(dl_handle, "lottie_image_load")); + imageFree = reinterpret_cast( + dlsym(dl_handle, "lottie_image_free")); + imageFromData = reinterpret_cast( + dlsym(dl_handle, "lottie_image_load_from_data")); } void moduleFree() { if (dl_handle) dlclose(dl_handle); } -#ifdef __APPLE__ bool moduleLoad() { - dl_handle = dlopen("librlottie-image-loader.dylib", RTLD_LAZY); + dl_handle = dlopen(LOTTIE_IMAGE_MODULE_PLUGIN, RTLD_LAZY); return (dl_handle == nullptr); } -#else - bool moduleLoad() - { - dl_handle = dlopen("librlottie-image-loader.so", RTLD_LAZY); - return (dl_handle == nullptr); - } -#endif -#endif -#else - void *dl_handle{nullptr}; +# endif // _WIN32 +#else // LOTTIE_IMAGE_MODULE_SUPPORT void init() { imageLoad = lottie_image_load; @@ -94,7 +88,7 @@ struct VImageLoader::Impl { } void moduleFree() {} bool moduleLoad() { return false; } -#endif +#endif // LOTTIE_IMAGE_MODULE_SUPPORT Impl() { @@ -131,7 +125,7 @@ struct VImageLoader::Impl { // create a bitmap of same size. VBitmap result = - VBitmap(width, height, VBitmap::Format::ARGB32); + VBitmap(width, height, VBitmap::Format::ARGB32_Premultiplied); // copy the data to bitmap buffer memcpy(result.data(), data, width * height * 4); @@ -156,13 +150,13 @@ struct VImageLoader::Impl { return createBitmap(data, width, height, n); } - VBitmap load(const char *imageData, int len) + VBitmap load(const char *imageData, size_t len) { if (!imageFromData) return VBitmap(); int width, height, n; unsigned char *data = - imageFromData(imageData, len, &width, &height, &n, 4); + imageFromData(imageData, static_cast(len), &width, &height, &n, 4); if (!data) { return VBitmap(); @@ -220,7 +214,7 @@ VBitmap VImageLoader::load(const char *fileName) return mImpl->load(fileName); } -VBitmap VImageLoader::load(const char *data, int len) +VBitmap VImageLoader::load(const char *data, size_t len) { - return mImpl->load(data, len); + return mImpl->load(data, int(len)); } diff --git a/AXrLottie/src/main/cpp/src/vector/vimageloader.h b/AXrLottie/src/main/cpp/src/vector/vimageloader.h old mode 100755 new mode 100644 index 2ca4cec..4d96a7d --- a/AXrLottie/src/main/cpp/src/vector/vimageloader.h +++ b/AXrLottie/src/main/cpp/src/vector/vimageloader.h @@ -15,7 +15,7 @@ class VImageLoader } VBitmap load(const char *fileName); - VBitmap load(const char *data, int len); + VBitmap load(const char *data, size_t len); ~VImageLoader(); private: VImageLoader(); diff --git a/AXrLottie/src/main/cpp/src/vector/vinterpolator.cpp b/AXrLottie/src/main/cpp/src/vector/vinterpolator.cpp old mode 100755 new mode 100644 index 94f454a..fca0784 --- a/AXrLottie/src/main/cpp/src/vector/vinterpolator.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vinterpolator.cpp @@ -1,38 +1,8 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SMIL module. - * - * The Initial Developer of the Original Code is Brian Birtles. - * Portions created by the Initial Developer are Copyright (C) 2005 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Brian Birtles - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "vinterpolator.h" #include @@ -45,7 +15,7 @@ V_BEGIN_NAMESPACE #define SUBDIVISION_MAX_ITERATIONS 10 const float VInterpolator::kSampleStepSize = - 1.0 / float(VInterpolator::kSplineTableSize - 1); + 1.0f / float(VInterpolator::kSplineTableSize - 1); void VInterpolator::init(float aX1, float aY1, float aX2, float aY2) { @@ -72,7 +42,7 @@ void VInterpolator::CalcSampleValues() float VInterpolator::GetSlope(float aT, float aA1, float aA2) { - return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + return 3.0f * A(aA1, aA2) * aT * aT + 2.0f * B(aA1, aA2) * aT + C(aA1); } float VInterpolator::value(float aX) const @@ -137,7 +107,7 @@ float VInterpolator::BinarySubdivide(float aX, float aA, float aB) const int i = 0; do { - currentT = aA + (aB - aA) / 2.0; + currentT = aA + (aB - aA) / 2.0f; currentX = CalcBezier(currentT, mX1, mX2) - aX; if (currentX > 0.0) { diff --git a/AXrLottie/src/main/cpp/src/vector/vinterpolator.h b/AXrLottie/src/main/cpp/src/vector/vinterpolator.h old mode 100755 new mode 100644 index 77aaaae..0218eab --- a/AXrLottie/src/main/cpp/src/vector/vinterpolator.h +++ b/AXrLottie/src/main/cpp/src/vector/vinterpolator.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VINTERPOLATOR_H @@ -64,11 +68,11 @@ class VInterpolator { float BinarySubdivide(float aX, float aA, float aB) const; - static float A(float aA1, float aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } + static float A(float aA1, float aA2) { return 1.0f - 3.0f * aA2 + 3.0f * aA1; } - static float B(float aA1, float aA2) { return 3.0 * aA2 - 6.0 * aA1; } + static float B(float aA1, float aA2) { return 3.0f * aA2 - 6.0f * aA1; } - static float C(float aA1) { return 3.0 * aA1; } + static float C(float aA1) { return 3.0f * aA1; } float mX1; float mY1; diff --git a/AXrLottie/src/main/cpp/src/vector/vline.h b/AXrLottie/src/main/cpp/src/vector/vline.h old mode 100755 new mode 100644 index f466e31..ee8b4a5 --- a/AXrLottie/src/main/cpp/src/vector/vline.h +++ b/AXrLottie/src/main/cpp/src/vector/vline.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VLINE_H @@ -51,17 +55,18 @@ class VLine { inline float VLine::angle() const { + static constexpr float K_PI = 3.141592f; const float dx = mX2 - mX1; const float dy = mY2 - mY1; - const float theta = std::atan2(dy, dx) * 180.0 / M_PI; + const float theta = std::atan2(dy, dx) * 180.0f / K_PI; return theta; } // approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. // With alpha = 1, beta = 3/8, giving results with the largest error less // than 7% compared to the exact value. -inline float VLine::length(float x1, float y1, float x2, float y2) +inline V_ALWAYS_INLINE float VLine::length(float x1, float y1, float x2, float y2) { float x = x2 - x1; float y = y2 - y1; @@ -69,7 +74,7 @@ inline float VLine::length(float x1, float y1, float x2, float y2) x = x < 0 ? -x : x; y = y < 0 ? -y : y; - return (x > y ? x + 0.375 * y : y + 0.375 * x); + return (x > y ? x + 0.375f * y : y + 0.375f * x); } inline void VLine::splitAtLength(float lengthAt, VLine &left, VLine &right) const diff --git a/AXrLottie/src/main/cpp/src/vector/vmatrix.cpp b/AXrLottie/src/main/cpp/src/vector/vmatrix.cpp old mode 100755 new mode 100644 index 3ca1404..7efed61 --- a/AXrLottie/src/main/cpp/src/vector/vmatrix.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vmatrix.cpp @@ -1,26 +1,29 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vmatrix.h" #include #include #include -#include V_BEGIN_NAMESPACE @@ -511,8 +514,8 @@ VMatrix VMatrix::inverted(bool *invertible) const inv = !vIsZero(m11); inv &= !vIsZero(m22); if (inv) { - invert.m11 = 1. / m11; - invert.m22 = 1. / m22; + invert.m11 = 1.0f / m11; + invert.m22 = 1.0f / m22; invert.mtx = -mtx * invert.m11; invert.mty = -mty * invert.m22; } @@ -554,7 +557,7 @@ bool VMatrix::fuzzyCompare(const VMatrix &o) const vCompare(mtx, o.mtx) && vCompare(mty, o.mty); } -#define V_NEAR_CLIP 0.000001 +#define V_NEAR_CLIP 0.000001f #ifdef MAP #undef MAP #endif @@ -594,13 +597,13 @@ VRect VMatrix::map(const VRect &rect) const { VMatrix::MatrixType t = type(); if (t <= MatrixType::Translate) - return rect.translated(round(mtx), round(mty)); + return rect.translated(std::lround(mtx), std::lround(mty)); if (t <= MatrixType::Scale) { - int x = round(m11 * rect.x() + mtx); - int y = round(m22 * rect.y() + mty); - int w = round(m11 * rect.width()); - int h = round(m22 * rect.height()); + int x = std::lround(m11 * rect.x() + mtx); + int y = std::lround(m22 * rect.y() + mty); + int w = std::lround(m11 * rect.width()); + int h = std::lround(m22 * rect.height()); if (w < 0) { w = -w; x -= w; @@ -633,32 +636,14 @@ VRect VMatrix::map(const VRect &rect) const ymin = vMin(ymin, y); xmax = vMax(xmax, x); ymax = vMax(ymax, y); - return VRect(round(xmin), round(ymin), - round(xmax) - round(xmin), - round(ymax) - round(ymin)); + return VRect(std::lround(xmin), std::lround(ymin), + std::lround(xmax) - std::lround(xmin), + std::lround(ymax) - std::lround(ymin)); } else { // Not supported assert(0); + return {}; } - return {0, 0, 0, 0}; -} - -VRegion VMatrix::map(const VRegion &r) const -{ - VMatrix::MatrixType t = type(); - if (t == MatrixType::None) return r; - - if (t == MatrixType::Translate) { - VRegion copy(r); - copy.translate(round(mtx), round(mty)); - return copy; - } - - if (t == MatrixType::Scale && r.rectCount() == 1) - return VRegion(map(r.boundingRect())); - // handle mapping of region properly - assert(0); - return r; } VPointF VMatrix::map(const VPointF &p) const @@ -688,45 +673,12 @@ VPointF VMatrix::map(const VPointF &p) const x = m11 * fx + m21 * fy + mtx; y = m12 * fx + m22 * fy + mty; if (t == MatrixType::Project) { - float w = 1. / (m13 * fx + m23 * fy + m33); + float w = 1.0f / (m13 * fx + m23 * fy + m33); x *= w; y *= w; } } return {x, y}; } -static std::string type_helper(VMatrix::MatrixType t) -{ - switch (t) { - case VMatrix::MatrixType::None: - return "MatrixType::None"; - break; - case VMatrix::MatrixType::Translate: - return "MatrixType::Translate"; - break; - case VMatrix::MatrixType::Scale: - return "MatrixType::Scale"; - break; - case VMatrix::MatrixType::Rotate: - return "MatrixType::Rotate"; - break; - case VMatrix::MatrixType::Shear: - return "MatrixType::Shear"; - break; - case VMatrix::MatrixType::Project: - return "MatrixType::Project"; - break; - } - return ""; -} -std::ostream &operator<<(std::ostream &os, const VMatrix &o) -{ - os << "[Matrix: " - << "type =" << type_helper(o.type()) << ", Data : " << o.m11 << " " - << o.m12 << " " << o.m13 << " " << o.m21 << " " << o.m22 << " " << o.m23 - << " " << o.mtx << " " << o.mty << " " << o.m33 << " " - << "]" << std::endl; - return os; -} V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vmatrix.h b/AXrLottie/src/main/cpp/src/vector/vmatrix.h old mode 100755 new mode 100644 index f762343..941e16e --- a/AXrLottie/src/main/cpp/src/vector/vmatrix.h +++ b/AXrLottie/src/main/cpp/src/vector/vmatrix.h @@ -1,26 +1,30 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VMATRIX_H #define VMATRIX_H #include "vglobal.h" #include "vpoint.h" -#include "vregion.h" +#include "vrect.h" V_BEGIN_NAMESPACE @@ -58,9 +62,9 @@ class VMatrix { float m_ty() const { return mty;} float m_33() const { return m33;} - VMatrix &translate(VPointF pos) { return translate(pos.x(), pos.y()); }; + VMatrix &translate(VPointF pos) { return translate(pos.x(), pos.y()); } VMatrix &translate(float dx, float dy); - VMatrix &scale(VPointF s) { return scale(s.x(), s.y()); }; + VMatrix &scale(VPointF s) { return scale(s.x(), s.y()); } VMatrix &scale(float sx, float sy); VMatrix &shear(float sh, float sv); VMatrix &rotate(float a, Axis axis = VMatrix::Axis::Z); @@ -69,7 +73,6 @@ class VMatrix { VPointF map(const VPointF &p) const; inline VPointF map(float x, float y) const; VRect map(const VRect &r) const; - VRegion map(const VRegion &r) const; V_REQUIRED_RESULT VMatrix inverted(bool *invertible = nullptr) const; V_REQUIRED_RESULT VMatrix adjoint() const; @@ -81,8 +84,7 @@ class VMatrix { bool operator==(const VMatrix &) const; bool operator!=(const VMatrix &) const; bool fuzzyCompare(const VMatrix &) const; - friend std::ostream &operator<<(std::ostream &os, const VMatrix &o); - + float scale() const; private: friend struct VSpanData; float m11{1}, m12{0}, m13{0}; @@ -92,6 +94,18 @@ class VMatrix { mutable MatrixType dirty{MatrixType::None}; }; +inline float VMatrix::scale() const +{ + constexpr float SQRT_2 = 1.41421f; + VPointF p1(0, 0); + VPointF p2(SQRT_2, SQRT_2); + p1 = map(p1); + p2 = map(p2); + VPointF final = p2 - p1; + + return std::sqrt(final.x() * final.x() + final.y() * final.y()) / 2.0f; +} + inline VPointF VMatrix::map(float x, float y) const { return map(VPointF(x, y)); diff --git a/AXrLottie/src/main/cpp/src/vector/vpainter.cpp b/AXrLottie/src/main/cpp/src/vector/vpainter.cpp old mode 100755 new mode 100644 index cdcaa11..4ebbc5c --- a/AXrLottie/src/main/cpp/src/vector/vpainter.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vpainter.cpp @@ -1,44 +1,33 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vpainter.h" #include -#include "vdrawhelper.h" -V_BEGIN_NAMESPACE -class VPainterImpl { -public: - void drawRle(const VPoint &pos, const VRle &rle); - void drawRle(const VRle &rle, const VRle &clip); - void setCompositionMode(VPainter::CompositionMode mode) - { - mSpanData.mCompositionMode = mode; - } - void drawBitmapUntransform(const VRect &target, const VBitmap &bitmap, - const VRect &source, uint8_t const_alpha); +V_BEGIN_NAMESPACE -public: - VRasterBuffer mBuffer; - VSpanData mSpanData; -}; -void VPainterImpl::drawRle(const VPoint &, const VRle &rle) +void VPainter::drawRle(const VPoint &, const VRle &rle) { if (rle.empty()) return; // mSpanData.updateSpanFunc(); @@ -50,7 +39,7 @@ void VPainterImpl::drawRle(const VPoint &, const VRle &rle) &mSpanData); } -void VPainterImpl::drawRle(const VRle &rle, const VRle &clip) +void VPainter::drawRle(const VRle &rle, const VRle &clip) { if (rle.empty() || clip.empty()) return; @@ -61,12 +50,10 @@ void VPainterImpl::drawRle(const VRle &rle, const VRle &clip) static void fillRect(const VRect &r, VSpanData *data) { - int x1, x2, y1, y2; - - x1 = std::max(r.x(), 0); - x2 = std::min(r.x() + r.width(), data->mDrawableSize.width()); - y1 = std::max(r.y(), 0); - y2 = std::min(r.y() + r.height(), data->mDrawableSize.height()); + auto x1 = std::max(r.x(), 0); + auto x2 = std::min(r.x() + r.width(), data->mDrawableSize.width()); + auto y1 = std::max(r.y(), 0); + auto y2 = std::min(r.y() + r.height(), data->mDrawableSize.height()); if (x2 <= x1 || y2 <= y1) return; @@ -78,9 +65,9 @@ static void fillRect(const VRect &r, VSpanData *data) int n = std::min(nspans, y2 - y); int i = 0; while (i < n) { - spans[i].x = x1; - spans[i].len = x2 - x1; - spans[i].y = y + i; + spans[i].x = short(x1); + spans[i].len = ushort(x2 - x1); + spans[i].y = short(y + i); spans[i].coverage = 255; ++i; } @@ -90,74 +77,53 @@ static void fillRect(const VRect &r, VSpanData *data) } } -void VPainterImpl::drawBitmapUntransform(const VRect & target, +void VPainter::drawBitmapUntransform(const VRect & target, const VBitmap &bitmap, const VRect & source, uint8_t const_alpha) { - mSpanData.initTexture(&bitmap, const_alpha, VBitmapData::Plain, source); + mSpanData.initTexture(&bitmap, const_alpha, source); if (!mSpanData.mUnclippedBlendFunc) return; - mSpanData.dx = -target.x(); - mSpanData.dy = -target.y(); + mSpanData.dx = float(-target.x()); + mSpanData.dy = float(-target.y()); VRect rr = source.translated(target.x(), target.y()); fillRect(rr, &mSpanData); } -VPainter::~VPainter() -{ - delete mImpl; -} - -VPainter::VPainter() -{ - mImpl = new VPainterImpl; -} - VPainter::VPainter(VBitmap *buffer) { - mImpl = new VPainterImpl; begin(buffer); } bool VPainter::begin(VBitmap *buffer) { - mImpl->mBuffer.prepare(buffer); - mImpl->mSpanData.init(&mImpl->mBuffer); + mBuffer.prepare(buffer); + mSpanData.init(&mBuffer); // TODO find a better api to clear the surface - mImpl->mBuffer.clear(); + mBuffer.clear(); return true; } void VPainter::end() {} void VPainter::setDrawRegion(const VRect ®ion) { - mImpl->mSpanData.setDrawRegion(region); + mSpanData.setDrawRegion(region); } void VPainter::setBrush(const VBrush &brush) { - mImpl->mSpanData.setup(brush); -} - -void VPainter::setCompositionMode(CompositionMode mode) -{ - mImpl->setCompositionMode(mode); + mSpanData.setup(brush); } -void VPainter::drawRle(const VPoint &pos, const VRle &rle) -{ - mImpl->drawRle(pos, rle); -} - -void VPainter::drawRle(const VRle &rle, const VRle &clip) +void VPainter::setBlendMode(BlendMode mode) { - mImpl->drawRle(rle, clip); + mSpanData.mBlendMode = mode; } VRect VPainter::clipBoundingRect() const { - return mImpl->mSpanData.clipRect(); + return mSpanData.clipRect(); } void VPainter::drawBitmap(const VPoint &point, const VBitmap &bitmap, @@ -165,7 +131,7 @@ void VPainter::drawBitmap(const VPoint &point, const VBitmap &bitmap, { if (!bitmap.valid()) return; - drawBitmap(VRect(point.x(), point.y(), bitmap.width(), bitmap.height()), + drawBitmap(VRect(point, bitmap.size()), bitmap, source, const_alpha); } @@ -178,7 +144,7 @@ void VPainter::drawBitmap(const VRect &target, const VBitmap &bitmap, setBrush(VBrush()); if (target.size() == source.size()) { - mImpl->drawBitmapUntransform(target, bitmap, source, const_alpha); + drawBitmapUntransform(target, bitmap, source, const_alpha); } else { // @TODO scaling } @@ -189,8 +155,8 @@ void VPainter::drawBitmap(const VPoint &point, const VBitmap &bitmap, { if (!bitmap.valid()) return; - drawBitmap(VRect(point.x(), point.y(), bitmap.width(), bitmap.height()), - bitmap, VRect(0, 0, bitmap.width(), bitmap.height()), + drawBitmap(VRect(point, bitmap.size()), + bitmap, bitmap.rect(), const_alpha); } @@ -199,7 +165,7 @@ void VPainter::drawBitmap(const VRect &rect, const VBitmap &bitmap, { if (!bitmap.valid()) return; - drawBitmap(rect, bitmap, VRect(0, 0, bitmap.width(), bitmap.height()), + drawBitmap(rect, bitmap, bitmap.rect(), const_alpha); } diff --git a/AXrLottie/src/main/cpp/src/vector/vpainter.h b/AXrLottie/src/main/cpp/src/vector/vpainter.h old mode 100755 new mode 100644 index 2d52337..68abd70 --- a/AXrLottie/src/main/cpp/src/vector/vpainter.h +++ b/AXrLottie/src/main/cpp/src/vector/vpainter.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VPAINTER_H @@ -22,27 +26,20 @@ #include "vbrush.h" #include "vpoint.h" #include "vrle.h" +#include "vdrawhelper.h" V_BEGIN_NAMESPACE class VBitmap; -class VPainterImpl; class VPainter { public: - enum CompositionMode { - CompModeSrc, - CompModeSrcOver, - CompModeDestIn, - CompModeDestOut - }; - ~VPainter(); - VPainter(); - VPainter(VBitmap *buffer); + VPainter() = default; + explicit VPainter(VBitmap *buffer); bool begin(VBitmap *buffer); void end(); void setDrawRegion(const VRect ®ion); // sub surface rendering area. void setBrush(const VBrush &brush); - void setCompositionMode(CompositionMode mode); + void setBlendMode(BlendMode mode); void drawRle(const VPoint &pos, const VRle &rle); void drawRle(const VRle &rle, const VRle &clip); VRect clipBoundingRect() const; @@ -52,7 +49,10 @@ class VPainter { void drawBitmap(const VPoint &point, const VBitmap &bitmap, uint8_t const_alpha = 255); void drawBitmap(const VRect &rect, const VBitmap &bitmap, uint8_t const_alpha = 255); private: - VPainterImpl *mImpl; + void drawBitmapUntransform(const VRect &target, const VBitmap &bitmap, + const VRect &source, uint8_t const_alpha); + VRasterBuffer mBuffer; + VSpanData mSpanData; }; V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vpath.cpp b/AXrLottie/src/main/cpp/src/vector/vpath.cpp old mode 100755 new mode 100644 index a82cbdf..d49cd00 --- a/AXrLottie/src/main/cpp/src/vector/vpath.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vpath.cpp @@ -1,21 +1,24 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - #include "vpath.h" #include #include @@ -144,7 +147,7 @@ void VPath::VPathData::reserve(size_t pts, size_t elms) static VPointF curvesForArc(const VRectF &, float, float, VPointF *, size_t *); static constexpr float PATH_KAPPA = 0.5522847498f; -static constexpr float K_PI = float(M_PI); +static constexpr float K_PI = 3.141592f; void VPath::VPathData::arcTo(const VRectF &rect, float startAngle, float sweepLength, bool forceMoveTo) @@ -216,13 +219,13 @@ void VPath::VPathData::addOval(const VRectF &rect, VPath::Direction dir) void VPath::VPathData::addRect(const VRectF &rect, VPath::Direction dir) { - if (rect.empty()) return; - float x = rect.x(); float y = rect.y(); float w = rect.width(); float h = rect.height(); + if (vCompare(w, 0.f) && vCompare(h, 0.f)) return; + reserve(5, 6); // 1Move + 4Line + 1Close if (dir == VPath::Direction::CW) { moveTo(x + w, y); @@ -524,7 +527,7 @@ void VPath::VPathData::addPolystar(float points, float innerRadius, float partialPointAmount = points - floorf(points); bool longSegment = false; size_t numPoints = size_t(ceilf(points) * 2); - float angleDir = ((dir == VPath::Direction::CW) ? 1.0 : -1.0); + float angleDir = ((dir == VPath::Direction::CW) ? 1.0f : -1.0f); bool hasRoundness = false; innerRoundness /= 100.0f; @@ -625,7 +628,7 @@ void VPath::VPathData::addPolygon(float points, float radius, float roundness, float y; float anglePerPoint = 2.0f * K_PI / floorf(points); size_t numPoints = size_t(floorf(points)); - float angleDir = ((dir == VPath::Direction::CW) ? 1.0 : -1.0); + float angleDir = ((dir == VPath::Direction::CW) ? 1.0f : -1.0f); bool hasRoundness = false; roundness /= 100.0f; @@ -676,7 +679,7 @@ void VPath::VPathData::addPolygon(float points, float radius, float roundness, close(); } -void VPath::VPathData::addPath(const VPathData &path) +void VPath::VPathData::addPath(const VPathData &path, const VMatrix *m) { size_t segment = path.segments(); @@ -687,8 +690,15 @@ void VPath::VPathData::addPath(const VPathData &path) if (m_elements.capacity() < m_elements.size() + path.m_elements.size()) m_elements.reserve(m_elements.size() + path.m_elements.size()); - std::copy(path.m_points.begin(), path.m_points.end(), - back_inserter(m_points)); + if (m) { + for (const auto &i : path.m_points) { + m_points.push_back(m->map(i)); + } + } else { + std::copy(path.m_points.begin(), path.m_points.end(), + back_inserter(m_points)); + } + std::copy(path.m_elements.begin(), path.m_elements.end(), back_inserter(m_elements)); diff --git a/AXrLottie/src/main/cpp/src/vector/vpath.h b/AXrLottie/src/main/cpp/src/vector/vpath.h old mode 100755 new mode 100644 index 1c4bf0b..90c2c3e --- a/AXrLottie/src/main/cpp/src/vector/vpath.h +++ b/AXrLottie/src/main/cpp/src/vector/vpath.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VPATH_H @@ -63,13 +67,14 @@ class VPath { float startAngle, float cx, float cy, VPath::Direction dir = Direction::CW); void addPath(const VPath &path); + void addPath(const VPath &path, const VMatrix &m); void transform(const VMatrix &m); float length() const; const std::vector &elements() const; const std::vector & points() const; void clone(const VPath &srcPath); bool unique() const { return d.unique();} - int refCount() const { return d.refCount();} + size_t refCount() const { return d.refCount();} private: struct VPathData { @@ -98,7 +103,7 @@ class VPath { void addPolygon(float points, float radius, float roundness, float startAngle, float cx, float cy, VPath::Direction dir = Direction::CW); - void addPath(const VPathData &path); + void addPath(const VPathData &path, const VMatrix *m = nullptr); void clone(const VPath::VPathData &o) { *this = o;} const std::vector &elements() const { @@ -107,7 +112,7 @@ class VPath { const std::vector &points() const { return m_points; } std::vector m_points; std::vector m_elements; - unsigned int m_segments; + size_t m_segments; VPointF mStartPoint; mutable float mLength{0}; mutable bool mLengthDirty{true}; @@ -253,6 +258,13 @@ inline void VPath::addPath(const VPath &path) } } +inline void VPath::addPath(const VPath &path, const VMatrix &m) +{ + if (path.empty()) return; + + d.write().addPath(path.d.read(), &m); +} + inline const std::vector &VPath::elements() const { return d->elements(); diff --git a/AXrLottie/src/main/cpp/src/vector/vpathmesure.cpp b/AXrLottie/src/main/cpp/src/vector/vpathmesure.cpp old mode 100755 new mode 100644 index f0f305b..5d44987 --- a/AXrLottie/src/main/cpp/src/vector/vpathmesure.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vpathmesure.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vpathmesure.h" @@ -46,7 +50,8 @@ VPath VPathMesure::trim(const VPath &path) std::numeric_limits::max(), // 2nd segment }; VDasher dasher(array, 4); - return dasher.dashed(path); + dasher.dashed(path, mScratchObject); + return mScratchObject; } else { float array[4] = { length * mEnd, (mStart - mEnd) * length, // 1st segment @@ -54,7 +59,8 @@ VPath VPathMesure::trim(const VPath &path) std::numeric_limits::max(), // 2nd segment }; VDasher dasher(array, 4); - return dasher.dashed(path); + dasher.dashed(path, mScratchObject); + return mScratchObject; } } diff --git a/AXrLottie/src/main/cpp/src/vector/vpathmesure.h b/AXrLottie/src/main/cpp/src/vector/vpathmesure.h old mode 100755 new mode 100644 index de3e824..2a4adb9 --- a/AXrLottie/src/main/cpp/src/vector/vpathmesure.h +++ b/AXrLottie/src/main/cpp/src/vector/vpathmesure.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VPATHMESURE_H @@ -25,12 +29,14 @@ V_BEGIN_NAMESPACE class VPathMesure { public: + void setRange(float start, float end) {mStart = start; mEnd = end;} void setStart(float start){mStart = start;} void setEnd(float end){mEnd = end;} VPath trim(const VPath &path); private: float mStart{0.0f}; float mEnd{1.0f}; + VPath mScratchObject; }; V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vpoint.h b/AXrLottie/src/main/cpp/src/vector/vpoint.h old mode 100755 new mode 100644 index 1a84cb1..da1bb2f --- a/AXrLottie/src/main/cpp/src/vector/vpoint.h +++ b/AXrLottie/src/main/cpp/src/vector/vpoint.h @@ -1,21 +1,24 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - #ifndef VPOINT_H #define VPOINT_H @@ -44,10 +47,10 @@ class VPointF { inline friend VDebug & operator<<(VDebug &os, const VPointF &o); friend inline VPointF operator-(const VPointF &p1, const VPointF &p2); - friend inline const VPointF operator*(const VPointF &, float val); - friend inline const VPointF operator*(float val, const VPointF &); - friend inline const VPointF operator/(const VPointF &, float val); - friend inline const VPointF operator/(float val, const VPointF &); + friend inline const VPointF operator*(const VPointF &, float); + friend inline const VPointF operator*(float, const VPointF &); + friend inline const VPointF operator/(const VPointF &, float); + friend inline const VPointF operator/(float, const VPointF &); private: float mx{0}; diff --git a/AXrLottie/src/main/cpp/src/vector/vraster.cpp b/AXrLottie/src/main/cpp/src/vector/vraster.cpp old mode 100755 new mode 100644 index 613312d..0624315 --- a/AXrLottie/src/main/cpp/src/vector/vraster.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vraster.cpp @@ -1,22 +1,26 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ - #include "vraster.h" +#include #include #include #include "config.h" @@ -71,7 +75,7 @@ struct FTOutline { SW_FT_Stroker_LineCap ftCap; SW_FT_Stroker_LineJoin ftJoin; SW_FT_Fixed ftWidth; - SW_FT_Fixed ftMeterLimit; + SW_FT_Fixed ftMiterLimit; dyn_array mPointMemory{100}; dyn_array mTagMemory{100}; dyn_array mContourMemory{10}; @@ -102,9 +106,6 @@ void FTOutline::convert(const VPath &path) { const std::vector &elements = path.elements(); const std::vector & points = path.points(); - if (points.size() > SHRT_MAX) { - return; - } grow(points.size(), path.segments()); @@ -132,7 +133,7 @@ void FTOutline::convert(const VPath &path) } void FTOutline::convert(CapStyle cap, JoinStyle join, float width, - float meterLimit) + float miterLimit) { // map strokeWidth to freetype. It uses as the radius of the pen not the // diameter @@ -141,7 +142,7 @@ void FTOutline::convert(CapStyle cap, JoinStyle join, float width, // IMP: stroker takes radius in 26.6 co-ordinate ftWidth = SW_FT_Fixed(width * (1 << 6)); // IMP: stroker takes meterlimit in 16.16 co-ordinate - ftMeterLimit = SW_FT_Fixed(meterLimit * (1 << 16)); + ftMiterLimit = SW_FT_Fixed(miterLimit * (1 << 16)); // map to freetype capstyle switch (cap) { @@ -170,6 +171,8 @@ void FTOutline::convert(CapStyle cap, JoinStyle join, float width, void FTOutline::moveTo(const VPointF &pt) { + assert(ft.n_points <= SHRT_MAX - 1); + ft.points[ft.n_points].x = TO_FT_COORD(pt.x()); ft.points[ft.n_points].y = TO_FT_COORD(pt.y()); ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON; @@ -186,6 +189,8 @@ void FTOutline::moveTo(const VPointF &pt) void FTOutline::lineTo(const VPointF &pt) { + assert(ft.n_points <= SHRT_MAX - 1); + ft.points[ft.n_points].x = TO_FT_COORD(pt.x()); ft.points[ft.n_points].y = TO_FT_COORD(pt.y()); ft.tags[ft.n_points] = SW_FT_CURVE_TAG_ON; @@ -195,6 +200,8 @@ void FTOutline::lineTo(const VPointF &pt) void FTOutline::cubicTo(const VPointF &cp1, const VPointF &cp2, const VPointF ep) { + assert(ft.n_points <= SHRT_MAX - 3); + ft.points[ft.n_points].x = TO_FT_COORD(cp1.x()); ft.points[ft.n_points].y = TO_FT_COORD(cp1.y()); ft.tags[ft.n_points] = SW_FT_CURVE_TAG_CUBIC; @@ -212,6 +219,8 @@ void FTOutline::cubicTo(const VPointF &cp1, const VPointF &cp2, } void FTOutline::close() { + assert(ft.n_points <= SHRT_MAX - 1); + // mark the contour as a close path. ft.contours_flag[ft.n_contours] = 0; @@ -236,6 +245,8 @@ void FTOutline::close() void FTOutline::end() { + assert(ft.n_contours <= SHRT_MAX - 1); + if (ft.n_points) { ft.contours[ft.n_contours] = ft.n_points - 1; ft.n_contours++; @@ -267,18 +278,27 @@ class SharedRle { } _cv.notify_one(); } - VRle &get() + void wait() { - if (!_pending) return _rle; + if (!_pending) return; + + { + std::unique_lock lock(_mutex); + while (!_ready) _cv.wait(lock); + } - std::unique_lock lock(_mutex); - while (!_ready) _cv.wait(lock); _pending = false; + } + + VRle &get() + { + wait(); return _rle; } void reset() { + wait(); _ready = false; _pending = true; } @@ -295,7 +315,7 @@ struct VRleTask { SharedRle mRle; VPath mPath; float mStrokeWidth; - float mMeterLimit; + float mMiterLimit; VRect mClip; FillRule mFillRule; CapStyle mCap; @@ -314,14 +334,14 @@ struct VRleTask { } void update(VPath path, CapStyle cap, JoinStyle join, float width, - float meterLimit, const VRect &clip) + float miterLimit, const VRect &clip) { mRle.reset(); mPath = std::move(path); mCap = cap; mJoin = join; mStrokeWidth = width; - mMeterLimit = meterLimit; + mMiterLimit = miterLimit; mClip = clip; mGenerateStroke = true; } @@ -349,16 +369,21 @@ struct VRleTask { sw_ft_grays_raster.raster_render(nullptr, ¶ms); } - void update(FTOutline &outRef, SW_FT_Stroker &stroker) + void operator()(FTOutline &outRef, SW_FT_Stroker &stroker) { + if (mPath.points().size() > SHRT_MAX || + mPath.points().size() + mPath.segments() > SHRT_MAX) { + return; + } + if (mGenerateStroke) { // Stroke Task outRef.convert(mPath); - outRef.convert(mCap, mJoin, mStrokeWidth, mMeterLimit); + outRef.convert(mCap, mJoin, mStrokeWidth, mMiterLimit); uint points, contors; SW_FT_Stroker_Set(stroker, outRef.ftWidth, outRef.ftCap, - outRef.ftJoin, outRef.ftMeterLimit); + outRef.ftJoin, outRef.ftMiterLimit); SW_FT_Stroker_ParseOutline(stroker, &outRef.ft); SW_FT_Stroker_GetCounts(stroker, &points, &contors); @@ -388,19 +413,109 @@ struct VRleTask { } }; -struct VRasterizer::VRasterizerImpl { - VRleTask mTask; - FTOutline outlineRef; - SW_FT_Stroker stroker; +using VTask = std::shared_ptr; + +#ifdef LOTTIE_THREAD_SUPPORT - VRasterizerImpl() { +#include +#include "vtaskqueue.h" + +class RleTaskScheduler { + const unsigned _count{std::thread::hardware_concurrency()}; + std::vector _threads; + std::vector> _q{_count}; + std::atomic _index{0}; + + void run(unsigned i) + { + /* + * initalize per thread objects. + */ + FTOutline outlineRef; + SW_FT_Stroker stroker; SW_FT_Stroker_New(&stroker); - } - ~VRasterizerImpl() { + // Task Loop + VTask task; + while (true) { + bool success = false; + + for (unsigned n = 0; n != _count * 2; ++n) { + if (_q[(i + n) % _count].try_pop(task)) { + success = true; + break; + } + } + + if (!success && !_q[i].pop(task)) break; + + (*task)(outlineRef, stroker); + } + + // cleanup SW_FT_Stroker_Done(stroker); } + RleTaskScheduler() + { + for (unsigned n = 0; n != _count; ++n) { + _threads.emplace_back([&, n] { run(n); }); + } + } + +public: + static RleTaskScheduler &instance() + { + static RleTaskScheduler singleton; + return singleton; + } + + ~RleTaskScheduler() + { + for (auto &e : _q) e.done(); + + for (auto &e : _threads) e.join(); + } + + void process(VTask task) + { + auto i = _index++; + + for (unsigned n = 0; n != _count; ++n) { + if (_q[(i + n) % _count].try_push(std::move(task))) return; + } + + if (_count > 0) { + _q[i % _count].push(std::move(task)); + } + } +}; + +#else + +class RleTaskScheduler { +public: + FTOutline outlineRef{}; + SW_FT_Stroker stroker; + +public: + static RleTaskScheduler &instance() + { + static RleTaskScheduler singleton; + return singleton; + } + + RleTaskScheduler() { SW_FT_Stroker_New(&stroker); } + + ~RleTaskScheduler() { SW_FT_Stroker_Done(stroker); } + + void process(VTask task) { (*task)(outlineRef, stroker); } +}; +#endif + +struct VRasterizer::VRasterizerImpl { + VRleTask mTask; + VRle & rle() { return mTask.rle(); } VRleTask &task() { return mTask; } }; @@ -418,7 +533,8 @@ void VRasterizer::init() void VRasterizer::updateRequest() { - d->task().update(d->outlineRef, d->stroker); + VTask taskObj = VTask(d, &d->task()); + RleTaskScheduler::instance().process(std::move(taskObj)); } void VRasterizer::rasterize(VPath path, FillRule fillRule, const VRect &clip) @@ -433,14 +549,14 @@ void VRasterizer::rasterize(VPath path, FillRule fillRule, const VRect &clip) } void VRasterizer::rasterize(VPath path, CapStyle cap, JoinStyle join, - float width, float meterLimit, const VRect &clip) + float width, float miterLimit, const VRect &clip) { init(); if (path.empty() || vIsZero(width)) { d->rle().reset(); return; } - d->task().update(std::move(path), cap, join, width, meterLimit, clip); + d->task().update(std::move(path), cap, join, width, miterLimit, clip); updateRequest(); } diff --git a/AXrLottie/src/main/cpp/src/vector/vraster.h b/AXrLottie/src/main/cpp/src/vector/vraster.h old mode 100755 new mode 100644 index 987f9ad..fec8413 --- a/AXrLottie/src/main/cpp/src/vector/vraster.h +++ b/AXrLottie/src/main/cpp/src/vector/vraster.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VRASTER_H @@ -32,7 +36,7 @@ class VRasterizer public: void rasterize(VPath path, FillRule fillRule = FillRule::Winding, const VRect &clip = VRect()); void rasterize(VPath path, CapStyle cap, JoinStyle join, float width, - float meterLimit, const VRect &clip = VRect()); + float miterLimit, const VRect &clip = VRect()); VRle rle(); private: struct VRasterizerImpl; diff --git a/AXrLottie/src/main/cpp/src/vector/vrect.cpp b/AXrLottie/src/main/cpp/src/vector/vrect.cpp old mode 100755 new mode 100644 index bc5b008..ff219c6 --- a/AXrLottie/src/main/cpp/src/vector/vrect.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vrect.cpp @@ -1,19 +1,23 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vrect.h" diff --git a/AXrLottie/src/main/cpp/src/vector/vrect.h b/AXrLottie/src/main/cpp/src/vector/vrect.h old mode 100755 new mode 100644 index 494579b..f1c673e --- a/AXrLottie/src/main/cpp/src/vector/vrect.h +++ b/AXrLottie/src/main/cpp/src/vector/vrect.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VRECT_H @@ -28,7 +32,8 @@ class VRect { public: VRect() = default; VRect(int x, int y, int w, int h):x1(x),y1(y),x2(x+w),y2(y+h){} - explicit VRect(const VRectF &r); + explicit VRect(VPoint pt, VSize sz):VRect(pt.x(), pt.y(), sz.width(), sz.height()){} + operator VRectF() const; V_CONSTEXPR bool empty() const {return x1 >= x2 || y1 >= y2;} V_CONSTEXPR int left() const {return x1;} V_CONSTEXPR int top() const {return y1;} @@ -107,23 +112,21 @@ inline void VRect::translate(int dx, int dy) inline bool VRect::contains(const VRect &r, bool proper) const { - if (!proper) { - if ((x1 <= r.x1) && (x2 >= r.x2) && (y1 <= r.y1) && (y2 >= r.y2)) - return true; - return false; - } else { - if ((x1 < r.x1) && (x2 > r.x2) && (y1 < r.y1) && (y2 > r.y2)) - return true; - return false; - } + return proper ? + ((x1 < r.x1) && (x2 > r.x2) && (y1 < r.y1) && (y2 > r.y2)) : + ((x1 <= r.x1) && (x2 >= r.x2) && (y1 <= r.y1) && (y2 >= r.y2)); } class VRectF { public: VRectF() = default; - VRectF(float x, float y, float w, float h):x1(x),y1(y),x2(x+w),y2(y+h){} - explicit VRectF(const VRect &r):x1(r.left()),y1(r.top()), - x2(r.right()),y2(r.bottom()){} + + VRectF(double x, double y, double w, double h): + x1(float(x)),y1(float(y)), + x2(float(x+w)),y2(float(y+h)){} + operator VRect() const { + return {int(left()), int(right()), int(width()), int(height())}; + } V_CONSTEXPR bool empty() const {return x1 >= x2 || y1 >= y2;} V_CONSTEXPR float left() const {return x1;} @@ -159,8 +162,11 @@ class VRectF { float y2{0}; }; -inline VRect::VRect(const VRectF &r):x1(r.left()),y1(r.top()), - x2(r.right()),y2(r.bottom()){} +inline VRect::operator VRectF() const +{ + return {double(left()), double(right()), double(width()), double(height())}; +} + V_END_NAMESPACE #endif // VRECT_H diff --git a/AXrLottie/src/main/cpp/src/vector/vrle.cpp b/AXrLottie/src/main/cpp/src/vector/vrle.cpp old mode 100755 new mode 100644 index 9fad3ba..379f8ed --- a/AXrLottie/src/main/cpp/src/vector/vrle.cpp +++ b/AXrLottie/src/main/cpp/src/vector/vrle.cpp @@ -1,19 +1,24 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #include "vrle.h" @@ -21,59 +26,53 @@ #include #include #include +#include +#include #include #include "vdebug.h" #include "vglobal.h" -#include "vregion.h" V_BEGIN_NAMESPACE -enum class Operation { Add, Xor }; - -struct VRleHelper { - size_t alloc; - size_t size; - VRle::Span *spans; -}; -static void rleIntersectWithRle(VRleHelper *, int, int, VRleHelper *, - VRleHelper *); -static void rleIntersectWithRect(const VRect &, VRleHelper *, VRleHelper *); -static void rleOpGeneric(VRleHelper *, VRleHelper *, VRleHelper *, - Operation op); -static void rleSubstractWithRle(VRleHelper *, VRleHelper *, VRleHelper *); +using Result = std::array; +using rle_view = VRle::View; +static size_t _opGeneric(rle_view &a, rle_view &b, Result &result, + VRle::Data::Op op); +static size_t _opIntersect(const VRect &, rle_view &, Result &); +static size_t _opIntersect(rle_view &, rle_view &, Result &); static inline uchar divBy255(int x) { return (x + (x >> 8) + 0x80) >> 8; } -inline static void copyArrayToVector(const VRle::Span *span, size_t count, - std::vector &v) +inline static void copy(const VRle::Span *span, size_t count, + std::vector &v) { // make sure enough memory available if (v.capacity() < v.size() + count) v.reserve(v.size() + count); std::copy(span, span + count, back_inserter(v)); } -void VRle::VRleData::addSpan(const VRle::Span *span, size_t count) +void VRle::Data::addSpan(const VRle::Span *span, size_t count) { - copyArrayToVector(span, count, mSpans); + copy(span, count, mSpans); mBboxDirty = true; } -VRect VRle::VRleData::bbox() const +VRect VRle::Data::bbox() const { updateBbox(); return mBbox; } -void VRle::VRleData::setBbox(const VRect &bbox) const +void VRle::Data::setBbox(const VRect &bbox) const { mBboxDirty = false; mBbox = bbox; } -void VRle::VRleData::reset() +void VRle::Data::reset() { mSpans.clear(); mBbox = VRect(); @@ -81,12 +80,12 @@ void VRle::VRleData::reset() mBboxDirty = false; } -void VRle::VRleData::clone(const VRle::VRleData &o) +void VRle::Data::clone(const VRle::Data &o) { *this = o; } -void VRle::VRleData::translate(const VPoint &p) +void VRle::Data::translate(const VPoint &p) { // take care of last offset if applied mOffset = p - mOffset; @@ -100,7 +99,7 @@ void VRle::VRleData::translate(const VPoint &p) mBbox.translate(mOffset.x(), mOffset.y()); } -void VRle::VRleData::addRect(const VRect &rect) +void VRle::Data::addRect(const VRect &rect) { int x = rect.left(); int y = rect.top(); @@ -117,10 +116,10 @@ void VRle::VRleData::addRect(const VRect &rect) span.coverage = 255; mSpans.push_back(span); } - updateBbox(); + mBbox = rect; } -void VRle::VRleData::updateBbox() const +void VRle::Data::updateBbox() const { if (!mBboxDirty) return; @@ -143,23 +142,15 @@ void VRle::VRleData::updateBbox() const } } -void VRle::VRleData::invert() +void VRle::Data::operator*=(uchar alpha) { - for (auto &i : mSpans) { - i.coverage = 255 - i.coverage; - } -} - -void VRle::VRleData::operator*=(int alpha) -{ - alpha &= 0xff; for (auto &i : mSpans) { i.coverage = divBy255(i.coverage * alpha); } } -void VRle::VRleData::opIntersect(const VRect &r, VRle::VRleSpanCb cb, - void *userData) const +void VRle::Data::opIntersect(const VRect &r, VRle::VRleSpanCb cb, + void *userData) const { if (empty()) return; @@ -168,206 +159,162 @@ void VRle::VRleData::opIntersect(const VRect &r, VRle::VRleSpanCb cb, return; } - VRect clip = r; - VRleHelper tresult, tmp_obj; - std::array array; - - // setup the tresult object - tresult.size = array.size(); - tresult.alloc = array.size(); - tresult.spans = array.data(); - - // setup tmp object - tmp_obj.size = mSpans.size(); - tmp_obj.spans = const_cast(mSpans.data()); - + auto obj = view(); + Result result; // run till all the spans are processed - while (tmp_obj.size) { - rleIntersectWithRect(clip, &tmp_obj, &tresult); - if (tresult.size) { - cb(tresult.size, tresult.spans, userData); - } - tresult.size = 0; + while (obj.size()) { + auto count = _opIntersect(r, obj, result); + if (count) cb(count, result.data(), userData); } } // res = a - b; -void VRle::VRleData::opSubstract(const VRle::VRleData &a, - const VRle::VRleData &b) +void VRle::Data::opSubstract(const VRle::Data &aObj, const VRle::Data &bObj) { // if two rle are disjoint - if (!a.bbox().intersects(b.bbox())) { - mSpans = a.mSpans; + if (!aObj.bbox().intersects(bObj.bbox())) { + mSpans = aObj.mSpans; } else { - VRle::Span * aPtr = const_cast(a.mSpans.data()); - const VRle::Span *aEnd = a.mSpans.data() + a.mSpans.size(); - VRle::Span * bPtr = const_cast(b.mSpans.data()); - const VRle::Span *bEnd = b.mSpans.data() + b.mSpans.size(); - - // 1. forward till both y intersect - while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++; - size_t sizeA = size_t(aPtr - a.mSpans.data()); - if (sizeA) copyArrayToVector(a.mSpans.data(), sizeA, mSpans); + auto a = aObj.view(); + auto b = bObj.view(); - // 2. forward b till it intersect with a. - while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++; - size_t sizeB = size_t(bPtr - b.mSpans.data()); + auto aPtr = a.data(); + auto aEnd = a.data() + a.size(); + auto bPtr = b.data(); + auto bEnd = b.data() + b.size(); - // 2. calculate the intersect region - VRleHelper tresult, aObj, bObj; - std::array array; + // 1. forward a till it intersects with b + while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++; + auto count = aPtr - a.data(); + if (count) copy(a.data(), count, mSpans); - // setup the tresult object - tresult.size = array.size(); - tresult.alloc = array.size(); - tresult.spans = array.data(); + // 2. forward b till it intersects with a + if (aPtr != aEnd) + while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++; - // setup a object - aObj.size = a.mSpans.size() - sizeA; - aObj.spans = aPtr; + // update a and b object + a = {aPtr, size_t(aEnd - aPtr)}; + b = {bPtr, size_t(bEnd - bPtr)}; - // setup b object - bObj.size = b.mSpans.size() - sizeB; - bObj.spans = bPtr; + // 3. calculate the intersect region + Result result; // run till all the spans are processed - while (aObj.size && bObj.size) { - rleSubstractWithRle(&aObj, &bObj, &tresult); - if (tresult.size) { - copyArrayToVector(tresult.spans, tresult.size, mSpans); - } - tresult.size = 0; + while (a.size() && b.size()) { + auto count = _opGeneric(a, b, result, Op::Substract); + if (count) copy(result.data(), count, mSpans); } - // 3. copy the rest of a - if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans); + + // 4. copy the rest of a + if (a.size()) copy(a.data(), a.size(), mSpans); } mBboxDirty = true; } -void VRle::VRleData::opGeneric(const VRle::VRleData &a, const VRle::VRleData &b, - OpCode code) +void VRle::Data::opGeneric(const VRle::Data &aObj, const VRle::Data &bObj, + Op op) { // This routine assumes, obj1(span_y) < obj2(span_y). + auto a = aObj.view(); + auto b = bObj.view(); + // reserve some space for the result vector. - mSpans.reserve(a.mSpans.size() + b.mSpans.size()); + mSpans.reserve(a.size() + b.size()); // if two rle are disjoint - if (!a.bbox().intersects(b.bbox())) { - if (a.mSpans[0].y < b.mSpans[0].y) { - copyArrayToVector(a.mSpans.data(), a.mSpans.size(), mSpans); - copyArrayToVector(b.mSpans.data(), b.mSpans.size(), mSpans); + if (!aObj.bbox().intersects(aObj.bbox())) { + if (a.data()[0].y < b.data()[0].y) { + copy(a.data(), a.size(), mSpans); + copy(b.data(), b.size(), mSpans); } else { - copyArrayToVector(b.mSpans.data(), b.mSpans.size(), mSpans); - copyArrayToVector(a.mSpans.data(), a.mSpans.size(), mSpans); + copy(b.data(), b.size(), mSpans); + copy(a.data(), a.size(), mSpans); } } else { - VRle::Span * aPtr = const_cast(a.mSpans.data()); - const VRle::Span *aEnd = a.mSpans.data() + a.mSpans.size(); - VRle::Span * bPtr = const_cast(b.mSpans.data()); - const VRle::Span *bEnd = b.mSpans.data() + b.mSpans.size(); + auto aPtr = a.data(); + auto aEnd = a.data() + a.size(); + auto bPtr = b.data(); + auto bEnd = b.data() + b.size(); // 1. forward a till it intersects with b while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++; - size_t sizeA = size_t(aPtr - a.mSpans.data()); - if (sizeA) copyArrayToVector(a.mSpans.data(), sizeA, mSpans); + + auto count = aPtr - a.data(); + if (count) copy(a.data(), count, mSpans); // 2. forward b till it intersects with a - while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++; - size_t sizeB = size_t(bPtr - b.mSpans.data()); - if (sizeB) copyArrayToVector(b.mSpans.data(), sizeB, mSpans); + if (aPtr != aEnd) + while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++; + + count = bPtr - b.data(); + if (count) copy(b.data(), count, mSpans); + + // update a and b object + a = {aPtr, size_t(aEnd - aPtr)}; + b = {bPtr, size_t(bEnd - bPtr)}; // 3. calculate the intersect region - VRleHelper tresult, aObj, bObj; - std::array array; - - // setup the tresult object - tresult.size = array.size(); - tresult.alloc = array.size(); - tresult.spans = array.data(); - - // setup a object - aObj.size = a.mSpans.size() - sizeA; - aObj.spans = aPtr; - - // setup b object - bObj.size = b.mSpans.size() - sizeB; - bObj.spans = bPtr; - - Operation op = Operation::Add; - switch (code) { - case OpCode::Add: - op = Operation::Add; - break; - case OpCode::Xor: - op = Operation::Xor; - break; - } + Result result; + // run till all the spans are processed - while (aObj.size && bObj.size) { - rleOpGeneric(&aObj, &bObj, &tresult, op); - if (tresult.size) { - copyArrayToVector(tresult.spans, tresult.size, mSpans); - } - tresult.size = 0; + while (a.size() && b.size()) { + auto count = _opGeneric(a, b, result, op); + if (count) copy(result.data(), count, mSpans); } // 3. copy the rest - if (bObj.size) copyArrayToVector(bObj.spans, bObj.size, mSpans); - if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans); + if (b.size()) copy(b.data(), b.size(), mSpans); + if (a.size()) copy(a.data(), a.size(), mSpans); } - // update result bounding box - VRegion reg(a.bbox()); - reg += b.bbox(); - mBbox = reg.boundingRect(); - mBboxDirty = false; -} - -static void rle_cb(size_t count, const VRle::Span *spans, void *userData) -{ - auto vector = static_cast *>(userData); - copyArrayToVector(spans, count, *vector); + mBboxDirty = true; } -void opIntersectHelper(const VRle::VRleData &obj1, const VRle::VRleData &obj2, - VRle::VRleSpanCb cb, void *userData) +static inline V_ALWAYS_INLINE void _opIntersectPrepare(VRle::View &a, + VRle::View &b) { - VRleHelper result, source, clip; - std::array array; - - // setup the tresult object - result.size = array.size(); - result.alloc = array.size(); - result.spans = array.data(); + auto aPtr = a.data(); + auto aEnd = a.data() + a.size(); + auto bPtr = b.data(); + auto bEnd = b.data() + b.size(); - // setup tmp object - source.size = obj1.mSpans.size(); - source.spans = const_cast(obj1.mSpans.data()); + // 1. advance a till it intersects with b + while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++; - // setup tmp clip object - clip.size = obj2.mSpans.size(); - clip.spans = const_cast(obj2.mSpans.data()); + // 2. advance b till it intersects with a + if (aPtr != aEnd) + while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++; - // run till all the spans are processed - while (source.size) { - rleIntersectWithRle(&clip, 0, 0, &source, &result); - if (result.size) { - cb(result.size, result.spans, userData); - } - result.size = 0; - } + // update a and b object + a = {aPtr, size_t(aEnd - aPtr)}; + b = {bPtr, size_t(bEnd - bPtr)}; } -void VRle::VRleData::opIntersect(const VRle::VRleData &obj1, - const VRle::VRleData &obj2) +void VRle::Data::opIntersect(VRle::View a, VRle::View b) { - opIntersectHelper(obj1, obj2, rle_cb, &mSpans); + _opIntersectPrepare(a, b); + Result result; + while (a.size()) { + auto count = _opIntersect(a, b, result); + if (count) copy(result.data(), count, mSpans); + } + updateBbox(); } -#define VMIN(a, b) ((a) < (b) ? (a) : (b)) -#define VMAX(a, b) ((a) > (b) ? (a) : (b)) +static void _opIntersect(rle_view a, rle_view b, VRle::VRleSpanCb cb, + void *userData) +{ + if (!cb) return; + + _opIntersectPrepare(a, b); + Result result; + while (a.size()) { + auto count = _opIntersect(a, b, result); + if (count) cb(count, result.data(), userData); + } +} /* * This function will clip a rle list with another rle object @@ -379,35 +326,34 @@ void VRle::VRleData::opIntersect(const VRle::VRleData &obj1, * that are yet to be processed as well as the tpm_clip object * with the unprocessed clip spans. */ -static void rleIntersectWithRle(VRleHelper *tmp_clip, int clip_offset_x, - int clip_offset_y, VRleHelper *tmp_obj, - VRleHelper *result) -{ - VRle::Span *out = result->spans; - int available = result->alloc; - VRle::Span *spans = tmp_obj->spans; - VRle::Span *end = tmp_obj->spans + tmp_obj->size; - VRle::Span *clipSpans = tmp_clip->spans; - VRle::Span *clipEnd = tmp_clip->spans + tmp_clip->size; - int sx1, sx2, cx1, cx2, x, len; + +static size_t _opIntersect(rle_view &obj, rle_view &clip, Result &result) +{ + auto out = result.data(); + auto available = result.max_size(); + auto spans = obj.data(); + auto end = obj.data() + obj.size(); + auto clipSpans = clip.data(); + auto clipEnd = clip.data() + clip.size(); + int sx1, sx2, cx1, cx2, x, len; while (available && spans < end) { if (clipSpans >= clipEnd) { spans = end; break; } - if ((clipSpans->y + clip_offset_y) > spans->y) { + if (clipSpans->y > spans->y) { ++spans; continue; } - if (spans->y != (clipSpans->y + clip_offset_y)) { + if (spans->y != clipSpans->y) { ++clipSpans; continue; } // assert(spans->y == (clipSpans->y + clip_offset_y)); sx1 = spans->x; sx2 = sx1 + spans->len; - cx1 = (clipSpans->x + clip_offset_x); + cx1 = clipSpans->x; cx2 = cx1 + clipSpans->len; if (cx1 < sx1 && cx2 < sx1) { @@ -434,16 +380,13 @@ static void rleIntersectWithRle(VRleHelper *tmp_clip, int clip_offset_x, } } - // update the span list that yet to be processed - tmp_obj->spans = spans; - tmp_obj->size = end - spans; + // update the obj view yet to be processed + obj = {spans, size_t(end - spans)}; - // update the clip list that yet to be processed - tmp_clip->spans = clipSpans; - tmp_clip->size = clipEnd - clipSpans; + // update the clip view yet to be processed + clip = {clipSpans, size_t(clipEnd - clipSpans)}; - // update the result - result->size = result->alloc - available; + return result.max_size() - available; } /* @@ -455,62 +398,55 @@ static void rleIntersectWithRle(VRleHelper *tmp_clip, int clip_offset_x, * it will stop and update the tmp_obj with the span list * that are yet to be processed */ -static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj, - VRleHelper *result) +static size_t _opIntersect(const VRect &clip, rle_view &obj, Result &result) { - VRle::Span *out = result->spans; - int available = result->alloc; - VRle::Span *spans = tmp_obj->spans; - VRle::Span *end = tmp_obj->spans + tmp_obj->size; - short minx, miny, maxx, maxy; - - minx = clip.left(); - miny = clip.top(); - maxx = clip.right() - 1; - maxy = clip.bottom() - 1; - - while (available && spans < end) { - if (spans->y > maxy) { - spans = end; // update spans so that we can breakout + auto out = result.data(); + auto available = result.max_size(); + auto ptr = obj.data(); + auto end = obj.data() + obj.size(); + + const auto minx = clip.left(); + const auto miny = clip.top(); + const auto maxx = clip.right() - 1; + const auto maxy = clip.bottom() - 1; + + while (available && ptr < end) { + const auto &span = *ptr; + if (span.y > maxy) { + ptr = end; // update spans so that we can breakout break; } - if (spans->y < miny || spans->x > maxx || - spans->x + spans->len <= minx) { - ++spans; + if (span.y < miny || span.x > maxx || span.x + span.len <= minx) { + ++ptr; continue; } - if (spans->x < minx) { - out->len = VMIN(spans->len - (minx - spans->x), maxx - minx + 1); + if (span.x < minx) { + out->len = std::min(span.len - (minx - span.x), maxx - minx + 1); out->x = minx; } else { - out->x = spans->x; - out->len = VMIN(spans->len, (maxx - spans->x + 1)); + out->x = span.x; + out->len = std::min(span.len, ushort(maxx - span.x + 1)); } if (out->len != 0) { - out->y = spans->y; - out->coverage = spans->coverage; + out->y = span.y; + out->coverage = span.coverage; ++out; --available; } - ++spans; + ++ptr; } // update the span list that yet to be processed - tmp_obj->spans = spans; - tmp_obj->size = end - spans; + obj = {ptr, size_t(end - ptr)}; - // update the result - result->size = result->alloc - available; + return result.max_size() - available; } -void blitXor(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) +static void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l >= len) { - return; - } uchar *ptr = buffer + x; while (l--) { int da = *ptr; @@ -522,14 +458,12 @@ void blitXor(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) } } -void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) +static void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, + int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l >= len) { - return; - } uchar *ptr = buffer + x; while (l--) { *ptr = divBy255((255 - spans->coverage) * (*ptr)); @@ -539,14 +473,12 @@ void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, int len, in } } -void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) +static void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, + int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l >= len) { - return; - } uchar *ptr = buffer + x; while (l--) { *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr)); @@ -556,14 +488,11 @@ void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int len, int offse } } -void blit(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) +void blitSrc(VRle::Span *spans, int count, uchar *buffer, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; - if (x + l > len) { - return; - } uchar *ptr = buffer + x; while (l--) { *ptr = std::max(spans->coverage, *ptr); @@ -573,16 +502,13 @@ void blit(VRle::Span *spans, int count, uchar *buffer, int len, int offsetX) } } -size_t bufferToRle(uchar *buffer, int len, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) { size_t count = 0; uchar value = buffer[0]; int curIndex = 0; - size = offsetX < 0 ? size + offsetX : size; - if (size > len) { - return count; - } + // size = offsetX < 0 ? size + offsetX : size; for (int i = 0; i < size; i++) { uchar curValue = buffer[0]; if (value != curValue) { @@ -609,137 +535,214 @@ size_t bufferToRle(uchar *buffer, int len, int size, int offsetX, int y, VRle::S return count; } -static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, - Operation op) +struct SpanMerger { + explicit SpanMerger(VRle::Data::Op op) + { + switch (op) { + case VRle::Data::Op::Add: + _blitter = &blitSrcOver; + break; + case VRle::Data::Op::Xor: + _blitter = &blitXor; + break; + case VRle::Data::Op::Substract: + _blitter = &blitDestinationOut; + break; + } + } + using blitter = void (*)(VRle::Span *, int, uchar *, int); + blitter _blitter; + std::array _result; + std::array _buffer; + VRle::Span * _aStart{nullptr}; + VRle::Span * _bStart{nullptr}; + + void revert(VRle::Span *&aPtr, VRle::Span *&bPtr) + { + aPtr = _aStart; + bPtr = _bStart; + } + VRle::Span *data() { return _result.data(); } + size_t merge(VRle::Span *&aPtr, const VRle::Span *aEnd, VRle::Span *&bPtr, + const VRle::Span *bEnd); +}; + +size_t SpanMerger::merge(VRle::Span *&aPtr, const VRle::Span *aEnd, + VRle::Span *&bPtr, const VRle::Span *bEnd) { - std::array temp; - VRle::Span * out = result->spans; - size_t available = result->alloc; - VRle::Span * aPtr = a->spans; - VRle::Span * aEnd = a->spans + a->size; - VRle::Span * bPtr = b->spans; - VRle::Span * bEnd = b->spans + b->size; + assert(aPtr->y == bPtr->y); - while (available && aPtr < aEnd && bPtr < bEnd) { - if (aPtr->y < bPtr->y) { - *out++ = *aPtr++; - available--; - } else if (bPtr->y < aPtr->y) { - *out++ = *bPtr++; - available--; - } else { // same y - VRle::Span *aStart = aPtr; - VRle::Span *bStart = bPtr; - - int y = aPtr->y; - - while (aPtr < aEnd && aPtr->y == y) aPtr++; - while (bPtr < bEnd && bPtr->y == y) bPtr++; - - int aLength = (aPtr - 1)->x + (aPtr - 1)->len; - int bLength = (bPtr - 1)->x + (bPtr - 1)->len; - int offset = std::min(aStart->x, bStart->x); - - std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), 1024, -offset); - if (op == Operation::Add) - blitSrcOver(bStart, (bPtr - bStart), array.data(), 1024, -offset); - else if (op == Operation::Xor) - blitXor(bStart, (bPtr - bStart), array.data(), 1024, -offset); - VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), 1024, std::max(aLength, bLength), - offset, y, tResult); - if (available >= size) { - while (size--) { - *out++ = *tResult++; - available--; - } - } else { - aPtr = aStart; - bPtr = bStart; - break; - } - } + _aStart = aPtr; + _bStart = bPtr; + int lb = std::min(aPtr->x, bPtr->x); + int y = aPtr->y; + + while (aPtr < aEnd && aPtr->y == y) aPtr++; + while (bPtr < bEnd && bPtr->y == y) bPtr++; + + int ub = std::max((aPtr - 1)->x + (aPtr - 1)->len, + (bPtr - 1)->x + (bPtr - 1)->len); + int length = (lb < 0) ? ub + lb : ub - lb; + + if (length <= 0 || size_t(length) >= _buffer.max_size()) { + // can't handle merge . skip + return 0; } - // update the span list that yet to be processed - a->spans = aPtr; - a->size = aEnd - aPtr; - // update the clip list that yet to be processed - b->spans = bPtr; - b->size = bEnd - bPtr; + // clear buffer + memset(_buffer.data(), 0, length); + + // blit a to buffer + blitSrc(_aStart, aPtr - _aStart, _buffer.data(), -lb); - // update the result - result->size = result->alloc - available; + // blit b to buffer + _blitter(_bStart, bPtr - _bStart, _buffer.data(), -lb); + + // convert buffer to span + return bufferToRle(_buffer.data(), length, lb, y, _result.data()); } -static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b, - VRleHelper *result) +static size_t _opGeneric(rle_view &a, rle_view &b, Result &result, + VRle::Data::Op op) { - std::array temp; - VRle::Span * out = result->spans; - size_t available = result->alloc; - VRle::Span * aPtr = a->spans; - VRle::Span * aEnd = a->spans + a->size; - VRle::Span * bPtr = b->spans; - VRle::Span * bEnd = b->spans + b->size; + SpanMerger merger{op}; + + auto out = result.data(); + size_t available = result.max_size(); + auto aPtr = a.data(); + auto aEnd = a.data() + a.size(); + auto bPtr = b.data(); + auto bEnd = b.data() + b.size(); + + // only logic change for substract operation. + const bool keep = op != (VRle::Data::Op::Substract); while (available && aPtr < aEnd && bPtr < bEnd) { if (aPtr->y < bPtr->y) { *out++ = *aPtr++; available--; } else if (bPtr->y < aPtr->y) { + if (keep) { + *out++ = *bPtr; + available--; + } bPtr++; } else { // same y - VRle::Span *aStart = aPtr; - VRle::Span *bStart = bPtr; - - int y = aPtr->y; - - while (aPtr < aEnd && aPtr->y == y) aPtr++; - while (bPtr < bEnd && bPtr->y == y) bPtr++; - - int aLength = (aPtr - 1)->x + (aPtr - 1)->len; - int bLength = (bPtr - 1)->x + (bPtr - 1)->len; - int offset = std::min(aStart->x, bStart->x); - - std::array array = {{0}}; - blit(aStart, (aPtr - aStart), array.data(), 1024, -offset); - blitDestinationOut(bStart, (bPtr - bStart), array.data(), 1024, -offset); - VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), 1024, std::max(aLength, bLength), - offset, y, tResult); - if (available >= size) { - while (size--) { - *out++ = *tResult++; - available--; + auto count = merger.merge(aPtr, aEnd, bPtr, bEnd); + if (available >= count) { + if (count) { + memcpy(out, merger.data(), count * sizeof(VRle::Span)); + out += count; + available -= count; } } else { - aPtr = aStart; - bPtr = bStart; + // not enough space try next time. + merger.revert(aPtr, bPtr); break; } } } // update the span list that yet to be processed - a->spans = aPtr; - a->size = size_t(aEnd - aPtr); + a = {aPtr, size_t(aEnd - aPtr)}; + b = {bPtr, size_t(bEnd - bPtr)}; - // update the clip list that yet to be processed - b->spans = bPtr; - b->size = size_t(bEnd - bPtr); + return result.max_size() - available; +} - // update the result - result->size = result->alloc - available; +/* + * this api makes use of thread_local temporary + * buffer to avoid creating intermediate temporary rle buffer + * the scratch buffer object will grow its size on demand + * so that future call won't need any more memory allocation. + * this function is thread safe as it uses thread_local variable + * which is unique per thread. + */ +static vthread_local VRle::Data Scratch_Object; + +VRle VRle::opGeneric(const VRle &o, Data::Op op) const +{ + if (empty()) return o; + if (o.empty()) return *this; + + Scratch_Object.reset(); + Scratch_Object.opGeneric(d.read(), o.d.read(), op); + + VRle result; + result.d.write() = Scratch_Object; + + return result; } -VRle VRle::toRle(const VRect &rect) +VRle VRle::operator-(const VRle &o) const { - if (rect.empty()) return VRle(); + if (empty()) return {}; + if (o.empty()) return *this; + + Scratch_Object.reset(); + Scratch_Object.opSubstract(d.read(), o.d.read()); VRle result; - result.d.write().addRect(rect); + result.d.write() = Scratch_Object; + return result; } +VRle VRle::operator&(const VRle &o) const +{ + if (empty() || o.empty()) return {}; + + Scratch_Object.reset(); + Scratch_Object.opIntersect(d.read().view(), o.d.read().view()); + + VRle result; + result.d.write() = Scratch_Object; + + return result; +} + +void VRle::operator&=(const VRle &o) +{ + if (empty()) return; + if (o.empty()) { + reset(); + return; + } + Scratch_Object.reset(); + Scratch_Object.opIntersect(d.read().view(), o.d.read().view()); + d.write() = Scratch_Object; +} + +VRle operator-(const VRect &rect, const VRle &o) +{ + if (rect.empty()) return {}; + + Scratch_Object.reset(); + Scratch_Object.addRect(rect); + + VRle result; + result.d.write().opSubstract(Scratch_Object, o.d.read()); + + return result; +} + +VRle operator&(const VRect &rect, const VRle &o) +{ + if (rect.empty() || o.empty()) return {}; + + Scratch_Object.reset(); + Scratch_Object.addRect(rect); + + VRle result; + result.d.write().opIntersect(Scratch_Object.view(), o.d.read().view()); + + return result; +} + +void VRle::intersect(const VRle &clip, VRleSpanCb cb, void *userData) const +{ + if (empty() || clip.empty()) return; + + _opIntersect(d.read().view(), clip.d.read().view(), cb, userData); +} + V_END_NAMESPACE diff --git a/AXrLottie/src/main/cpp/src/vector/vrle.h b/AXrLottie/src/main/cpp/src/vector/vrle.h old mode 100755 new mode 100644 index b8d97db..761e5d1 --- a/AXrLottie/src/main/cpp/src/vector/vrle.h +++ b/AXrLottie/src/main/cpp/src/vector/vrle.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VRLE_H @@ -30,169 +34,88 @@ V_BEGIN_NAMESPACE class VRle { public: struct Span { - short x; - short y; - ushort len; - uchar coverage; + short x{0}; + short y{0}; + ushort len{0}; + uchar coverage{0}; }; - typedef void (*VRleSpanCb)(size_t count, const VRle::Span *spans, - void *userData); - bool empty() const; - VRect boundingRect() const; - void setBoundingRect(const VRect &bbox); - void addSpan(const VRle::Span *span, size_t count); + using VRleSpanCb = void (*)(size_t count, const VRle::Span *spans, + void *userData); + bool empty() const { return d->empty(); } + VRect boundingRect() const { return d->bbox(); } + void setBoundingRect(const VRect &bbox) { d->setBbox(bbox); } + void addSpan(const VRle::Span *span, size_t count) + { + d.write().addSpan(span, count); + } - void reset(); - void translate(const VPoint &p); - void invert(); + void reset() { d.write().reset(); } + void translate(const VPoint &p) { d.write().translate(p); } - void operator*=(int alpha); + void operator*=(uchar alpha) { d.write() *= alpha; } void intersect(const VRect &r, VRleSpanCb cb, void *userData) const; void intersect(const VRle &rle, VRleSpanCb cb, void *userData) const; + void operator&=(const VRle &o); VRle operator&(const VRle &o) const; VRle operator-(const VRle &o) const; - VRle operator+(const VRle &o) const; - VRle operator^(const VRle &o) const; + VRle operator+(const VRle &o) const { return opGeneric(o, Data::Op::Add); } + VRle operator^(const VRle &o) const { return opGeneric(o, Data::Op::Xor); } - static VRle toRle(const VRect &rect); + friend VRle operator-(const VRect &rect, const VRle &o); + friend VRle operator&(const VRect &rect, const VRle &o); - bool unique() const {return d.unique();} - int refCount() const { return d.refCount();} - void clone(const VRle &o); + bool unique() const { return d.unique(); } + size_t refCount() const { return d.refCount(); } + void clone(const VRle &o) { d.write().clone(o.d.read()); } -private: - struct VRleData { - enum class OpCode { - Add, - Xor - }; +public: + struct View { + Span * _data; + size_t _size; + View(const Span *data, size_t sz) : _data((Span *)data), _size(sz) {} + Span * data() { return _data; } + size_t size() { return _size; } + }; + struct Data { + enum class Op { Add, Xor, Substract }; + VRle::View view() const + { + return VRle::View(mSpans.data(), mSpans.size()); + } bool empty() const { return mSpans.empty(); } void addSpan(const VRle::Span *span, size_t count); void updateBbox() const; VRect bbox() const; - void setBbox(const VRect &bbox) const; + void setBbox(const VRect &bbox) const; void reset(); void translate(const VPoint &p); - void operator*=(int alpha); - void invert(); + void operator*=(uchar alpha); + void opGeneric(const VRle::Data &, const VRle::Data &, Op code); + void opSubstract(const VRle::Data &, const VRle::Data &); + void opIntersect(VRle::View a, VRle::View b); void opIntersect(const VRect &, VRle::VRleSpanCb, void *) const; - void opGeneric(const VRle::VRleData &, const VRle::VRleData &, OpCode code); - void opSubstract(const VRle::VRleData &, const VRle::VRleData &); - void opIntersect(const VRle::VRleData &, const VRle::VRleData &); void addRect(const VRect &rect); - void clone(const VRle::VRleData &); + void clone(const VRle::Data &); + std::vector mSpans; VPoint mOffset; mutable VRect mBbox; mutable bool mBboxDirty = true; }; - friend void opIntersectHelper(const VRle::VRleData &obj1, - const VRle::VRleData &obj2, - VRle::VRleSpanCb cb, void *userData); - vcow_ptr d; -}; - -inline bool VRle::empty() const -{ - return d->empty(); -} - -inline void VRle::addSpan(const VRle::Span *span, size_t count) -{ - d.write().addSpan(span, count); -} - -inline VRect VRle::boundingRect() const -{ - return d->bbox(); -} - -inline void VRle::setBoundingRect(const VRect & bbox) -{ - d->setBbox(bbox); -} - -inline void VRle::invert() -{ - d.write().invert(); -} - -inline void VRle::operator*=(int alpha) -{ - d.write() *= alpha; -} - -inline VRle VRle::operator&(const VRle &o) const -{ - if (empty() || o.empty()) return VRle(); - - VRle result; - result.d.write().opIntersect(d.read(), o.d.read()); - - return result; -} -inline VRle VRle::operator+(const VRle &o) const -{ - if (empty()) return o; - if (o.empty()) return *this; - - VRle result; - result.d.write().opGeneric(d.read(), o.d.read(), VRleData::OpCode::Add); - - return result; -} - -inline VRle VRle::operator^(const VRle &o) const -{ - if (empty()) return o; - if (o.empty()) return *this; - - VRle result; - result.d.write().opGeneric(d.read(), o.d.read(), VRleData::OpCode::Xor); - - return result; -} - -inline VRle VRle::operator-(const VRle &o) const -{ - if (empty()) return VRle(); - if (o.empty()) return *this; - - VRle result; - result.d.write().opSubstract(d.read(), o.d.read()); - - return result; -} - -inline void VRle::reset() -{ - d.write().reset(); -} - -inline void VRle::clone(const VRle &o) -{ - d.write().clone(o.d.read()); -} +private: + VRle opGeneric(const VRle &o, Data::Op opcode) const; -inline void VRle::translate(const VPoint &p) -{ - d.write().translate(p); -} + vcow_ptr d; +}; inline void VRle::intersect(const VRect &r, VRleSpanCb cb, void *userData) const { d->opIntersect(r, cb, userData); } -inline void VRle::intersect(const VRle &r, VRleSpanCb cb, void *userData) const -{ - if (empty() || r.empty()) return; - opIntersectHelper(d.read(), r.d.read(), cb, userData); -} - V_END_NAMESPACE #endif // VRLE_H diff --git a/AXrLottie/src/main/cpp/src/vector/vsharedptr.h b/AXrLottie/src/main/cpp/src/vector/vsharedptr.h old mode 100755 new mode 100644 diff --git a/AXrLottie/src/main/cpp/src/vector/vstackallocator.h b/AXrLottie/src/main/cpp/src/vector/vstackallocator.h old mode 100755 new mode 100644 index 5989133..a305b73 --- a/AXrLottie/src/main/cpp/src/vector/vstackallocator.h +++ b/AXrLottie/src/main/cpp/src/vector/vstackallocator.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VSTACK_ALLOCATOR_H diff --git a/AXrLottie/src/main/cpp/src/vector/vtaskqueue.h b/AXrLottie/src/main/cpp/src/vector/vtaskqueue.h old mode 100755 new mode 100644 index 62c0436..e505c2f --- a/AXrLottie/src/main/cpp/src/vector/vtaskqueue.h +++ b/AXrLottie/src/main/cpp/src/vector/vtaskqueue.h @@ -1,19 +1,23 @@ -/* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef VTASKQUEUE_H diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottie.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottie.java index 6040610..1e79cd3 100644 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottie.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottie.java @@ -31,7 +31,7 @@ /** * * @author Amir Hossein Aghajari - * @version 1.0.0 + * @version 1.0.2 * */ public class AXrLottie { @@ -51,6 +51,10 @@ public static void init(Context context){ loadScreenRefreshRate(context); } + public static void configureModelCacheSize(int cacheSize){ + AXrLottieNative.configureModelCacheSize(cacheSize); + } + public static void loadScreenRefreshRate(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); if (manager != null) { @@ -93,15 +97,6 @@ public static AXrLottieDrawable createFromPath(String path, int width, int heigh .build(); } - public static AXrLottieDrawable createFromPath(String path,int width,int height,boolean precache, boolean limitFps,int[] colorReplacement){ - return AXrLottieDrawable.fromPath(path) - .setSize(width,height) - .setCacheEnabled(precache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - public static AXrLottieDrawable createFromFile(File file,int width,int height,boolean precache, boolean limitFps){ return AXrLottieDrawable.fromFile(file) .setSize(width,height) @@ -110,15 +105,6 @@ public static AXrLottieDrawable createFromFile(File file,int width,int height,bo .build(); } - public static AXrLottieDrawable createFromFile(File file,int width,int height,boolean precache, boolean limitFps,int[] colorReplacement){ - return AXrLottieDrawable.fromFile(file) - .setSize(width,height) - .setCacheEnabled(precache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - public static AXrLottieDrawable createFromURL(String url,int width,int height,boolean precache, boolean limitFps){ return AXrLottieDrawable.fromURL(url) .setSize(width,height) @@ -127,21 +113,11 @@ public static AXrLottieDrawable createFromURL(String url,int width,int height,bo .build(); } - public static AXrLottieDrawable createFromURL(String url,int width,int height,boolean precache, boolean limitFps,int[] colorReplacement){ - return AXrLottieDrawable.fromURL(url) - .setSize(width,height) - .setCacheEnabled(precache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - - public static AXrLottieDrawable createFromURL(String url, AXrLottieNetworkFetcher fetcher, int width, int height, boolean precache, boolean limitFps, int[] colorReplacement){ + public static AXrLottieDrawable createFromURL(String url, AXrLottieNetworkFetcher fetcher, int width, int height, boolean precache, boolean limitFps){ return AXrLottieDrawable.fromURL(url,fetcher) .setSize(width,height) .setCacheEnabled(precache) .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) .build(); } @@ -161,25 +137,6 @@ public static AXrLottieDrawable createFromJson(String json, String name, int wid .build(); } - public static AXrLottieDrawable createFromJson(String json, String name, int width, int height,boolean startDecode, int[] colorReplacement) { - return AXrLottieDrawable.fromJson(json,name) - .setSize(width,height) - .setCacheEnabled(false) - .setFpsLimit(false) - .setAllowDecodeSingleFrame(startDecode) - .setColorReplacement(colorReplacement) - .build(); - } - - public static AXrLottieDrawable createFromJson(String json, String name, int width, int height,boolean cache,boolean limitFps, int[] colorReplacement) { - return AXrLottieDrawable.fromJson(json,name) - .setSize(width,height) - .setCacheEnabled(cache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - public static AXrLottieDrawable createFromAssets(Context context,String fileName, String name, int width, int height) { return AXrLottieDrawable.fromAssets(context,fileName) .setCacheName(name) @@ -198,24 +155,13 @@ public static AXrLottieDrawable createFromAssets(Context context,String fileName .build(); } - public static AXrLottieDrawable createFromAssets(Context context,String fileName, String name, int width, int height,boolean startDecode, int[] colorReplacement) { + public static AXrLottieDrawable createFromAssets(Context context,String fileName, String name, int width, int height,boolean startDecode) { return AXrLottieDrawable.fromAssets(context,fileName) .setCacheName(name) .setSize(width,height) .setCacheEnabled(false) .setFpsLimit(false) .setAllowDecodeSingleFrame(startDecode) - .setColorReplacement(colorReplacement) - .build(); - } - - public static AXrLottieDrawable createFromAssets(Context context,String fileName, String name, int width, int height,boolean cache,boolean limitFps, int[] colorReplacement) { - return AXrLottieDrawable.fromAssets(context,fileName) - .setCacheName(name) - .setSize(width,height) - .setCacheEnabled(cache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) .build(); } @@ -227,13 +173,12 @@ public static AXrLottieDrawable createFromRes(Context context,int res, String na .build(); } - public static AXrLottieDrawable createFromRes(Context context,int res, String name, int width, int height,boolean startDecode, int[] colorReplacement) { + public static AXrLottieDrawable createFromRes(Context context,int res, String name, int width, int height,boolean startDecode) { return AXrLottieDrawable.fromRes(context,res,name) .setSize(width,height) .setCacheEnabled(false) .setFpsLimit(false) .setAllowDecodeSingleFrame(startDecode) - .setColorReplacement(colorReplacement) .build(); } @@ -245,15 +190,6 @@ public static AXrLottieDrawable createFromRes(Context context,int res, String na .build(); } - public static AXrLottieDrawable createFromRes(Context context,int res, String name, int width, int height,boolean cache,boolean limitFps, int[] colorReplacement) { - return AXrLottieDrawable.fromRes(context,res,name) - .setSize(width,height) - .setCacheEnabled(cache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - public static AXrLottieDrawable createFromInputStream(InputStream inputStream, String name, int width, int height) { return AXrLottieDrawable.fromInputStream(inputStream,name) .setSize(width,height) @@ -262,13 +198,12 @@ public static AXrLottieDrawable createFromInputStream(InputStream inputStream, S .build(); } - public static AXrLottieDrawable createFromInputStream(InputStream inputStream, String name, int width, int height,boolean startDecode, int[] colorReplacement) { + public static AXrLottieDrawable createFromInputStream(InputStream inputStream, String name, int width, int height,boolean startDecode) { return AXrLottieDrawable.fromInputStream(inputStream,name) .setSize(width,height) .setCacheEnabled(false) .setFpsLimit(false) .setAllowDecodeSingleFrame(startDecode) - .setColorReplacement(colorReplacement) .build(); } @@ -280,13 +215,4 @@ public static AXrLottieDrawable createFromInputStream(InputStream inputStream, S .build(); } - public static AXrLottieDrawable createFromInputStream(InputStream inputStream, String name, int width, int height,boolean cache,boolean limitFps, int[] colorReplacement) { - return AXrLottieDrawable.fromInputStream(inputStream,name) - .setSize(width,height) - .setCacheEnabled(cache) - .setFpsLimit(limitFps) - .setColorReplacement(colorReplacement) - .build(); - } - } diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieDrawable.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieDrawable.java index 8ebd716..cfa09b6 100755 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieDrawable.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieDrawable.java @@ -58,8 +58,7 @@ public class AXrLottieDrawable extends BitmapDrawable implements Animatable { private int timeBetweenFrames; private int customEndFrame = -1; private boolean playInDirectionOfCustomEndFrame; - private int[] newReplaceColors; - private int[] pendingReplaceColors; + private ArrayList newPropertyUpdates = new ArrayList<>(); private volatile ArrayList pendingPropertyUpdates = new ArrayList<>(); @@ -253,10 +252,6 @@ public void run() { } } catch (Exception ignore) { } - if (pendingReplaceColors != null) { - AXrLottieNative.replaceColors(nativePtr, pendingReplaceColors); - pendingReplaceColors = null; - } try { long ptrToUse = nativePtr; @@ -332,10 +327,10 @@ public AXrLottieDrawable(Builder builder) { switch (builder.type) { case FILE: - initFromFile(builder.file, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps, builder.colorReplacement); + initFromFile(builder.file, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps); break; case JSON: - initFromJson(builder.json, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps, builder.startDecode, builder.colorReplacement); + initFromJson(builder.json, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps, builder.startDecode); break; case URL: this.width = builder.w; @@ -364,11 +359,11 @@ public AXrLottieDrawable(Builder builder) { start(); } - private void initFromJson(String json, String name, int width, int height, boolean cache, boolean limitFps, boolean startDecode, int[] colorReplacement) { + private void initFromJson(String json, String name, int width, int height, boolean cache, boolean limitFps, boolean startDecode) { if (cache) { File f = CacheWriter.load(json, name); if (f != null) { - initFromFile(f, name, width, height, true, limitFps, colorReplacement); + initFromFile(f, name, width, height, true, limitFps); return; } } @@ -379,7 +374,7 @@ private void initFromJson(String json, String name, int width, int height, boole shouldLimitFps = limitFps; this.cacheName = name; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); - nativePtr = createWithJson(json, name, metaData, colorReplacement); + nativePtr = createWithJson(json, name, metaData); timeBetweenFrames = Math.max(shouldLimitFps ? 33 : 16, (int) (1000.0f / metaData[1])); if (startDecode) { setAllowDecodeSingleFrame(true); @@ -387,14 +382,14 @@ private void initFromJson(String json, String name, int width, int height, boole lottieLoaded(); } - private void initFromFile(File file, String name, int width, int height, boolean precache, boolean limitFps, int[] colorReplacement) { + private void initFromFile(File file, String name, int width, int height, boolean precache, boolean limitFps) { this.width = width; this.height = height; shouldLimitFps = limitFps; this.cacheName = name; getPaint().setFlags(Paint.FILTER_BITMAP_FLAG); - nativePtr = create(file.getAbsolutePath(), width, height, metaData, precache, colorReplacement, shouldLimitFps); + nativePtr = create(file.getAbsolutePath(), width, height, metaData, precache, shouldLimitFps); if (precache && lottieCacheGenerateQueue == null) { lottieCacheGenerateQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); } @@ -587,19 +582,14 @@ public void commitApplyLayerProperties() { invalidateInternal(); } - public void replaceColors(int[] colors) { - newReplaceColors = colors; - requestRedraw(); - } - /** * Sets property value for the specified layer. layer can resolve * to multiple contents. In that case, the callback's value will apply to all of them. *

- * layer should contain object names separated by (.) and can handle globe(**) or wildchar(*). + * keyPath should contain object names separated by (.) and can handle globe(**) or wildchar(*). */ - public void setLayerProperty(String layerName, AXrLottieProperty property) { - newPropertyUpdates.add(new AXrLottieProperty.PropertyUpdate(property, layerName)); + public void setLayerProperty(String keyPath, AXrLottieProperty property) { + newPropertyUpdates.add(new AXrLottieProperty.PropertyUpdate(property, keyPath)); requestRedraw(); } @@ -631,10 +621,6 @@ private boolean scheduleNextGetFrame() { pendingPropertyUpdates.addAll(newPropertyUpdates); newPropertyUpdates.clear(); } - if (newReplaceColors != null) { - pendingReplaceColors = newReplaceColors; - newReplaceColors = null; - } loadFrameRunnableQueue.execute(loadFrameTask = loadFrameRunnable); return true; } @@ -886,10 +872,6 @@ public AXrLottieFrame getLottieFrameAt(int frame, int width, int height) { } catch (Exception ignore) { } - if (pendingReplaceColors != null) { - AXrLottieNative.replaceColors(nativePtr, pendingReplaceColors); - pendingReplaceColors = null; - } int result = getFrame(nativePtr, frame, backgroundBitmap, width, height, backgroundBitmap.getRowBytes()); cframe.loaded = (result != -1); @@ -900,14 +882,14 @@ public AXrLottieFrame getLottieFrameAt(int frame, int width, int height) { } /** - * @return Size of layers of the composition. + * @return composition layers count. */ public int getLayersCount() { return AXrLottieNative.getLayersCount(nativePtr); } /** - * Returns Layer information {name, inFrame, outFrame} of an specific layer of the composition. + * Returns Layer information {name, inFrame, outFrame, type} of an specific layer of the composition. * * @return Layer Information of the Composition. * @see AXrLottieLayerInfo @@ -917,7 +899,7 @@ public AXrLottieLayerInfo getLayerInfo(int index) { } /** - * Returns Layer information {name, inFrame, outFrame} of an specific layer of the composition. + * Returns Layer information {name, inFrame, outFrame, type} of an specific layer of the composition. * or null if layer doesn't exists * * @return Layer Information of the Composition. @@ -933,7 +915,7 @@ public AXrLottieLayerInfo getLayerInfo(String name) { } /** - * Returns Layer information {name, inFrame, outFrame} of all the child layers of the composition. + * Returns Layer information {name, inFrame, outFrame, type} of all the child layers of the composition. * * @return List of Layer Information of the Composition. * @see AXrLottieLayerInfo @@ -947,6 +929,47 @@ public List getLayers() { return layers; } + /** + * @return composition markers count. + */ + public int getMarkersCount() { + return AXrLottieNative.getMarkersCount(nativePtr); + } + + /** + * @return Composition Marker + * @see AXrLottieMarker + */ + public AXrLottieMarker getMarker(int index) { + return new AXrLottieMarker(AXrLottieNative.getMarkerData(nativePtr, index)); + } + + /** + * @return Composition Marker + * @see AXrLottieMarker + */ + public AXrLottieMarker getMarker(String marker) { + int max = getMarkersCount(); + for (int i = 0; i < max; i++) { + AXrLottieMarker info = getMarker(i); + if (info.getMarker().equals(marker)) return info; + } + return null; + } + + /** + * @return Composition Markers List + * @see AXrLottieMarker + */ + public List getMarkers() { + List markers = new ArrayList<>(); + int max = getMarkersCount(); + for (int i = 0; i < max; i++) { + markers.add(getMarker(i)); + } + return markers; + } + protected Bitmap render(Bitmap bitmap, int frame) { Bitmap r = null; if (render != null) r = render.renderFrame(this, bitmap, frame); @@ -962,7 +985,7 @@ protected void lottieLoaded() { } public void load(File file) { - initFromFile(file, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps, builder.colorReplacement); + initFromFile(file, builder.cacheName, builder.w, builder.h, builder.cache, builder.limitFps); uiHandler.post(new Runnable() { @Override public void run() { @@ -1092,7 +1115,6 @@ public static class Builder { private boolean cache = true; private boolean limitFps = false; private boolean startDecode = true; - private int[] colorReplacement = null; private List properties = null; private int customEndFrame = -1; private int autoRepeat = 0; @@ -1172,11 +1194,6 @@ public Builder setFpsLimit(boolean limitFps) { return this; } - public Builder setColorReplacement(int[] colorReplacement) { - this.colorReplacement = colorReplacement; - return this; - } - public Builder setAllowDecodeSingleFrame(boolean startDecode) { this.startDecode = startDecode; return this; @@ -1186,11 +1203,11 @@ public Builder setAllowDecodeSingleFrame(boolean startDecode) { * Sets property value for the specified layer. layer can resolve * to multiple contents. In that case, the callback's value will apply to all of them. *

- * layer should contain object names separated by (.) and can handle globe(**) or wildchar(*). + * keyPath should contain object names separated by (.) and can handle globe(**) or wildchar(*). */ - public Builder addLayerProperty(String layerName, AXrLottieProperty property) { + public Builder addLayerProperty(String keyPath, AXrLottieProperty property) { if (properties == null) properties = new ArrayList<>(); - properties.add(new AXrLottieProperty.PropertyUpdate(property, layerName)); + properties.add(new AXrLottieProperty.PropertyUpdate(property, keyPath)); return this; } diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieImageView.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieImageView.java index 95203c2..71e5947 100755 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieImageView.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieImageView.java @@ -60,12 +60,6 @@ public void setLayerProperty(String layer, AXrLottieProperty property) { } } - public void replaceColors(int[] colors) { - if (drawable != null) { - drawable.replaceColors(colors); - } - } - public boolean setLottieDrawable(AXrLottieDrawable lottieDrawable) { if (drawable != null && drawable.equals(lottieDrawable)) return false; setImageDrawable(lottieDrawable); diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieLayerInfo.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieLayerInfo.java index 19088d9..ea5639e 100644 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieLayerInfo.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieLayerInfo.java @@ -23,6 +23,27 @@ public class AXrLottieLayerInfo { private String name; private int inFrame; private int outFrame; + private LayerType type; + + public enum LayerType { + UNKNOWN(-1), + PRECOM(0), + SOLID (1), + IMAGE (2), + NULL (3), + SHAPE (4), + TEXT (5); + + private int type; + + LayerType(int type) { + this.type = type; + } + + public int getType() { + return this.type; + } + } AXrLottieLayerInfo(String[] data) { try { @@ -30,10 +51,16 @@ public class AXrLottieLayerInfo { name = data[0]; inFrame = Integer.parseInt(data[1]); outFrame = Integer.parseInt(data[2]); + + try { + type = LayerType.values()[Integer.parseInt(data[3])+1]; // +1 for skipping UNKNOWN + }catch (Exception ignore){ + } } - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception ignore) { } + + if (type == null) type = LayerType.UNKNOWN; } public int getInFrame() { @@ -48,10 +75,15 @@ public String getName() { return name; } + public LayerType getType() { + return type; + } + @Override public String toString() { return "AXrLottieLayerInfo{" + "name='" + name + '\'' + + ", type=" + type + ", inFrame=" + inFrame + ", outFrame=" + outFrame + '}'; @@ -66,15 +98,17 @@ public boolean equals(Object o) { if (inFrame != layerInfo.inFrame) return false; if (outFrame != layerInfo.outFrame) return false; + if (type != layerInfo.type) return false; if (name == null) return layerInfo.name == null; return name.equals(layerInfo.name); } @Override public int hashCode() { - int result = name != null ? name.hashCode() : 0; + int result = name.hashCode(); result = 31 * result + inFrame; result = 31 * result + outFrame; + result = 31 * result + type.hashCode(); return result; } } diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieMarker.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieMarker.java new file mode 100644 index 0000000..b79b5e3 --- /dev/null +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieMarker.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 - Amir Hossein Aghajari + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package com.aghajari.rlottie; + +/** + * Markers exported form AE are used to describe a segment of an animation {comment/tag , startFrame, endFrame} + * Marker can be use to divide a resource in to separate animations by tagging the segment with comment string , + * start frame and duration of that segment. + */ +public class AXrLottieMarker { + + private String marker; + private int inFrame; + private int outFrame; + + AXrLottieMarker(String[] data) { + try { + if (data != null) { + marker = data[0]; + inFrame = Integer.parseInt(data[1]); + outFrame = Integer.parseInt(data[2]); + } + } catch (Exception ignore) { + } + + } + + public int getInFrame() { + return inFrame; + } + + public int getOutFrame() { + return outFrame; + } + + public String getMarker() { + return marker; + } + + @Override + public String toString() { + return "AXrLottieMarker{" + + "marker='" + marker + '\'' + + ", inFrame=" + inFrame + + ", outFrame=" + outFrame + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AXrLottieMarker markerInfo = (AXrLottieMarker) o; + + if (inFrame != markerInfo.inFrame) return false; + if (outFrame != markerInfo.outFrame) return false; + if (marker == null) return markerInfo.marker == null; + return marker.equals(markerInfo.marker); + } + + @Override + public int hashCode() { + int result = marker.hashCode(); + result = 31 * result + inFrame; + result = 31 * result + outFrame; + return result; + } +} diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieNative.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieNative.java index 1f1a678..c5816e0 100644 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieNative.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieNative.java @@ -21,17 +21,20 @@ import android.graphics.Bitmap; class AXrLottieNative { - public static native long create(String src, int w, int h, int[] params, boolean precache, int[] colorReplacement, boolean limitFps); - public static native long createWithJson(String json, String name, int[] params, int[] colorReplacement); + public static native long create(String src, int w, int h, int[] params, boolean precache, boolean limitFps); + public static native long createWithJson(String json, String name, int[] params); public static native void destroy(long ptr); public static native int getFrame(long ptr, int frame, Bitmap bitmap, int w, int h, int stride); public static native void createCache(long ptr, int w, int h); + public static native int getMarkersCount(long ptr); + public static native String[] getMarkerData(long ptr,int index); + public static native int getLayersCount(long ptr); public static native String[] getLayerData(long ptr,int index); public static native void setLayerColor(long ptr, String layer, int color); - public static native void replaceColors(long ptr, int[] colorReplacement); + public static native void setLayerStrokeColor(long ptr, String layer, int color); public static native void setLayerFillOpacity(long ptr, String layer, float color); public static native void setLayerStrokeOpacity(long ptr, String layer, float value); @@ -43,4 +46,5 @@ class AXrLottieNative { public static native void setLayerTrScale(long ptr, String layer, float w,float h); public static native boolean lottie2gif(long ptr, Bitmap bitmap,int w, int h,int stride, int bgColor,boolean transparent, String gifPath,int delay, int bitDepth, boolean dither,int frameStart,int frameEnd, AXrLottie2Gif.Lottie2GifListener listener); + public static native void configureModelCacheSize(int cacheSize); } diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieProperty.java b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieProperty.java index ea08a35..3b1f0e6 100644 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieProperty.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/AXrLottieProperty.java @@ -23,8 +23,9 @@ public class AXrLottieProperty { PropertyType type; private enum PropertyType { - Color, + FillColor, FillOpacity, + StrokeColor, StrokeOpacity, StrokeWidth, TrAnchor, @@ -55,8 +56,8 @@ private enum PropertyType { } /* Color property of Fill object */ - public static AXrLottieProperty colorProperty(int color) { - return new AXrLottieProperty(PropertyType.Color, color); + public static AXrLottieProperty fillColorProperty(int color) { + return new AXrLottieProperty(PropertyType.FillColor, color); } /* Opacity property of Fill object, [ 0 .. 100] */ @@ -64,6 +65,11 @@ public static AXrLottieProperty fillOpacity(float value) { return new AXrLottieProperty(PropertyType.FillOpacity, value); } + /* Color property of Stroke object */ + public static AXrLottieProperty strokeColorProperty(int color) { + return new AXrLottieProperty(PropertyType.StrokeColor, color); + } + /* Opacity property of Stroke object, [ 0 .. 100] */ public static AXrLottieProperty strokeOpacity(float value) { return new AXrLottieProperty(PropertyType.StrokeOpacity, value); @@ -115,12 +121,15 @@ void apply(long ptr) { private static void apply(long ptr, String layer, AXrLottieProperty property) { switch (property.type) { - case Color: + case FillColor: AXrLottieNative.setLayerColor(ptr, layer, property.intValue); break; case FillOpacity: AXrLottieNative.setLayerFillOpacity(ptr, layer, property.floatValue); break; + case StrokeColor: + AXrLottieNative.setLayerStrokeColor(ptr, layer, property.intValue); + break; case StrokeOpacity: AXrLottieNative.setLayerStrokeOpacity(ptr, layer, property.floatValue); break; diff --git a/AXrLottie/src/main/java/com/aghajari/rlottie/DispatchQueue.java b/AXrLottie/src/main/java/com/aghajari/rlottie/DispatchQueue.java index 6420a2f..dfc0659 100755 --- a/AXrLottie/src/main/java/com/aghajari/rlottie/DispatchQueue.java +++ b/AXrLottie/src/main/java/com/aghajari/rlottie/DispatchQueue.java @@ -55,20 +55,6 @@ public DispatchQueue(final String threadName, boolean start) { start(); } } - - public void sendMessage(Message msg, int delay) { - try { - syncLatch.await(); - if (delay <= 0) { - handler.sendMessage(msg); - } else { - handler.sendMessageDelayed(msg, delay); - } - } catch (Exception ignore) { - - } - } - public void cancelRunnable(Runnable runnable) { try { syncLatch.await(); @@ -116,10 +102,6 @@ public void cleanupQueue() { } } - public void handleMessage(Message inputMessage) { - - } - public long getLastTaskTime() { return lastTaskTime; } @@ -131,12 +113,7 @@ public void recycle() { @Override public void run() { Looper.prepare(); - handler = new Handler() { - @Override - public void handleMessage(Message msg) { - DispatchQueue.this.handleMessage(msg); - } - }; + handler = new Handler(); syncLatch.countDown(); Looper.loop(); } diff --git a/app/build.gradle b/app/build.gradle index 931558c..7a56ea2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,6 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - implementation 'com.aghajari.emojiview:AXEmojiView:1.2.2' + implementation 'com.aghajari.emojiview:AXEmojiView:1.3.0' implementation project(':AXrLottie') } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0f48977..2be546e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,6 +25,7 @@ + { + + List list; + AXrLottieDrawable drawable; + + public void setAnimation(AXrLottieDrawable drawable){ + this.drawable = drawable; + list = drawable.getLayers(); + notifyDataSetChanged(); + + Log.i("AXrLottie","Layers : "); + for (AXrLottieLayerInfo layerInfo : list) { + Log.i("AXrLottie", layerInfo.toString()); + } + + // markers + Log.i("AXrLottie","Markers : "); + for (AXrLottieMarker marker : drawable.getMarkers()) { + Log.i("AXrLottie", marker.toString()); + } + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_layer_info,parent,false)); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + holder.onBind(drawable,list.get(position).getName()); + } + + @Override + public int getItemCount() { + return list!=null ? list.size() : 0; + } + + private class ViewHolder extends RecyclerView.ViewHolder{ + + TextView layerName; + AppCompatButton button; + + public ViewHolder(@NonNull View itemView) { + super(itemView); + + layerName = ((ViewGroup) itemView).findViewById(R.id.layer_name); + button = ((ViewGroup) itemView).findViewById(R.id.btn); + } + + public void onBind(final AXrLottieDrawable drawable,final String layer){ + layerName.setText(layer); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + drawable.setLayerProperty(layer+".**",AXrLottieProperty.fillColorProperty(findColor())); + } + }); + } + } + + Random rnd = new Random(); + + private int findColor() { + return Color.rgb(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/aghajari/sample/axrlottie/activity/SimpleActivity.java b/app/src/main/java/com/aghajari/sample/axrlottie/activity/SimpleActivity.java index 2b7f9e5..39307f9 100644 --- a/app/src/main/java/com/aghajari/sample/axrlottie/activity/SimpleActivity.java +++ b/app/src/main/java/com/aghajari/sample/axrlottie/activity/SimpleActivity.java @@ -2,7 +2,10 @@ import androidx.appcompat.app.AppCompatActivity; +import android.graphics.Color; import android.os.Bundle; + +import com.aghajari.rlottie.AXrLottieProperty; import com.aghajari.sample.axrlottie.R; import com.aghajari.rlottie.AXrLottie; @@ -18,9 +21,8 @@ protected void onCreate(Bundle savedInstanceState) { final AXrLottieImageView lottieView = findViewById(R.id.lottie_view); lottieView.setLottieDrawable(AXrLottie.createFromAssets(this, "emoji_simple.json", - "emoji", lottieView.getLayoutParams().width, lottieView.getLayoutParams().height)); - - lottieView.playAnimation(); + "emoji", 256, 256)); + lottieView.playAnimation(); } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml new file mode 100644 index 0000000..4b7a4b9 --- /dev/null +++ b/app/src/main/res/layout/activity_editor.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_emoji_view.xml b/app/src/main/res/layout/activity_emoji_view.xml index 973f352..318a3f8 100644 --- a/app/src/main/res/layout/activity_emoji_view.xml +++ b/app/src/main/res/layout/activity_emoji_view.xml @@ -1,33 +1,36 @@ - + tools:context=".activity.AXEmojiViewActivity" + android:orientation="vertical"> - + android:layout_height="0dp" + android:layout_weight="1" + android:layout_marginLeft="8dp" + android:layout_marginTop="8dp" + android:layout_marginRight="8dp" + android:layout_marginBottom="8dp" /> - + + android:layout_gravity="top" + android:background="@android:color/white"> - - + + - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 565a69d..d8ee268 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -20,6 +20,12 @@ android:onClick="colorLayerActivity" android:text="Color Layer Activity" /> + + + + + + + + + \ No newline at end of file diff --git a/deploy.settings b/deploy.settings index 7f57430..b100e36 100644 --- a/deploy.settings +++ b/deploy.settings @@ -1,6 +1,6 @@ siteUrl = https://github.com/Aghajari/AXrLottie gitUrl = https://github.com/Aghajari/AXrLottie.git -version = 1.0.0 +version = 1.0.2 groupId = com.aghajari.rlottie licenses = ['Apache-2.0'] id = AXrLottie