diff --git a/Lottie b/Lottie new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Lottie @@ -0,0 +1 @@ + diff --git a/inc/rlottie.h b/inc/rlottie.h index 1436539d..db81448d 100644 --- a/inc/rlottie.h +++ b/inc/rlottie.h @@ -43,6 +43,15 @@ struct LOTLayerNode; namespace rlottie { +enum class FitzModifier { + None, + Type12, + Type3, + Type4, + Type5, + Type6 +}; + /** * @brief Configures rlottie model cache policy. * @@ -293,7 +302,7 @@ class LOT_EXPORT Animation { loadFromData(std::string jsonData, const std::string &key, const std::string &resourcePath="", bool cachePolicy=true, const std::vector> - &colorReplacements = {}); + &colorReplacements = {}, FitzModifier fitzModifier = FitzModifier::None); /** * @brief Returns default framerate of the Lottie resource. diff --git a/src/lottie/lottieanimation.cpp b/src/lottie/lottieanimation.cpp index 58d1b13b..197d2597 100644 --- a/src/lottie/lottieanimation.cpp +++ b/src/lottie/lottieanimation.cpp @@ -242,7 +242,7 @@ std::unique_ptr Animation::loadFromData( std::string jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements) + &colorReplacements, FitzModifier fitzModifier) { if (jsonData.empty()) { vWarning << "jason data is empty"; @@ -252,7 +252,7 @@ std::unique_ptr Animation::loadFromData( LottieLoader loader; if (loader.loadFromData(std::move(jsonData), key, (resourcePath.empty() ? " " : resourcePath), - cachePolicy, colorReplacements)) { + cachePolicy, colorReplacements, fitzModifier)) { auto animation = std::unique_ptr(new Animation); animation->d->init(loader.model()); return animation; diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 09d14a4e..06e09cc7 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -92,6 +92,7 @@ void LOTCompItem::setValue(const std::string &keypath, LOTVariant &value) { LOTKeyPath key(keypath); mRootLayer->resolveKeyPath(key, 0, value); + mCurFrameNo = -1; } std::unique_ptr LOTCompItem::createLayerItem( @@ -518,6 +519,9 @@ LOTCompLayerItem::LOTCompLayerItem(LOTLayerData *layerModel) { // 1. create layer item for (auto &i : mLayerData->mChildren) { + if (i->type() != LOTData::Type::Layer) { + continue; + } auto model = static_cast(i.get()); auto item = LOTCompItem::createLayerItem(model); if (item) mLayers.push_back(std::move(item)); diff --git a/src/lottie/lottieloader.cpp b/src/lottie/lottieloader.cpp index 8c067808..c997e413 100644 --- a/src/lottie/lottieloader.cpp +++ b/src/lottie/lottieloader.cpp @@ -71,7 +71,7 @@ class LottieModelCache { std::unordered_map> mHash; std::mutex mMutex; - size_t mcacheSize{10}; + size_t mcacheSize{10000}; }; #else @@ -144,15 +144,16 @@ bool LottieLoader::loadFromData( std::string &&jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements) + &colorReplacements, rlottie::FitzModifier fitzModifier) { if (cachePolicy) { mModel = LottieModelCache::instance().find(key); - if (mModel) return true; + if (mModel) + return true; } LottieParser parser(const_cast(jsonData.c_str()), - resourcePath.c_str(), colorReplacements); + resourcePath.c_str(), colorReplacements, fitzModifier); mModel = parser.model(); if (!mModel) return false; diff --git a/src/lottie/lottieloader.h b/src/lottie/lottieloader.h index 711d0d64..48c1bc4d 100644 --- a/src/lottie/lottieloader.h +++ b/src/lottie/lottieloader.h @@ -23,6 +23,8 @@ #include #include +#include "rlottie.h" + class LOTModel; class LottieLoader { @@ -32,7 +34,7 @@ class LottieLoader bool loadFromData(std::string &&jsonData, const std::string &key, const std::string &resourcePath, bool cachePolicy, const std::vector> - &colorReplacements); + &colorReplacements, rlottie::FitzModifier fitzModifier); std::shared_ptr model(); private: std::shared_ptr mModel; diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index ab7e984a..bf0e3572 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -184,11 +184,17 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) LottieGradient gradData = mGradient.value(frameNo); auto size = gradData.mGradient.size(); float * ptr = gradData.mGradient.data(); + if (!ptr) { + return; + } int colorPoints = mColorPoints; - if (colorPoints == -1) { // for legacy bodymovin (ref: lottie-android) + if (colorPoints < 0 || colorPoints > size / 4) { // for legacy bodymovin (ref: lottie-android) colorPoints = int(size / 4); } auto opacityArraySize = size - colorPoints * 4; + if ((opacityArraySize % 2 != 0) || (colorPoints > opacityArraySize / 2 && opacityArraySize < 4)) { + opacityArraySize = 0; + } float *opacityPtr = ptr + (colorPoints * 4); stops.clear(); size_t j = 0; @@ -242,6 +248,9 @@ void LOTGradient::populate(VGradientStops &stops, int frameNo) } 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) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 4a5473d2..d263e467 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -225,11 +225,13 @@ class LOTAnimInfo { public: T value(int frameNo) const { + if (mKeyFrames.empty()) + return T(); + if (mKeyFrames.front().mStartFrame >= frameNo) return mKeyFrames.front().mValue.mStartValue; - if(mKeyFrames.back().mEndFrame <= frameNo) + if (mKeyFrames.back().mEndFrame <= frameNo) return mKeyFrames.back().mValue.mEndValue; - for(const auto &keyFrame : mKeyFrames) { if (frameNo >= keyFrame.mStartFrame && frameNo < keyFrame.mEndFrame) return keyFrame.value(frameNo); @@ -238,7 +240,8 @@ class LOTAnimInfo } float angle(int frameNo) const { - if ((mKeyFrames.front().mStartFrame >= frameNo) || + if (mKeyFrames.empty() || + (mKeyFrames.front().mStartFrame >= frameNo) || (mKeyFrames.back().mEndFrame <= frameNo) ) return 0; @@ -250,6 +253,9 @@ class LOTAnimInfo } bool changed(int prevFrame, int curFrame) const { + if (mKeyFrames.empty()) + return false; + auto first = mKeyFrames.front().mStartFrame; auto last = mKeyFrames.back().mEndFrame; diff --git a/src/lottie/lottieparser.cpp b/src/lottie/lottieparser.cpp index 1cc7febf..5dccf172 100644 --- a/src/lottie/lottieparser.cpp +++ b/src/lottie/lottieparser.cpp @@ -171,9 +171,10 @@ class LottieParserImpl : public LookaheadParserHandler { public: LottieParserImpl(char *str, const char *dir_path, const std::vector> - &colorReplacements) + &colorReplacements, rlottie::FitzModifier fitzModifier) : LookaheadParserHandler(str), mColorReplacements(colorReplacements), + mFitzModifier(fitzModifier), mDirPath(dir_path) { } @@ -259,7 +260,10 @@ class LottieParserImpl : public LookaheadParserHandler { void parseShapeKeyFrame(LOTAnimInfo &obj); void parseShapeProperty(LOTAnimatable &obj); void parseDashProperty(LOTDashProperty &dash); - + + void parseFitzColorReplacements(); + void parseFitzColorReplacement(); + std::shared_ptr interpolator(VPointF, VPointF, std::string); LottieColor toColor(const char *str); @@ -268,8 +272,9 @@ class LottieParserImpl : public LookaheadParserHandler { void resolveLayerRefs(); protected: - const std::vector> - &mColorReplacements; + std::vector> + mColorReplacements; + const rlottie::FitzModifier mFitzModifier; std::unordered_map> mInterpolatorCache; std::shared_ptr mComposition; @@ -313,7 +318,7 @@ bool LottieParserImpl::EnterObject() { if (st_ != kEnteringObject) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -325,7 +330,7 @@ bool LottieParserImpl::EnterArray() { if (st_ != kEnteringArray) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -355,7 +360,7 @@ const char *LottieParserImpl::NextObjectKey() } if (st_ != kExitingObject) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); st_ = kError; return nullptr; } @@ -379,7 +384,7 @@ bool LottieParserImpl::NextArrayValue() } if (st_ == kError || st_ == kHasKey) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); st_ = kError; return false; } @@ -391,7 +396,7 @@ int LottieParserImpl::GetInt() { if (st_ != kHasNumber || !v_.IsInt()) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return 0; } @@ -404,7 +409,7 @@ double LottieParserImpl::GetDouble() { if (st_ != kHasNumber) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return 0.; } @@ -417,7 +422,7 @@ bool LottieParserImpl::GetBool() { if (st_ != kHasBool) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return false; } @@ -440,7 +445,7 @@ const char *LottieParserImpl::GetString() { if (st_ != kHasString) { st_ = kError; - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return nullptr; } @@ -457,7 +462,7 @@ void LottieParserImpl::SkipOut(int depth) } else if (st_ == kExitingArray || st_ == kExitingObject) { --depth; } else if (st_ == kError) { - RAPIDJSON_ASSERT(false); + //RAPIDJSON_ASSERT(false); return; } @@ -590,6 +595,8 @@ void LottieParserImpl::parseComposition() parseAssets(comp); } else if (0 == strcmp(key, "layers")) { parseLayers(comp); + } else if (0 == strcmp(key, "fitz")) { + parseFitzColorReplacements(); } else { #ifdef DEBUG_PARSER vWarning << "Composition Attribute Skipped : " << key; @@ -624,6 +631,70 @@ void LottieParserImpl::parseAssets(LOTCompositionData *composition) // update the precomp layers with the actual layer object } +void LottieParserImpl::parseFitzColorReplacements() +{ + RAPIDJSON_ASSERT(PeekType() == kArrayType); + EnterArray(); + while (NextArrayValue()) { + parseFitzColorReplacement(); + } +} + +void LottieParserImpl::parseFitzColorReplacement() +{ + uint32_t original = 0; + uint32_t type12 = 0; + uint32_t type3 = 0; + uint32_t type4 = 0; + uint32_t type5 = 0; + uint32_t type6 = 0; + + EnterObject(); + while (const char *key = NextObjectKey()) { + if (0 == strcmp(key, "o")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + original = GetInt(); + } else if (0 == strcmp(key, "f12")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type12 = GetInt(); + } else if (0 == strcmp(key, "f3")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type3 = GetInt(); + } else if (0 == strcmp(key, "f4")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type4 = GetInt(); + } else if (0 == strcmp(key, "f5")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type5 = GetInt(); + } else if (0 == strcmp(key, "f6")) { + RAPIDJSON_ASSERT(PeekType() == kNumberType); + type6 = GetInt(); + } else { + Skip(key); + } + } + + switch (mFitzModifier) { + case rlottie::FitzModifier::None: + break; + case rlottie::FitzModifier::Type12: + mColorReplacements.push_back(std::pair(original, type12)); + break; + case rlottie::FitzModifier::Type3: + mColorReplacements.push_back(std::pair(original, type3)); + break; + case rlottie::FitzModifier::Type4: + mColorReplacements.push_back(std::pair(original, type4)); + break; + case rlottie::FitzModifier::Type5: + mColorReplacements.push_back(std::pair(original, type5)); + break; + case rlottie::FitzModifier::Type6: + mColorReplacements.push_back(std::pair(original, type6)); + break; + } +} + static constexpr const unsigned char B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -925,9 +996,10 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) } else if (0 == strcmp(key, "bm")) { layer->mBlendMode = getBlendMode(); } else if (0 == strcmp(key, "ks")) { - RAPIDJSON_ASSERT(PeekType() == kObjectType); - EnterObject(); - layer->mTransform = parseTransformObject(ddd); + if (PeekType() == kObjectType) { + EnterObject(); + layer->mTransform = parseTransformObject(ddd); + } } else if (0 == strcmp(key, "shapes")) { parseShapesAttr(layer); } else if (0 == strcmp(key, "w")) { @@ -981,7 +1053,7 @@ std::shared_ptr LottieParserImpl::parseLayer(bool record) staticFlag &= child.get()->isStatic(); } - if (layer->hasMask()) { + if (layer->hasMask() && layer->mExtra) { for (const auto &mask : layer->mExtra->mMasks) { staticFlag &= mask->isStatic(); } @@ -1135,7 +1207,8 @@ std::shared_ptr LottieParserImpl::parseGroupObject() RAPIDJSON_ASSERT(PeekType() == kObjectType); parseObject(group); } - if (group->mChildren.back()->mType == LOTData::Type::Transform) { + if (!group->mChildren.empty() + && group->mChildren.back()->mType == LOTData::Type::Transform) { group->mTransform = std::static_pointer_cast( group->mChildren.back()); group->mChildren.pop_back(); @@ -1456,10 +1529,19 @@ std::shared_ptr LottieParserImpl::parseTransformObject( } else if (0 == strcmp(key, "hd")) { sharedTransform->mHidden = GetBool(); } else if (0 == strcmp(key, "rx")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRx); } else if (0 == strcmp(key, "ry")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRy); } else if (0 == strcmp(key, "rz")) { + if (!obj->mExtra) { + return sharedTransform; + } parseProperty(obj->mExtra->m3DRz); } else { Skip(key); @@ -2291,8 +2373,8 @@ LottieParser::~LottieParser() = default; LottieParser::LottieParser( char *str, const char *dir_path, const std::vector> - &colorReplacements) - : d(std::make_unique(str, dir_path, colorReplacements)) + &colorReplacements, rlottie::FitzModifier fitzModifier) + : d(std::make_unique(str, dir_path, colorReplacements, fitzModifier)) { if (d->VerifyType()) d->parseComposition(); diff --git a/src/lottie/lottieparser.h b/src/lottie/lottieparser.h index 06165f97..3a20e4f9 100644 --- a/src/lottie/lottieparser.h +++ b/src/lottie/lottieparser.h @@ -19,6 +19,7 @@ #ifndef LOTTIEPARSER_H #define LOTTIEPARSER_H +#include "rlottie.h" #include "lottiemodel.h" #include @@ -28,7 +29,7 @@ class LottieParser { ~LottieParser(); LottieParser(char *str, const char *dir_path, const std::vector> - &colorReplacements = {}); + &colorReplacements = {}, rlottie::FitzModifier fitzModifier = rlottie::FitzModifier::None); std::shared_ptr model(); private: std::unique_ptr d; diff --git a/src/lottie/rapidjson/rapidjson.h b/src/lottie/rapidjson/rapidjson.h index 549936ff..7c4fd7be 100644 --- a/src/lottie/rapidjson/rapidjson.h +++ b/src/lottie/rapidjson/rapidjson.h @@ -403,7 +403,7 @@ RAPIDJSON_NAMESPACE_END */ #ifndef RAPIDJSON_ASSERT #include -#define RAPIDJSON_ASSERT(x) assert(x) +#define RAPIDJSON_ASSERT(x) //assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// diff --git a/src/vector/config.h b/src/vector/config.h index 528115bc..8a259506 100644 --- a/src/vector/config.h +++ b/src/vector/config.h @@ -11,7 +11,7 @@ //#define LOTTIE_IMAGE_MODULE_SUPPORT //enable lottie model caching -//#define LOTTIE_CACHE_SUPPORT +#define LOTTIE_CACHE_SUPPORT // disable image loader #define LOTTIE_IMAGE_MODULE_DISABLED diff --git a/src/vector/freetype/v_ft_raster.cpp b/src/vector/freetype/v_ft_raster.cpp index 51cb1f2c..2fd2259c 100644 --- a/src/vector/freetype/v_ft_raster.cpp +++ b/src/vector/freetype/v_ft_raster.cpp @@ -537,6 +537,10 @@ static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y) dx = to_x - ras.x; dy = to_y - ras.y; + if (SW_FT_ABS(dx) > 10000000 || SW_FT_ABS(dy) > 10000000) { + goto End; + } + fx1 = ras.x - SUBPIXELS(ex1); fy1 = ras.y - SUBPIXELS(ey1); @@ -707,6 +711,9 @@ static void gray_render_conic(RAS_ARG_ const SW_FT_Vector* control, gray_split_conic(arc); arc += 2; top++; + + if (top + 1 > 32) return; + levels[top] = levels[top - 1] = level - 1; continue; } @@ -833,8 +840,11 @@ static void gray_render_cubic(RAS_ARG_ const SW_FT_Vector* control1, } Split: + if (arc + 7 > ras.bez_stack + 32 * 3 + 1) return; + gray_split_cubic(arc); arc += 3; + continue; Draw: diff --git a/src/vector/vdrawable.cpp b/src/vector/vdrawable.cpp index cba3288f..9d3e8fe3 100644 --- a/src/vector/vdrawable.cpp +++ b/src/vector/vdrawable.cpp @@ -77,6 +77,9 @@ void VDrawable::setDashInfo(std::vector &dashInfo) if (!hasChanged) return; mStroke.mDash = dashInfo; + if (mStroke.mDash.size() == 1) { + mStroke.mDash.push_back(20); + } mFlag |= DirtyState::Path; } diff --git a/src/vector/vdrawhelper.cpp b/src/vector/vdrawhelper.cpp index 771228ed..9bbdb6c6 100644 --- a/src/vector/vdrawhelper.cpp +++ b/src/vector/vdrawhelper.cpp @@ -137,6 +137,9 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, float opacity, uint32_t *colorTable, int size) { + if (stops.empty()) { + return false; + } int dist, idist, pos = 0; size_t i; bool alpha = false; @@ -156,7 +159,7 @@ bool VGradientCache::generateGradientColorTable(const VGradientStops &stops, colorTable[pos++] = curColor; - while (fpos <= curr->first) { + while (fpos <= curr->first && pos < size) { colorTable[pos] = colorTable[pos - 1]; pos++; fpos += incr; @@ -867,7 +870,7 @@ void VSpanData::updateSpanFunc() } } -#if !defined(__SSE2__) && !defined(__ARM_NEON__) +#if !defined(__SSE2__) && (!defined(__ARM_NEON__) || defined(LOTTIE_DISABLE_ARM_NEON)) void memfill32(uint32_t *dest, uint32_t value, int length) { int n; @@ -912,7 +915,7 @@ void vInitDrawhelperFunctions() { vInitBlendFunctions(); -#if defined(__ARM_NEON__) +#if defined(__ARM_NEON__) && !defined(LOTTIE_DISABLE_ARM_NEON) // update fast path for NEON extern void Vcomp_func_solid_SourceOver_neon( uint32_t * dest, int length, uint32_t color, uint32_t const_alpha); diff --git a/src/vector/vraster.cpp b/src/vector/vraster.cpp index 80e7537e..467fd7dc 100644 --- a/src/vector/vraster.cpp +++ b/src/vector/vraster.cpp @@ -483,8 +483,10 @@ class RleTaskScheduler { class RleTaskScheduler { public: +#ifndef LOTTIE_THREAD_SAFE FTOutline outlineRef{}; SW_FT_Stroker stroker; +#endif public: static RleTaskScheduler &instance() @@ -493,11 +495,29 @@ class RleTaskScheduler { return singleton; } - RleTaskScheduler() { SW_FT_Stroker_New(&stroker); } + RleTaskScheduler() { +#ifndef LOTTIE_THREAD_SAFE + SW_FT_Stroker_New(&stroker); +#endif + } - ~RleTaskScheduler() { SW_FT_Stroker_Done(stroker); } + ~RleTaskScheduler() { +#ifndef LOTTIE_THREAD_SAFE + SW_FT_Stroker_Done(stroker); +#endif + } - void process(VTask task) { (*task)(outlineRef, stroker); } + void process(VTask task) { +#ifdef LOTTIE_THREAD_SAFE + FTOutline outlineRef{}; + SW_FT_Stroker stroker; + SW_FT_Stroker_New(&stroker); +#endif + (*task)(outlineRef, stroker); +#ifdef LOTTIE_THREAD_SAFE + SW_FT_Stroker_Done(stroker); +#endif + } }; #endif diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index d56710d3..a5deee1d 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -503,11 +503,14 @@ static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj, result->size = result->alloc - available; } -void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitXor(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { int da = *ptr; @@ -519,12 +522,15 @@ void blitXor(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, +void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = divBy255((255 - spans->coverage) * (*ptr)); @@ -534,11 +540,14 @@ void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer, } } -void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x > bufferLen || l > bufferLen || x + l > bufferLen) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr)); @@ -548,11 +557,14 @@ void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) +void blit(VRle::Span *spans, int count, uchar *buffer, int bufferLen, int offsetX) { while (count--) { int x = spans->x + offsetX; int l = spans->len; + if (x > bufferLen || l > bufferLen || x + l > bufferLen || x + l < 0) { + return; + } uchar *ptr = buffer + x; while (l--) { *ptr = std::max(spans->coverage, *ptr); @@ -562,13 +574,16 @@ void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX) } } -size_t bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) +size_t bufferToRle(uchar *buffer, int bufferLen, 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 > bufferLen) { + return count; + } for (int i = 0; i < size; i++) { uchar curValue = buffer[0]; if (value != curValue) { @@ -626,14 +641,15 @@ static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, 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(), -offset); + constexpr auto kBufferSize = 1024; + std::array array = {{0}}; + blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset); if (op == Operation::Add) - blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset); + blitSrcOver(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); else if (op == Operation::Xor) - blitXor(bStart, (bPtr - bStart), array.data(), -offset); + blitXor(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) { @@ -689,11 +705,12 @@ static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b, 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(), -offset); - blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset); + constexpr auto kBufferSize = 1024; + std::array array = {{0}}; + blit(aStart, (aPtr - aStart), array.data(), kBufferSize, -offset); + blitDestinationOut(bStart, (bPtr - bStart), array.data(), kBufferSize, -offset); VRle::Span *tResult = temp.data(); - size_t size = bufferToRle(array.data(), std::max(aLength, bLength), + size_t size = bufferToRle(array.data(), kBufferSize, std::max(aLength, bLength), offset, y, tResult); if (available >= size) { while (size--) {