2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * https://www.gnu.org/licenses/
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.
29 enum class Operation {
39 static void rleIntersectWithRle(VRleHelper *, int, int, 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 *);
45 static inline uchar divBy255(int x)
47 return (x + (x >> 8) + 0x80) >> 8;
50 inline static void copyArrayToVector(const VRle::Span *span, int count,
51 std::vector<VRle::Span> &v)
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));
58 void VRle::VRleData::addSpan(const VRle::Span *span, int count)
60 copyArrayToVector(span, count, mSpans);
64 VRect VRle::VRleData::bbox() const
70 void VRle::VRleData::setBbox(const VRect &bbox) const
76 void VRle::VRleData::reset()
84 void VRle::VRleData::translate(const VPoint &p)
86 // take care of last offset if applied
87 mOffset = p - mOffset;
90 for (auto &i : mSpans) {
95 mBbox.translate(mOffset.x(), mOffset.y());
98 void VRle::VRleData::addRect(const VRect &rect)
102 int width = rect.width();
103 int height = rect.height();
105 mSpans.reserve(height);
108 for (int i = 0; i < height; i++) {
113 mSpans.push_back(span);
118 void VRle::VRleData::updateBbox() const
120 if (!mBboxDirty) return;
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();
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;
137 mBbox = VRect(l, t, r - l, b - t + 1);
141 void VRle::VRleData::invert()
143 for (auto &i : mSpans) {
144 i.coverage = 255 - i.coverage;
148 void VRle::VRleData::operator*=(int alpha)
151 for (auto &i : mSpans) {
152 i.coverage = divBy255(i.coverage * alpha);
156 void VRle::VRleData::opIntersect(const VRect &r, VRle::VRleSpanCb cb,
157 void *userData) const
161 if (r.contains(bbox())) {
162 cb(mSpans.size(), mSpans.data(), userData);
167 VRleHelper tresult, tmp_obj;
168 std::array<VRle::Span, 256> array;
170 // setup the tresult object
171 tresult.size = array.size();
172 tresult.alloc = array.size();
173 tresult.spans = array.data();
176 tmp_obj.size = mSpans.size();
177 tmp_obj.spans = const_cast<VRle::Span *>(mSpans.data());
179 // run till all the spans are processed
180 while (tmp_obj.size) {
181 rleIntersectWithRect(clip, &tmp_obj, &tresult);
183 cb(tresult.size, tresult.spans, userData);
190 void VRle::VRleData::opSubstract(const VRle::VRleData &a,
191 const VRle::VRleData &b)
193 // if two rle are disjoint
194 if (!a.bbox().intersects(b.bbox())) {
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();
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);
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();
211 // 2. calculate the intersect region
212 VRleHelper tresult, aObj, bObj;
213 std::array<VRle::Span, 256> array;
215 // setup the tresult object
216 tresult.size = array.size();
217 tresult.alloc = array.size();
218 tresult.spans = array.data();
221 aObj.size = a.mSpans.size() - sizeA;
225 bObj.size = b.mSpans.size() - sizeB;
228 // run till all the spans are processed
229 while (aObj.size && bObj.size) {
230 rleSubstractWithRle(&aObj, &bObj, &tresult);
232 copyArrayToVector(tresult.spans, tresult.size, mSpans);
236 // 3. copy the rest of a
237 if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans);
243 void VRle::VRleData::opGeneric(const VRle::VRleData &a, const VRle::VRleData &b, OpCode code)
245 // This routine assumes, obj1(span_y) < obj2(span_y).
247 // reserve some space for the result vector.
248 mSpans.reserve(a.mSpans.size() + b.mSpans.size());
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);
256 copyArrayToVector(b.mSpans.data(), b.mSpans.size(), mSpans);
257 copyArrayToVector(a.mSpans.data(), a.mSpans.size(), mSpans);
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();
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);
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);
275 // 3. calculate the intersect region
276 VRleHelper tresult, aObj, bObj;
277 std::array<VRle::Span, 256> array;
279 // setup the tresult object
280 tresult.size = array.size();
281 tresult.alloc = array.size();
282 tresult.spans = array.data();
285 aObj.size = a.mSpans.size() - sizeA;
289 bObj.size = b.mSpans.size() - sizeB;
292 Operation op = Operation::Add;
303 // run till all the spans are processed
304 while (aObj.size && bObj.size) {
305 rleOpGeneric(&aObj, &bObj, &tresult, op);
307 copyArrayToVector(tresult.spans, tresult.size, mSpans);
312 if (bObj.size) copyArrayToVector(bObj.spans, bObj.size, mSpans);
313 if (aObj.size) copyArrayToVector(aObj.spans, aObj.size, mSpans);
316 // update result bounding box
317 VRegion reg(a.bbox());
319 mBbox = reg.boundingRect();
323 static void rle_cb(int count, const VRle::Span *spans, void *userData)
325 auto vector = static_cast<std::vector<VRle::Span> *>(userData);
326 copyArrayToVector(spans, count, *vector);
329 void opIntersectHelper(const VRle::VRleData &obj1,
330 const VRle::VRleData &obj2,
331 VRle::VRleSpanCb cb, void *userData)
333 VRleHelper result, source, clip;
334 std::array<VRle::Span, 256> array;
336 // setup the tresult object
337 result.size = array.size();
338 result.alloc = array.size();
339 result.spans = array.data();
342 source.size = obj1.mSpans.size();
343 source.spans = const_cast<VRle::Span *>(obj1.mSpans.data());
345 // setup tmp clip object
346 clip.size = obj2.mSpans.size();
347 clip.spans = const_cast<VRle::Span *>(obj2.mSpans.data());
349 // run till all the spans are processed
350 while (source.size) {
351 rleIntersectWithRle(&clip, 0, 0, &source, &result);
353 cb(result.size, result.spans, userData);
359 void VRle::VRleData::opIntersect(const VRle::VRleData &obj1,
360 const VRle::VRleData &obj2)
362 opIntersectHelper(obj1, obj2, rle_cb, &mSpans);
367 #define VMIN(a, b) ((a) < (b) ? (a) : (b))
368 #define VMAX(a, b) ((a) > (b) ? (a) : (b))
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.
380 static void rleIntersectWithRle(VRleHelper *tmp_clip, int clip_offset_x,
381 int clip_offset_y, VRleHelper *tmp_obj,
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;
392 while (available && spans < end) {
393 if (clipSpans >= clipEnd) {
397 if ((clipSpans->y + clip_offset_y) > spans->y) {
401 if (spans->y != (clipSpans->y + clip_offset_y)) {
405 // assert(spans->y == (clipSpans->y + clip_offset_y));
407 sx2 = sx1 + spans->len;
408 cx1 = (clipSpans->x + clip_offset_x);
409 cx2 = cx1 + clipSpans->len;
411 if (cx1 < sx1 && cx2 < sx1) {
414 } else if (sx1 < cx1 && sx2 < cx1) {
419 len = VMIN(sx2, cx2) - x;
421 out->x = VMAX(sx1, cx1);
422 out->len = (VMIN(sx2, cx2) - out->x);
424 out->coverage = divBy255(spans->coverage * clipSpans->coverage);
435 // update the span list that yet to be processed
436 tmp_obj->spans = spans;
437 tmp_obj->size = end - spans;
439 // update the clip list that yet to be processed
440 tmp_clip->spans = clipSpans;
441 tmp_clip->size = clipEnd - clipSpans;
444 result->size = result->alloc - available;
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
456 static void rleIntersectWithRect(const VRect &clip, VRleHelper *tmp_obj,
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;
467 maxx = clip.right() - 1;
468 maxy = clip.bottom() - 1;
470 while (available && spans < end) {
471 if (spans->y > maxy) {
472 spans = end; // update spans so that we can breakout
475 if (spans->y < miny || spans->x > maxx ||
476 spans->x + spans->len <= minx) {
480 if (spans->x < minx) {
481 out->len = VMIN(spans->len - (minx - spans->x), maxx - minx + 1);
485 out->len = VMIN(spans->len, (maxx - spans->x + 1));
489 out->coverage = spans->coverage;
496 // update the span list that yet to be processed
497 tmp_obj->spans = spans;
498 tmp_obj->size = end - spans;
501 result->size = result->alloc - available;
504 void blitXor(VRle::Span *spans, int count, uchar *buffer,
509 int x = spans->x + offsetX;
514 *ptr = divBy255((255 - spans->coverage) * (da) + spans->coverage * (255 - da));
521 void blitDestinationOut(VRle::Span *spans, int count, uchar *buffer,
526 int x = spans->x + offsetX;
530 *ptr = divBy255((255 - spans->coverage) * (*ptr));
537 void blitSrcOver(VRle::Span *spans, int count, uchar *buffer, int offsetX)
541 int x = spans->x + offsetX;
545 *ptr = spans->coverage + divBy255((255 - spans->coverage) * (*ptr));
552 void blit(VRle::Span *spans, int count, uchar *buffer, int offsetX)
556 int x = spans->x + offsetX;
560 *ptr = std::max(spans->coverage, *ptr);
567 int bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out)
570 uchar value = buffer[0];
573 size = offsetX < 0 ? size + offsetX : size;
574 for (int i = 0; i < size; i++) {
575 uchar curValue = buffer[0];
576 if (value != curValue) {
579 out->x = offsetX + curIndex;
580 out->len = i - curIndex;
581 out->coverage = value;
592 out->x = offsetX + curIndex;
593 out->len = size - curIndex;
594 out->coverage = value;
600 static void rleOpGeneric(VRleHelper *a, VRleHelper *b, VRleHelper *result, Operation op)
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;
610 while (available && aPtr < aEnd && bPtr < bEnd) {
611 if (aPtr->y < bPtr->y) {
614 } else if (bPtr->y < aPtr->y) {
618 VRle::Span *aStart = aPtr;
619 VRle::Span *bStart = bPtr;
623 while (aPtr < aEnd && aPtr->y == y) aPtr++;
624 while (bPtr < bEnd && bPtr->y == y) bPtr++;
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);
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),
639 if (available >= size) {
651 // update the span list that yet to be processed
653 a->size = aEnd - aPtr;
655 // update the clip list that yet to be processed
657 b->size = bEnd - bPtr;
660 result->size = result->alloc - available;
663 static void rleSubstractWithRle(VRleHelper *a, VRleHelper *b,
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;
674 while (available && aPtr < aEnd && bPtr < bEnd) {
675 if (aPtr->y < bPtr->y) {
678 } else if (bPtr->y < aPtr->y) {
681 VRle::Span *aStart = aPtr;
682 VRle::Span *bStart = bPtr;
686 while (aPtr < aEnd && aPtr->y == y) aPtr++;
687 while (bPtr < bEnd && bPtr->y == y) bPtr++;
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);
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),
699 if (available >= size) {
711 // update the span list that yet to be processed
713 a->size = aEnd - aPtr;
715 // update the clip list that yet to be processed
717 b->size = bEnd - bPtr;
720 result->size = result->alloc - available;
723 VRle VRle::toRle(const VRect &rect)
725 if (rect.empty()) return VRle();
728 result.d.write().addRect(rect);