lottie/vector: refactored VRle class to use cow_ptr. 11/185911/4
authorsubhransu mohanty <sub.mohanty@samsung.com>
Wed, 1 Aug 2018 02:04:29 +0000 (11:04 +0900)
committerYoungbok Shin <youngb.shin@samsung.com>
Tue, 7 Aug 2018 04:35:36 +0000 (04:35 +0000)
Change-Id: I00dd76c57e94a255efb478a61465ce6b20e8d0b5

src/lottie/lottieitem.cpp
src/vector/vrle.cpp
src/vector/vrle.h

index e76100d..f3283f6 100644 (file)
@@ -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;
 }
index 0fedea0..69d4f64 100644 (file)
@@ -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<VRle::Span> &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<int>::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<VRle::Span, 256> 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<VRle::Span *>(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<VRle::Span *>(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<VRle::Span, 256> 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<VRle::Span *>(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<VRle::Span, 256> 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<VRle::Span *>(obj1.mSpans.data());
+
+    // setup tmp clip object
+    clip.size = obj2.mSpans.size();
+    clip.spans = const_cast<VRle::Span *>(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<VRle::Span, 256> 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<VRle::Span> m_spans;  // array of Spanlines.
-    VPoint                  mOffset;
-    bool                    mBboxDirty;
-};
-
-inline static void copyArrayToVector(const VRle::Span *span, int count,
-                                     std::vector<VRle::Span> &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<VRle::Span, 256> 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<VRle::Span, 256> 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<VRle::Span *>(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<VRle::Span, 256> 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<VRle::Span *>(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<VRle::Span, 256> 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<VRle::Span *>(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<int>::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<VRleData *>(&shared_empty)) {}
-
-VRle::VRle(const VRle &other)
-{
-    d = other.d;
-    d->ref.ref();
-}
-
-VRle::VRle(VRle &&other) : d(other.d)
-{
-    other.d = const_cast<VRleData *>(&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<VRleData *>(&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
index 5e2bc1b..b6a6b97 100644 (file)
@@ -1,12 +1,14 @@
 #ifndef VRLE_H
 #define VRLE_H
-#include <vglobal.h>
-#include <vpoint.h>
-#include <vrect.h>
+
+#include <vector>
+#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<VRle::Span> mSpans;
+        VPoint                  mOffset;
+        mutable VRect           mBbox;
+        mutable bool            mBboxDirty = true;
+    };
+
+    vcow_ptr<VRleData> 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