lottie/parser : Fixed proper parsing of opacity stops for gradient. 44/184044/2
authorsubhransu mohanty <sub.mohanty@samsung.com>
Fri, 13 Jul 2018 07:30:44 +0000 (16:30 +0900)
committersubhransu mohanty <sub.mohanty@samsung.com>
Fri, 13 Jul 2018 07:34:24 +0000 (16:34 +0900)
Change-Id: I91a2a8f99c253fa0478ec8e8ffc76d5313fafa97

src/lottie/lottiemodel.cpp
src/lottie/lottiemodel.h
src/lottie/lottieparser.cpp

index e843008c39e7517fc97a235b5b90c862f54da600..29156e689ea89caa91f74e7d9d267c27ba83ec06 100644 (file)
@@ -230,6 +230,83 @@ int LOTGStrokeData::getDashInfo(int frameNo, float *array) const
     }
 }
 
+/**
+ * Both the color stops and opacity stops are in the same array.
+ * There are {@link #colorPoints} colors sequentially as:
+ * [
+ *     ...,
+ *     position,
+ *     red,
+ *     green,
+ *     blue,
+ *     ...
+ * ]
+ *
+ * The remainder of the array is the opacity stops sequentially as:
+ * [
+ *     ...,
+ *     position,
+ *     opacity,
+ *     ...
+ * ]
+ */
+void LOTGradient::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 == -1 ) { // for legacy bodymovin (ref: lottie-android)
+        colorPoints = size / 4;
+    }
+    int opacityArraySize = size - colorPoints * 4;
+    float *opacityPtr = ptr + (colorPoints * 4);
+    stops.clear();
+    int j = 0;
+    for (int i = 0; i < colorPoints ; i++) {
+        float colorStop = ptr[0];
+        LottieColor color = LottieColor(ptr[1], ptr[2], ptr[3]);
+        if (opacityArraySize) {
+            if (j == opacityArraySize) {
+                // already reached the end
+                float stop1 = opacityPtr[j-4];
+                float op1 = opacityPtr[j-3];
+                float stop2 = opacityPtr[j-2];
+                float op2 = opacityPtr[j-1];
+                if (colorStop > stop2) {
+                    stops.push_back(std::make_pair(colorStop, color.toColor(op2)));
+                } else {
+                    float progress = (colorStop - stop1) / (stop2 - stop1);
+                    float opacity = op1 + progress * (op2 - op1);
+                    stops.push_back(std::make_pair(colorStop, color.toColor(opacity)));
+                }
+                continue;
+            }
+            for (; j < opacityArraySize ; j += 2) {
+                float opacityStop = opacityPtr[j];
+                if (opacityStop < colorStop) {
+                    // add a color using opacity stop
+                    stops.push_back(std::make_pair(opacityStop, color.toColor(opacityPtr[j+1])));
+                    continue;
+                }
+                // add a color using color stop
+                if (j == 0) {
+                    stops.push_back(std::make_pair(colorStop, color.toColor(opacityPtr[j+1])));
+                } else {
+                    float progress = (colorStop - opacityPtr[j-2]) / (opacityPtr[j] - opacityPtr[j-2]);
+                    float opacity = opacityPtr[j-1] + progress * (opacityPtr[j+1] - opacityPtr[j-1]);
+                    stops.push_back(std::make_pair(colorStop, color.toColor(opacity)));
+                }
+                j += 2;
+                break;
+            }
+        } else {
+            stops.push_back(std::make_pair(colorStop, color.toColor()));
+        }
+        ptr += 4;
+    }
+}
+
 void LOTGradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
 {
     bool init = false;
@@ -243,15 +320,7 @@ void LOTGradient::update(std::unique_ptr<VGradient> &grad, int frameNo)
     }
 
     if (!mGradient.isStatic() || init) {
-        LottieGradient gradData = mGradient.value(frameNo);
-        int size = gradData.mGradient.size();
-        float *ptr = gradData.mGradient.data();
-        grad->mStops.clear();
-        for (int i = 0; i < size ; i += 4) {
-            float stop = ptr[i];
-            LottieColor color = LottieColor(ptr[i+1], ptr[i+2], ptr[i+3]);
-            grad->mStops.push_back(std::make_pair(stop, color.toColor()));
-        }
+        populate(grad->mStops, frameNo);
     }
 
     if (mGradientType == 1) { //linear gradient
index 9265dda0b072bb9c5da27a796e95109050fcf681..80cca54872ccf48dae315614c568e9796d1749aa 100644 (file)
@@ -555,17 +555,21 @@ inline LottieGradient operator*(float m, const LottieGradient &g)
 class LOTGradient : public LOTData
 {
 public:
-    LOTGradient(LOTData::Type  type):LOTData(type){}
+    LOTGradient(LOTData::Type  type):LOTData(type), mColorPoints(-1){}
     inline float opacity(int frameNo) const {return mOpacity.value(frameNo)/100.0;}
     void update(std::unique_ptr<VGradient> &grad, int frameNo);
+
+private:
+    void populate(VGradientStops &stops, int frameNo);
 public:
     int                                 mGradientType;        /* "t" Linear=1 , Radial = 2*/
-    LOTAnimatable<VPointF>             mStartPoint;          /* "s" */
-    LOTAnimatable<VPointF>             mEndPoint;            /* "e" */
+    LOTAnimatable<VPointF>              mStartPoint;          /* "s" */
+    LOTAnimatable<VPointF>              mEndPoint;            /* "e" */
     LOTAnimatable<int>                  mHighlightLength;     /* "h" */
     LOTAnimatable<int>                  mHighlightAngle;      /* "a" */
     LOTAnimatable<int>                  mOpacity;             /* "o" */
     LOTAnimatable<LottieGradient>       mGradient;            /* "g" */
+    int                                 mColorPoints;
     bool                                mEnabled = true;      /* "fillEnabled" */
 };
 
index 5ff34517fe7e5ef8a1938d12dd49c8d45ade1923..8905d502faa8e3252af408f514d4ac0c7dfb51d6 100644 (file)
@@ -1274,7 +1274,9 @@ LottieParserImpl::parseGradientProperty(LOTGradient *obj, const char *key)
         while (const char* key = NextObjectKey()) {
             if (0 == strcmp(key, "k")) {
                 parseProperty(obj->mGradient);
-            } else {
+            } else if (0 == strcmp(key, "p")) {
+                obj->mColorPoints = GetInt();
+            }  else {
                 Skip(nullptr);
             }
         }