updated licenses info
[platform/core/uifw/lottie-player.git] / src / vector / vrle.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the LGPL License, Version 2.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.gnu.org/licenses/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "vrle.h"
18 #include <vrect.h>
19 #include <algorithm>
20 #include <array>
21 #include <cstdlib>
22 #include <vector>
23 #include "vdebug.h"
24 #include "vglobal.h"
25 #include "vregion.h"
26
27 V_BEGIN_NAMESPACE
28
29 enum class Operation {
30     Add,
31     Xor
32 };
33
34 struct VRleHelper {
35     ushort      alloc;
36     ushort      size;
37     VRle::Span *spans;
38 };
39 static void rleIntersectWithRle(VRleHelper *, int, int, VRleHelper *,
40                                 VRleHelper *);
41 static void rleIntersectWithRect(const VRect &, VRleHelper *, VRleHelper *);
42 static void rleOpGeneric(VRleHelper *, VRleHelper *, VRleHelper *, Operation op);
43 static void rleSubstractWithRle(VRleHelper *, VRleHelper *, VRleHelper *);
44
45 static inline uchar divBy255(int x)
46 {
47     return (x + (x >> 8) + 0x80) >> 8;
48 }
49
50 inline static void copyArrayToVector(const VRle::Span *span, int count,
51                                      std::vector<VRle::Span> &v)
52 {
53     // make sure enough memory available
54     if (v.capacity() < v.size() + count) v.reserve(v.size() + count);
55     std::copy(span, span + count, back_inserter(v));
56 }
57
58 void VRle::VRleData::addSpan(const VRle::Span *span, int count)
59 {
60     copyArrayToVector(span, count, mSpans);
61     mBboxDirty = true;
62 }
63
64 VRect VRle::VRleData::bbox() const
65 {
66     updateBbox();
67     return mBbox;
68 }
69
70 void VRle::VRleData::setBbox(const VRect &bbox) const
71 {
72     mBboxDirty = false;
73     mBbox = bbox;
74 }
75
76 void VRle::VRleData::reset()
77 {
78     mSpans.clear();
79     mBbox = VRect();
80     mOffset = VPoint();
81     mBboxDirty = false;
82 }
83
84 void VRle::VRleData::translate(const VPoint &p)
85 {
86     // take care of last offset if applied
87     mOffset = p - mOffset;
88     int x = mOffset.x();
89     int y = mOffset.y();
90     for (auto &i : mSpans) {
91         i.x = i.x + x;
92         i.y = i.y + y;
93     }
94     updateBbox();
95     mBbox.translate(mOffset.x(), mOffset.y());
96 }
97
98 void VRle::VRleData::addRect(const VRect &rect)
99 {
100     int x = rect.left();
101     int y = rect.top();
102     int width = rect.width();
103     int height = rect.height();
104
105     mSpans.reserve(height);
106
107     VRle::Span span;
108     for (int i = 0; i < height; i++) {
109         span.x = x;
110         span.y = y + i;
111         span.len = width;
112         span.coverage = 255;
113         mSpans.push_back(span);
114     }
115     updateBbox();
116 }
117
118 void VRle::VRleData::updateBbox() const
119 {
120     if (!mBboxDirty) return;
121
122     mBboxDirty = false;
123
124     int i, l = 0, t = 0, r = 0, b = 0, sz;
125     l = std::numeric_limits<int>::max();
126     const VRle::Span *span = mSpans.data();
127
128     mBbox = VRect();
129     sz = mSpans.size();
130     if (sz) {
131         t = span[0].y;
132         b = span[sz - 1].y;
133         for (i = 0; i < sz; i++) {
134             if (span[i].x < l) l = span[i].x;
135             if (span[i].x + span[i].len > r) r = span[i].x + span[i].len;
136         }
137         mBbox = VRect(l, t, r - l, b - t + 1);
138     }
139 }
140
141 void VRle::VRleData::invert()
142 {
143     for (auto &i : mSpans) {
144         i.coverage = 255 - i.coverage;
145     }
146 }
147
148 void VRle::VRleData::operator*=(int alpha)
149 {
150     alpha &= 0xff;
151     for (auto &i : mSpans) {
152         i.coverage = divBy255(i.coverage * alpha);
153     }
154 }
155
156 void VRle::VRleData::opIntersect(const VRect &r, VRle::VRleSpanCb cb,
157                                  void *userData) const
158 {
159     if (empty()) return;
160
161     if (r.contains(bbox())) {
162         cb(mSpans.size(), mSpans.data(), userData);
163         return;
164     }
165
166     VRect clip = r;
167     VRleHelper                  tresult, tmp_obj;
168     std::array<VRle::Span, 256> array;
169
170     // setup the tresult object
171     tresult.size = array.size();
172     tresult.alloc = array.size();
173     tresult.spans = array.data();
174
175     // setup tmp object
176     tmp_obj.size = mSpans.size();
177     tmp_obj.spans = const_cast<VRle::Span *>(mSpans.data());
178
179     // run till all the spans are processed
180     while (tmp_obj.size) {
181         rleIntersectWithRect(clip, &tmp_obj, &tresult);
182         if (tresult.size) {
183             cb(tresult.size, tresult.spans, userData);
184         }
185         tresult.size = 0;
186     }
187 }
188
189 // res = a - b;
190 void VRle::VRleData::opSubstract(const VRle::VRleData &a,
191                                  const VRle::VRleData &b)
192 {
193     // if two rle are disjoint
194     if (!a.bbox().intersects(b.bbox())) {
195         mSpans = a.mSpans;
196     } else {
197         VRle::Span *      aPtr = const_cast<VRle::Span *>(a.mSpans.data());
198         const VRle::Span *aEnd = a.mSpans.data() + a.mSpans.size();
199         VRle::Span *      bPtr = const_cast<VRle::Span *>(b.mSpans.data());
200         const VRle::Span *bEnd = b.mSpans.data() + b.mSpans.size();
201
202         // 1. forward till both y intersect
203         while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++;
204         int sizeA = aPtr - a.mSpans.data();
205         if (sizeA) copyArrayToVector(a.mSpans.data(), sizeA, mSpans);
206
207         // 2. forward b till it intersect with a.
208         while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++;
209         int sizeB = bPtr - b.mSpans.data();
210
211         // 2. calculate the intersect region
212         VRleHelper                  tresult, aObj, bObj;
213         std::array<VRle::Span, 256> array;
214
215         // setup the tresult object
216         tresult.size = array.size();
217         tresult.alloc = array.size();
218         tresult.spans = array.data();
219
220         // setup a object
221         aObj.size = a.mSpans.size() - sizeA;
222         aObj.spans = aPtr;
223
224         // setup b object
225         bObj.size = b.mSpans.size() - sizeB;
226         bObj.spans = bPtr;
227
228         // run till all the spans are processed
229         while (aObj.size && bObj.size) {
230             rleSubstractWithRle(&aObj, &bObj, &tresult);
231             if (tresult.size) {
232                 copyArrayToVector(tresult.spans, tresult.size, mSpans);
233             }
234             tresult.size = 0;
235         }
236         // 3. copy the rest of a
237         if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans);
238     }
239
240     mBboxDirty = true;
241 }
242
243 void VRle::VRleData::opGeneric(const VRle::VRleData &a, const VRle::VRleData &b, OpCode code)
244 {
245     // This routine assumes, obj1(span_y) < obj2(span_y).
246
247     // reserve some space for the result vector.
248     mSpans.reserve(a.mSpans.size() + b.mSpans.size());
249
250     // if two rle are disjoint
251     if (!a.bbox().intersects(b.bbox())) {
252         if (a.mSpans[0].y < b.mSpans[0].y) {
253             copyArrayToVector(a.mSpans.data(), a.mSpans.size(), mSpans);
254             copyArrayToVector(b.mSpans.data(), b.mSpans.size(), mSpans);
255         } else {
256             copyArrayToVector(b.mSpans.data(), b.mSpans.size(), mSpans);
257             copyArrayToVector(a.mSpans.data(), a.mSpans.size(), mSpans);
258         }
259     } else {
260         VRle::Span *      aPtr = const_cast<VRle::Span *>(a.mSpans.data());
261         const VRle::Span *aEnd = a.mSpans.data() + a.mSpans.size();
262         VRle::Span *      bPtr = const_cast<VRle::Span *>(b.mSpans.data());
263         const VRle::Span *bEnd = b.mSpans.data() + b.mSpans.size();
264
265         // 1. forward a till it intersects with b
266         while ((aPtr != aEnd) && (aPtr->y < bPtr->y)) aPtr++;
267         int sizeA = aPtr - a.mSpans.data();
268         if (sizeA) copyArrayToVector(a.mSpans.data(), sizeA, mSpans);
269
270         // 2. forward b till it intersects with a
271         while ((bPtr != bEnd) && (bPtr->y < aPtr->y)) bPtr++;
272         int sizeB = bPtr - b.mSpans.data();
273         if (sizeB) copyArrayToVector(b.mSpans.data(), sizeB, mSpans);
274
275         // 3. calculate the intersect region
276         VRleHelper                  tresult, aObj, bObj;
277         std::array<VRle::Span, 256> array;
278
279         // setup the tresult object
280         tresult.size = array.size();
281         tresult.alloc = array.size();
282         tresult.spans = array.data();
283
284         // setup a object
285         aObj.size = a.mSpans.size() - sizeA;
286         aObj.spans = aPtr;
287
288         // setup b object
289         bObj.size = b.mSpans.size() - sizeB;
290         bObj.spans = bPtr;
291
292         Operation op = Operation::Add;
293         switch (code) {
294         case OpCode::Add:
295             op = Operation::Add;
296             break;
297         case OpCode::Xor:
298             op = Operation::Xor;
299             break;
300         default:
301             break;
302         }
303         // run till all the spans are processed
304         while (aObj.size && bObj.size) {
305             rleOpGeneric(&aObj, &bObj, &tresult, op);
306             if (tresult.size) {
307                 copyArrayToVector(tresult.spans, tresult.size, mSpans);
308             }
309             tresult.size = 0;
310         }
311         // 3. copy the rest
312         if (bObj.size) copyArrayToVector(bObj.spans, bObj.size, mSpans);
313         if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans);
314     }
315
316     // update result bounding box
317     VRegion reg(a.bbox());
318     reg += b.bbox();
319     mBbox = reg.boundingRect();
320     mBboxDirty = false;
321 }
322
323 static void  rle_cb(int count, const VRle::Span *spans, void *userData)
324 {
325     auto vector = static_cast<std::vector<VRle::Span> *>(userData);
326     copyArrayToVector(spans, count, *vector);
327 }
328
329 void opIntersectHelper(const VRle::VRleData &obj1,
330                        const VRle::VRleData &obj2,
331                        VRle::VRleSpanCb cb, void *userData)
332 {
333     VRleHelper                  result, source, clip;
334     std::array<VRle::Span, 256> array;
335
336     // setup the tresult object
337     result.size = array.size();
338     result.alloc = array.size();
339     result.spans = array.data();
340
341     // setup tmp object
342     source.size = obj1.mSpans.size();
343     source.spans = const_cast<VRle::Span *>(obj1.mSpans.data());
344
345     // setup tmp clip object
346     clip.size = obj2.mSpans.size();
347     clip.spans = const_cast<VRle::Span *>(obj2.mSpans.data());
348
349     // run till all the spans are processed
350     while (source.size) {
351         rleIntersectWithRle(&clip, 0, 0, &source, &result);
352         if (result.size) {
353             cb(result.size, result.spans, userData);
354         }
355         result.size = 0;
356     }
357 }
358
359 void VRle::VRleData::opIntersect(const VRle::VRleData &obj1,
360                                  const VRle::VRleData &obj2)
361 {
362     opIntersectHelper(obj1, obj2, rle_cb, &mSpans);
363     updateBbox();
364 }
365
366
367 #define VMIN(a, b) ((a) < (b) ? (a) : (b))
368 #define VMAX(a, b) ((a) > (b) ? (a) : (b))
369
370 /*
371  * This function will clip a rle list with another rle object
372  * tmp_clip  : The rle list that will be use to clip the rle
373  * tmp_obj   : holds the list of spans that has to be clipped
374  * result    : will hold the result after the processing
375  * NOTE: if the algorithm runs out of the result buffer list
376  *       it will stop and update the tmp_obj with the span list
377  *       that are yet to be processed as well as the tpm_clip object
378  *       with the unprocessed clip spans.
379  */
380 static void rleIntersectWithRle(VRleHelper *tmp_clip, int clip_offset_x,
381                                 int clip_offset_y, VRleHelper *tmp_obj,
382                                 VRleHelper *result)
383 {
384     VRle::Span *out = result->spans;
385     int         available = result->alloc;
386     VRle::Span *spans = tmp_obj->spans;
387     VRle::Span *end = tmp_obj->spans + tmp_obj->size;
388     VRle::Span *clipSpans = tmp_clip->spans;
389     VRle::Span *clipEnd = tmp_clip->spans + tmp_clip->size;
390     int         sx1, sx2, cx1, cx2, x, len;
391
392     while (available && spans < end) {
393         if (clipSpans >= clipEnd) {
394             spans = end;
395             break;
396         }
397         if ((clipSpans->y + clip_offset_y) > spans->y) {
398             ++spans;
399             continue;
400         }
401         if (spans->y != (clipSpans->y + clip_offset_y)) {
402             ++clipSpans;
403             continue;
404         }
405         // assert(spans->y == (clipSpans->y + clip_offset_y));
406         sx1 = spans->x;
407         sx2 = sx1 + spans->len;
408         cx1 = (clipSpans->x + clip_offset_x);
409         cx2 = cx1 + clipSpans->len;
410
411         if (cx1 < sx1 && cx2 < sx1) {
412             ++clipSpans;
413             continue;
414         } else if (sx1 < cx1 && sx2 < cx1) {
415             ++spans;
416             continue;
417         }
418         x = VMAX(sx1, cx1);
419         len = VMIN(sx2, cx2) - x;
420         if (len) {
421             out->x = VMAX(sx1, cx1);
422             out->len = (VMIN(sx2, cx2) - out->x);
423             out->y = spans->y;
424             out->coverage = divBy255(spans->coverage * clipSpans->coverage);
425             ++out;
426             --available;
427         }
428         if (sx2 < cx2) {
429             ++spans;
430         } else {
431             ++clipSpans;
432         }
433     }
434
435     // update the span list that yet to be processed
436     tmp_obj->spans = spans;
437     tmp_obj->size = end - spans;
438
439     // update the clip list that yet to be processed
440     tmp_clip->spans = clipSpans;
441     tmp_clip->size = clipEnd - clipSpans;
442
443     // update the result
444     result->size = result->alloc - available;
445 }
446
447 /*
448  * This function will clip a rle list with a given rect
449  * clip      : The clip rect that will be use to clip the rle
450  * tmp_obj   : holds the list of spans that has to be clipped
451  * result    : will hold the result after the processing
452  * NOTE: if the algorithm runs out of the result buffer list
453  *       it will stop and update the tmp_obj with the span list
454  *       that are yet to be processed
455  */
456 static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj,
457                                  VRleHelper *result)
458 {
459     VRle::Span *out = result->spans;
460     int         available = result->alloc;
461     VRle::Span *spans = tmp_obj->spans;
462     VRle::Span *end = tmp_obj->spans + tmp_obj->size;
463     short       minx, miny, maxx, maxy;
464
465     minx = clip.left();
466     miny = clip.top();
467     maxx = clip.right() - 1;
468     maxy = clip.bottom() - 1;
469
470     while (available && spans < end) {
471         if (spans->y > maxy) {
472             spans = end;  // update spans so that we can breakout
473             break;
474         }
475         if (spans->y < miny || spans->x > maxx ||
476             spans->x + spans->len <= minx) {
477             ++spans;
478             continue;
479         }
480         if (spans->x < minx) {
481             out->len = VMIN(spans->len - (minx - spans->x), maxx - minx + 1);
482             out->x = minx;
483         } else {
484             out->x = spans->x;
485             out->len = VMIN(spans->len, (maxx - spans->x + 1));
486         }
487         if (out->len != 0) {
488             out->y = spans->y;
489             out->coverage = spans->coverage;
490             ++out;
491             --available;
492         }
493         ++spans;
494     }
495
496     // update the span list that yet to be processed
497     tmp_obj->spans = spans;
498     tmp_obj->size = end - spans;
499
500     // update the result
501     result->size = result->alloc - available;
502 }
503
504 void blitXor(VRle::Span *spans, int count, uchar *buffer,
505                         int offsetX)
506 {
507     uchar *ptr;
508     while (count--) {
509         int x = spans->x + offsetX;
510         int l = spans->len;
511         ptr = buffer + x;
512         while (l--) {
513             int da = *ptr;
514             *ptr = divBy255((255 - spans->coverage) * (da) + spans->coverage * (255 - da));
515             ptr++;
516         }
517         spans++;
518     }
519 }
520
521 void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer,
522                         int offsetX)
523 {
524     uchar *ptr;
525     while (count--) {
526         int x = spans->x + offsetX;
527         int l = spans->len;
528         ptr = buffer + x;
529         while (l--) {
530             *ptr = divBy255((255 - spans->coverage) * (*ptr));
531             ptr++;
532         }
533         spans++;
534     }
535 }
536
537 void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX)
538 {
539     uchar *ptr;
540     while (count--) {
541         int x = spans->x + offsetX;
542         int l = spans->len;
543         ptr = buffer + x;
544         while (l--) {
545             *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr));
546             ptr++;
547         }
548         spans++;
549     }
550 }
551
552 void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX)
553 {
554     uchar *ptr;
555     while (count--) {
556         int x = spans->x + offsetX;
557         int l = spans->len;
558         ptr = buffer + x;
559         while (l--) {
560             *ptr = std::max(spans->coverage, *ptr);
561             ptr++;
562         }
563         spans++;
564     }
565 }
566
567 int bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out)
568 {
569     int   count = 0;
570     uchar value = buffer[0];
571     int   curIndex = 0;
572
573     size = offsetX < 0 ? size + offsetX : size;
574     for (int i = 0; i < size; i++) {
575         uchar curValue = buffer[0];
576         if (value != curValue) {
577             if (value) {
578                 out->y = y;
579                 out->x = offsetX + curIndex;
580                 out->len = i - curIndex;
581                 out->coverage = value;
582                 out++;
583                 count++;
584             }
585             curIndex = i;
586             value = curValue;
587         }
588         buffer++;
589     }
590     if (value) {
591         out->y = y;
592         out->x = offsetX + curIndex;
593         out->len = size - curIndex;
594         out->coverage = value;
595         count++;
596     }
597     return count;
598 }
599
600 static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, Operation op)
601 {
602     std::array<VRle::Span, 256> temp;
603     VRle::Span *                out = result->spans;
604     int                         available = result->alloc;
605     VRle::Span *                aPtr = a->spans;
606     VRle::Span *                aEnd = a->spans + a->size;
607     VRle::Span *                bPtr = b->spans;
608     VRle::Span *                bEnd = b->spans + b->size;
609
610     while (available && aPtr < aEnd && bPtr < bEnd) {
611         if (aPtr->y < bPtr->y) {
612             *out++ = *aPtr++;
613             available--;
614         } else if (bPtr->y < aPtr->y) {
615             *out++ = *bPtr++;
616             available--;
617         } else {  // same y
618             VRle::Span *aStart = aPtr;
619             VRle::Span *bStart = bPtr;
620
621             int y = aPtr->y;
622
623             while (aPtr < aEnd && aPtr->y == y) aPtr++;
624             while (bPtr < bEnd && bPtr->y == y) bPtr++;
625
626             int aLength = (aPtr - 1)->x + (aPtr - 1)->len;
627             int bLength = (bPtr - 1)->x + (bPtr - 1)->len;
628             int offset = std::min(aStart->x, bStart->x);
629
630             std::array<uchar, 1024> array = {{0}};
631             blit(aStart, (aPtr - aStart), array.data(), -offset);
632             if (op == Operation::Add)
633                 blitSrcOver(bStart, (bPtr - bStart), array.data(), -offset);
634             else if (op == Operation::Xor)
635                 blitXor(bStart, (bPtr - bStart), array.data(), -offset);
636             VRle::Span *tResult = temp.data();
637             int size = bufferToRle(array.data(), std::max(aLength, bLength),
638                                    offset, y, tResult);
639             if (available >= size) {
640                 while (size--) {
641                     *out++ = *tResult++;
642                     available--;
643                 }
644             } else {
645                 aPtr = aStart;
646                 bPtr = bStart;
647                 break;
648             }
649         }
650     }
651     // update the span list that yet to be processed
652     a->spans = aPtr;
653     a->size = aEnd - aPtr;
654
655     // update the clip list that yet to be processed
656     b->spans = bPtr;
657     b->size = bEnd - bPtr;
658
659     // update the result
660     result->size = result->alloc - available;
661 }
662
663 static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b,
664                                 VRleHelper *result)
665 {
666     std::array<VRle::Span, 256> temp;
667     VRle::Span *                out = result->spans;
668     int                         available = result->alloc;
669     VRle::Span *                aPtr = a->spans;
670     VRle::Span *                aEnd = a->spans + a->size;
671     VRle::Span *                bPtr = b->spans;
672     VRle::Span *                bEnd = b->spans + b->size;
673
674     while (available && aPtr < aEnd && bPtr < bEnd) {
675         if (aPtr->y < bPtr->y) {
676             *out++ = *aPtr++;
677             available--;
678         } else if (bPtr->y < aPtr->y) {
679             bPtr++;
680         } else {  // same y
681             VRle::Span *aStart = aPtr;
682             VRle::Span *bStart = bPtr;
683
684             int y = aPtr->y;
685
686             while (aPtr < aEnd && aPtr->y == y) aPtr++;
687             while (bPtr < bEnd && bPtr->y == y) bPtr++;
688
689             int aLength = (aPtr - 1)->x + (aPtr - 1)->len;
690             int bLength = (bPtr - 1)->x + (bPtr - 1)->len;
691             int offset = std::min(aStart->x, bStart->x);
692
693             std::array<uchar, 1024> array = {{0}};
694             blit(aStart, (aPtr - aStart), array.data(), -offset);
695             blitDestinationOut(bStart, (bPtr - bStart), array.data(), -offset);
696             VRle::Span *tResult = temp.data();
697             int size = bufferToRle(array.data(), std::max(aLength, bLength),
698                                    offset, y, tResult);
699             if (available >= size) {
700                 while (size--) {
701                     *out++ = *tResult++;
702                     available--;
703                 }
704             } else {
705                 aPtr = aStart;
706                 bPtr = bStart;
707                 break;
708             }
709         }
710     }
711     // update the span list that yet to be processed
712     a->spans = aPtr;
713     a->size = aEnd - aPtr;
714
715     // update the clip list that yet to be processed
716     b->spans = bPtr;
717     b->size = bEnd - bPtr;
718
719     // update the result
720     result->size = result->alloc - available;
721 }
722
723 VRle VRle::toRle(const VRect &rect)
724 {
725     if (rect.empty()) return VRle();
726
727     VRle result;
728     result.d.write().addRect(rect);
729     return result;
730 }
731
732 V_END_NAMESPACE