From: subhransu mohanty Date: Wed, 1 Aug 2018 02:04:29 +0000 (+0900) Subject: lottie/vector: refactored VRle class to use cow_ptr. X-Git-Tag: submit/tizen/20180917.042405~137 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=62b1cea9e37475423d6cbf2943071238b0bb88b6;p=platform%2Fcore%2Fuifw%2Flottie-player.git lottie/vector: refactored VRle class to use cow_ptr. Change-Id: I00dd76c57e94a255efb478a61465ce6b20e8d0b5 --- diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index e76100d..f3283f6 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -185,6 +185,7 @@ void LOTMaskItem::update(int frameNo, const VMatrix &parentMatrix, path.transform(parentMatrix); mRleTask = VRaster::instance().generateFillInfo(std::move(path), std::move(mRle)); + mRle = VRle(); } VRle LOTMaskItem::rle() @@ -192,8 +193,8 @@ VRle LOTMaskItem::rle() if (mRleTask.valid()) { mRle = mRleTask.get(); if (!vCompare(mCombinedAlpha, 1.0f)) - mRle = mRle * (mCombinedAlpha * 255); - if (mData->mInv) mRle = ~mRle; + mRle *= (mCombinedAlpha * 255); + if (mData->mInv) mRle.invert(); } return mRle; } diff --git a/src/vector/vrle.cpp b/src/vector/vrle.cpp index 0fedea0..69d4f64 100644 --- a/src/vector/vrle.cpp +++ b/src/vector/vrle.cpp @@ -15,15 +15,237 @@ struct VRleHelper { ushort size; VRle::Span *spans; }; - -#define VMIN(a, b) ((a) < (b) ? (a) : (b)) -#define VMAX(a, b) ((a) > (b) ? (a) : (b)) +static void rleIntersectWithRle(VRleHelper *, int, int, VRleHelper *, + VRleHelper *); +static void rleIntersectWithRect(const VRect &, VRleHelper *, VRleHelper *); +static void rleAddWithRle(VRleHelper *, VRleHelper *, VRleHelper *); static inline uchar divBy255(int x) { return (x + (x >> 8) + 0x80) >> 8; } +inline static void copyArrayToVector(const VRle::Span *span, int 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, int count) +{ + copyArrayToVector(span, count, mSpans); + mBboxDirty = true; +} + +VRect VRle::VRleData::bbox() const +{ + updateBbox(); + return mBbox; +} + +void VRle::VRleData::reset() +{ + mSpans.clear(); + mBbox = VRect(); + mOffset = VPoint(); + mBboxDirty = false; +} + +void VRle::VRleData::translate(const VPoint &p) +{ + // take care of last offset if applied + mOffset = p - mOffset; + int x = mOffset.x(); + int y = mOffset.y(); + for (auto &i : mSpans) { + i.x = i.x + x; + i.y = i.y + y; + } + updateBbox(); + mBbox.translate(mOffset.x(), mOffset.y()); +} + +void VRle::VRleData::addRect(const VRect &rect) +{ + int x = rect.left(); + int y = rect.top(); + int width = rect.width(); + int height = rect.height(); + + mSpans.reserve(height); + + VRle::Span span; + for (int i = 0; i < height; i++) { + span.x = x; + span.y = y + i; + span.len = width; + span.coverage = 255; + mSpans.push_back(span); + } + updateBbox(); +} + +void VRle::VRleData::updateBbox() const +{ + if (!mBboxDirty) return; + + mBboxDirty = false; + + int i, l = 0, t = 0, r = 0, b = 0, sz; + l = std::numeric_limits::max(); + const VRle::Span *span = mSpans.data(); + + mBbox = VRect(); + sz = mSpans.size(); + if (sz) { + t = span[0].y; + b = span[sz - 1].y; + for (i = 0; i < sz; i++) { + if (span[i].x < l) l = span[i].x; + if (span[i].x + span[i].len > r) r = span[i].x + span[i].len; + } + mBbox = VRect(l, t, r - l, b - t + 1); + } +} + +void VRle::VRleData::invert() +{ + 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 +{ + 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()); + + // 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; + } +} + +void VRle::VRleData::opAdd(const VRle::VRleData &obj1, + const VRle::VRleData &obj2) +{ + // This routine assumes, obj1(span_y) < obj2(span_y). + + // reserve some space for the result vector. + mSpans.reserve(obj1.mSpans.size() + obj2.mSpans.size()); + + // if two rle are disjoint + if (!obj1.bbox().intersects(obj2.bbox())) { + copyArrayToVector(obj1.mSpans.data(), obj1.mSpans.size(), mSpans); + copyArrayToVector(obj2.mSpans.data(), obj2.mSpans.size(), mSpans); + } else { + VRle::Span *ptr = const_cast(obj1.mSpans.data()); + int otherY = obj2.mBbox.top(); + // 1. forward till both y intersect + while (ptr->y < otherY) ptr++; + int spanToCopy = ptr - obj1.mSpans.data(); + copyArrayToVector(obj1.mSpans.data(), spanToCopy, mSpans); + + // 2. calculate the intersect region + VRleHelper tresult, tmp_obj, tmp_other; + 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 = obj1.mSpans.size() - spanToCopy; + tmp_obj.spans = ptr; + + // setup tmp clip object + tmp_other.size = obj2.mSpans.size(); + tmp_other.spans = const_cast(obj2.mSpans.data()); + + // run till all the spans are processed + while (tmp_obj.size && tmp_other.size) { + rleAddWithRle(&tmp_other, &tmp_obj, &tresult); + if (tresult.size) { + copyArrayToVector(tresult.spans, tresult.size, mSpans); + } + tresult.size = 0; + } + // 3. copy the rest + if (tmp_other.size) { + copyArrayToVector(tmp_other.spans, tmp_other.size, mSpans); + } + if (tmp_obj.size) { + copyArrayToVector(tmp_obj.spans, tmp_obj.size, mSpans); + } + } + + // update result bounding box + VRegion reg(obj1.bbox()); + reg += obj2.bbox(); + mBbox = reg.boundingRect(); + mBboxDirty = false; +} + +void VRle::VRleData::opIntersect(const VRle::VRleData &obj1, + const VRle::VRleData &obj2) +{ + VRleHelper result, source, clip; + std::array array; + + // setup the tresult object + result.size = array.size(); + result.alloc = array.size(); + result.spans = array.data(); + + // setup tmp object + source.size = obj1.mSpans.size(); + source.spans = const_cast(obj1.mSpans.data()); + + // setup tmp clip object + clip.size = obj2.mSpans.size(); + clip.spans = const_cast(obj2.mSpans.data()); + + // run till all the spans are processed + while (source.size) { + rleIntersectWithRle(&clip, 0, 0, &source, &result); + if (result.size) { + copyArrayToVector(result.spans, result.size, mSpans); + } + result.size = 0; + } + updateBbox(); +} + +#define VMIN(a, b) ((a) < (b) ? (a) : (b)) +#define VMAX(a, b) ((a) > (b) ? (a) : (b)) + /* * This function will clip a rle list with another rle object * tmp_clip : The rle list that will be use to clip the rle @@ -214,8 +436,8 @@ int bufferToRle(uchar *buffer, int size, int offsetX, int y, VRle::Span *out) return count; } -static void rleAddWithRle1(VRleHelper *tmp_clip, VRleHelper *tmp_obj, - VRleHelper *result) +static void rleAddWithRle(VRleHelper *tmp_clip, VRleHelper *tmp_obj, + VRleHelper *result) { std::array rleHolder; VRle::Span * out = result->spans; @@ -275,534 +497,13 @@ static void rleAddWithRle1(VRleHelper *tmp_clip, VRleHelper *tmp_obj, result->size = result->alloc - available; } -class VRleImpl { -public: - inline VRleImpl() : m_bbox(), m_spans(), mOffset(), mBboxDirty(true) {} - VRleImpl &operator=(const VRleImpl &); - void addSpan(const VRle::Span *span, int count); - void updateBbox(); - bool operator==(const VRleImpl &) const; - void intersected(const VRect &r, VRleImpl &result); - void intersect(const VRect &r, VRle::VRleSpanCb cb, void *userData) const; - void intersected(const VRleImpl &clip, VRleImpl &result); - friend VDebug &operator<<(VDebug &os, const VRleImpl &object); - void invert(); - void alphaMul(int alpha); - void translate(const VPoint &pt); - void opAdd(const VRleImpl &other, VRleImpl &res); - VRect bbox(); - void reset(); - -public: - VRect m_bbox; - std::vector m_spans; // array of Spanlines. - VPoint mOffset; - bool mBboxDirty; -}; - -inline static void copyArrayToVector(const VRle::Span *span, int 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)); -} - -VDebug &operator<<(VDebug &os, const VRleImpl &o) -{ - os << "[bbox=" << o.m_bbox << "]" - << "[offset=" << o.mOffset << "]" - << "[span count =" << o.m_spans.size() << "]\n"; - os << "[rle spans = {x y len coverage}"; - for (auto sp : o.m_spans) - os << "{" << sp.x << " " << sp.y << " " << sp.len << " " << sp.coverage - << "}"; - os << "]"; - return os; -} - -VRect VRleImpl::bbox() -{ - updateBbox(); - return m_bbox; -} - -void VRleImpl::reset() -{ - m_spans.clear(); - m_bbox = VRect(); - mOffset = VPoint(); - mBboxDirty = false; -} - -void VRleImpl::translate(const VPoint &pt) -{ - // take care of last offset if applied - mOffset = pt - mOffset; - int x = mOffset.x(); - int y = mOffset.y(); - for (auto &i : m_spans) { - i.x = i.x + x; - i.y = i.y + y; - } - updateBbox(); - m_bbox.translate(mOffset.x(), mOffset.y()); -} - -void VRleImpl::invert() -{ - for (auto &i : m_spans) { - i.coverage = 255 - i.coverage; - } -} - -void VRleImpl::alphaMul(int alpha) -{ - alpha &= 0xff; - - for (auto &i : m_spans) { - i.coverage = divBy255(i.coverage * alpha); - } -} - -void VRleImpl::intersected(const VRect &r, VRleImpl &result) -{ - 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 = m_spans.size(); - tmp_obj.spans = m_spans.data(); - - // run till all the spans are processed - while (tmp_obj.size) { - rleIntersectWithRect(clip, &tmp_obj, &tresult); - if (tresult.size) { - copyArrayToVector(tresult.spans, tresult.size, result.m_spans); - } - tresult.size = 0; - } - result.updateBbox(); -} - -void VRleImpl::intersect(const VRect &r, VRle::VRleSpanCb cb, - void *userData) const -{ - 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 = m_spans.size(); - tmp_obj.spans = const_cast(m_spans.data()); - - // 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; - } -} - -void VRleImpl::intersected(const VRleImpl &clip, VRleImpl &result) -{ - VRleHelper tresult, tmp_obj, tmp_clip; - 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 = m_spans.size(); - tmp_obj.spans = m_spans.data(); - - // setup tmp clip object - tmp_clip.size = clip.m_spans.size(); - tmp_clip.spans = const_cast(clip.m_spans.data()); - - // run till all the spans are processed - while (tmp_obj.size) { - rleIntersectWithRle(&tmp_clip, 0, 0, &tmp_obj, &tresult); - if (tresult.size) { - copyArrayToVector(tresult.spans, tresult.size, result.m_spans); - } - tresult.size = 0; - } - result.updateBbox(); -} - -void VRleImpl::opAdd(const VRleImpl &other, VRleImpl &result) -{ - // reserve some space for the result vector. - result.m_spans.reserve(m_spans.size() + other.m_spans.size()); - // if two rle are disjoint - if (!m_bbox.intersects(other.m_bbox)) { - result.m_spans = m_spans; - copyArrayToVector(other.m_spans.data(), other.m_spans.size(), - result.m_spans); - } else { - VRle::Span *ptr = m_spans.data(); - int otherY = other.m_bbox.top(); - // 1. forward till both y intersect - while (ptr->y < otherY) ptr++; - int spanToCopy = ptr - m_spans.data(); - copyArrayToVector(m_spans.data(), spanToCopy, result.m_spans); - - // 2. calculate the intersect region - VRleHelper tresult, tmp_obj, tmp_other; - 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 = m_spans.size() - spanToCopy; - tmp_obj.spans = ptr; - - // setup tmp clip object - tmp_other.size = other.m_spans.size(); - tmp_other.spans = const_cast(other.m_spans.data()); - - // run till all the spans are processed - while (tmp_obj.size && tmp_other.size) { - rleAddWithRle1(&tmp_other, &tmp_obj, &tresult); - if (tresult.size) { - copyArrayToVector(tresult.spans, tresult.size, result.m_spans); - } - tresult.size = 0; - } - // 3. copy the rest - if (tmp_other.size) { - copyArrayToVector(tmp_other.spans, tmp_other.size, result.m_spans); - } - if (tmp_obj.size) { - copyArrayToVector(tmp_obj.spans, tmp_obj.size, result.m_spans); - } - } - - // update result bounding box - VRegion reg(m_bbox); - reg += other.m_bbox; - result.m_bbox = reg.boundingRect(); - result.mBboxDirty = false; -} - -VRleImpl &VRleImpl::operator=(const VRleImpl &other) -{ - m_spans = other.m_spans; - m_bbox = other.m_bbox; - mOffset = other.mOffset; - return *this; -} - -bool VRleImpl::operator==(const VRleImpl &other) const -{ - if (m_spans.size() != other.m_spans.size()) return false; - const VRle::Span *spans = m_spans.data(); - const VRle::Span *o_spans = other.m_spans.data(); - int sz = m_spans.size(); - - for (int i = 0; i < sz; i++) { - if (spans[i].x != o_spans[i].x || spans[i].y != o_spans[i].y || - spans[i].len != o_spans[i].len || - spans[i].coverage != o_spans[i].coverage) - return false; - } - return true; -} - -void VRleImpl::updateBbox() -{ - if (!mBboxDirty) return; - - mBboxDirty = false; - - int i, l = 0, t = 0, r = 0, b = 0, sz; - l = std::numeric_limits::max(); - const VRle::Span *span = m_spans.data(); - - m_bbox = VRect(); - sz = m_spans.size(); - if (sz) { - t = span[0].y; - b = span[sz - 1].y; - for (i = 0; i < sz; i++) { - if (span[i].x < l) l = span[i].x; - if (span[i].x + span[i].len > r) r = span[i].x + span[i].len; - } - m_bbox = VRect(l, t, r - l, b - t + 1); - } -} - -void VRleImpl::addSpan(const VRle::Span *span, int count) -{ - copyArrayToVector(span, count, m_spans); - mBboxDirty = true; -} - -struct VRleData { - VRleData() : ref(-1), impl() {} - RefCount ref; - VRleImpl impl; -}; - -static const struct VRleData shared_empty; - -inline void VRle::cleanUp(VRleData *d) -{ - delete d; -} - -void VRle::detach() -{ - if (d->ref.isShared()) *this = copy(); -} - -VRle VRle::copy() const -{ - VRle other; - - other.d = new VRleData; - other.d->impl = d->impl; - other.d->ref.setOwned(); - return other; -} - -VRle::~VRle() -{ - if (!d->ref.deref()) cleanUp(d); -} - -VRle::VRle() : d(const_cast(&shared_empty)) {} - -VRle::VRle(const VRle &other) -{ - d = other.d; - d->ref.ref(); -} - -VRle::VRle(VRle &&other) : d(other.d) -{ - other.d = const_cast(&shared_empty); -} - -VRle &VRle::operator=(const VRle &other) -{ - other.d->ref.ref(); - if (!d->ref.deref()) cleanUp(d); - - d = other.d; - return *this; -} - -VRle &VRle::operator=(VRle &&other) -{ - if (!d->ref.deref()) cleanUp(d); - d = other.d; - other.d = const_cast(&shared_empty); - return *this; -} - -bool VRle::isEmpty() const -{ - return (d == &shared_empty || d->impl.m_spans.empty()); -} - -void VRle::addSpan(const VRle::Span *span, int count) -{ - detach(); - d->impl.addSpan(span, count); -} - -VRect VRle::boundingRect() const -{ - if (isEmpty()) return VRect(); - return d->impl.bbox(); -} - -bool VRle::operator==(const VRle &other) const -{ - if (isEmpty()) return other.isEmpty(); - if (other.isEmpty()) return isEmpty(); - - if (d == other.d) - return true; - else - return d->impl == other.d->impl; -} - -void VRle::translate(const VPoint &p) -{ - if (isEmpty()) return; - - if (d->impl.mOffset == p) return; - - detach(); - d->impl.translate(p); -} - -VRle VRle::intersected(const VRect &r) const -{ - if (isEmpty() || r.isEmpty()) return VRle(); - - // check if the bounding rect is contain inside r - if (r.contains(boundingRect(), true)) return *this; - - VRle result; - result.detach(); - d->impl.intersected(r, result.d->impl); - return result; -} - -VRle VRle::intersected(const VRle &other) const -{ - if (isEmpty() || other.isEmpty()) return VRle(); - // check if the bounding rect are not intersecting - VRle result; - result.detach(); - d->impl.intersected(other.d->impl, result.d->impl); - return result; -} - -VRle VRle::operator~() const -{ - if (isEmpty()) return VRle(); - - VRle result = *this; - result.detach(); - result.d->impl.invert(); - return result; -} - -VRle VRle::operator+(const VRle &other) const -{ - if (isEmpty()) return other; - - if (other.isEmpty()) return *this; - - VRle result; - result.detach(); - if (boundingRect().top() < other.boundingRect().top()) - d->impl.opAdd(other.d->impl, result.d->impl); - else - other.d->impl.opAdd(d->impl, result.d->impl); - return result; -} - -VRle VRle::operator-(const VRle &other) const -{ - if (isEmpty()) return ~other; - - if (other.isEmpty()) return *this; - - VRle temp = ~other; - return *this + temp; -} - -VRle VRle::operator&(const VRle &o) const -{ - if (isEmpty() || o.isEmpty()) return VRle(); - - if (!boundingRect().intersects(o.boundingRect())) return VRle(); - - VRle result; - result.detach(); - d->impl.intersected(o.d->impl, result.d->impl); - return result; -} - -void VRle::intersect(const VRect &r, VRleSpanCb cb, void *userData) const -{ - d->impl.intersect(r, cb, userData); -} - -VRle &VRle::intersect(const VRect &r) -{ - if (isEmpty() || r.isEmpty()) return *this = VRle(); - - VRle result; - result.detach(); - d->impl.intersected(r, result.d->impl); - return *this = result; -} - -VRle operator*(const VRle &obj, int alpha) -{ - if (obj.isEmpty()) return obj; - - VRle result = obj; - result.detach(); - result.d->impl.alphaMul(alpha); - return result; -} - -int VRle::size() const -{ - if (isEmpty()) return 0; - return d->impl.m_spans.size(); -} - -const VRle::Span *VRle::data() const -{ - if (isEmpty()) return nullptr; - return d->impl.m_spans.data(); -} - -void VRle::reset() -{ - detach(); - d->impl.reset(); -} - VRle VRle::toRle(const VRect &rect) { if (rect.isEmpty()) return VRle(); VRle result; - result.detach(); - int x = rect.left(); - int y = rect.top(); - int width = rect.width(); - int height = rect.height(); - result.d->impl.m_spans.reserve(height); - VRle::Span span; - for (int i = 0; i < height; i++) { - span.x = x; - span.y = y + i; - span.len = width; - span.coverage = 255; - result.d->impl.m_spans.push_back(span); - } + result.d.write().addRect(rect); return result; } -VDebug &operator<<(VDebug &os, const VRle &o) -{ - os << "[RLE: [dptr = " - << "o.d" - << "]" - << "[ref = " << o.d->ref.count() << "]" << o.d->impl << "]"; - return os; -} - V_END_NAMESPACE diff --git a/src/vector/vrle.h b/src/vector/vrle.h index 5e2bc1b..b6a6b97 100644 --- a/src/vector/vrle.h +++ b/src/vector/vrle.h @@ -1,12 +1,14 @@ #ifndef VRLE_H #define VRLE_H -#include -#include -#include + +#include +#include "vcowptr.h" +#include "vglobal.h" +#include "vpoint.h" +#include "vrect.h" V_BEGIN_NAMESPACE -struct VRleData; class VRle { public: struct Span { @@ -17,49 +19,122 @@ public: }; typedef void (*VRleSpanCb)(int count, const VRle::Span *spans, void *userData); - ~VRle(); - VRle(); - VRle(const VRle &other); - VRle(VRle &&other); - VRle &operator=(const VRle &); - VRle &operator=(VRle &&other); bool isEmpty() const; VRect boundingRect() const; void addSpan(const VRle::Span *span, int count); - bool operator==(const VRle &other) const; - void translate(const VPoint &p); - void translate(int x, int y); - VRle intersected(const VRect &r) const; - VRle intersected(const VRle &other) const; - void intersect(const VRect &r, VRleSpanCb cb, void *userData) const; - VRle &intersect(const VRect &r); - int size() const; - const VRle::Span * data() const; - void reset(); - VRle operator~() const; - VRle operator+(const VRle &o) const; - VRle operator-(const VRle &o) const; - VRle operator&(const VRle &o) const; - static VRle toRle(const VRect &rect); - friend VRle operator*(const VRle &, int alpha); - inline friend VRle operator*(int alpha, const VRle &); - friend VDebug & operator<<(VDebug &os, const VRle &object); + + void reset(); + void translate(const VPoint &p); + void invert(); + + void operator*=(int alpha); + + void intersect(const VRect &r, VRleSpanCb cb, void *userData) const; + + VRle operator&(const VRle &o) const; + VRle operator-(const VRle &o) const; + VRle operator+(const VRle &o) const; + + static VRle toRle(const VRect &rect); private: - VRle copy() const; - void detach(); - void cleanUp(VRleData *x); - VRleData *d; + struct VRleData { + bool isEmpty() const { return mSpans.empty(); } + void addSpan(const VRle::Span *span, int count); + void updateBbox() const; + VRect bbox() const; + void reset(); + void translate(const VPoint &p); + void operator*=(int alpha); + void invert(); + void opIntersect(const VRect &, VRle::VRleSpanCb, void *) const; + void opAdd(const VRle::VRleData &, const VRle::VRleData &); + void opIntersect(const VRle::VRleData &, const VRle::VRleData &); + void addRect(const VRect &rect); + std::vector mSpans; + VPoint mOffset; + mutable VRect mBbox; + mutable bool mBboxDirty = true; + }; + + vcow_ptr d; }; -inline void VRle::translate(int x, int y) +inline bool VRle::isEmpty() const +{ + return d->isEmpty(); +} + +inline void VRle::addSpan(const VRle::Span *span, int count) +{ + d.write().addSpan(span, count); +} + +inline VRect VRle::boundingRect() const +{ + return d->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 (isEmpty() || o.isEmpty()) return VRle(); + + VRle result; + result.d.write().opIntersect(d.read(), o.d.read()); + + return result; +} + +inline VRle VRle::operator+(const VRle &o) const +{ + if (isEmpty()) return o; + if (o.isEmpty()) return *this; + + VRle result; + if (d->bbox().top() < o.d->bbox().top()) + result.d.write().opAdd(d.read(), o.d.read()); + else + result.d.write().opAdd(o.d.read(), d.read()); + + return result; +} + +inline VRle VRle::operator-(const VRle &o) const +{ + if (o.isEmpty()) return *this; + + VRle result = o; + result.invert(); + + if (isEmpty()) + return result; + else + return *this + result; +} + +inline void VRle::reset() +{ + d.write().reset(); +} + +inline void VRle::translate(const VPoint &p) { - translate(VPoint(x, y)); + d.write().translate(p); } -inline VRle operator*(int alpha, const VRle &rle) +inline void VRle::intersect(const VRect &r, VRleSpanCb cb, void *userData) const { - return (rle * alpha); + d->opIntersect(r, cb, userData); } V_END_NAMESPACE