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
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;
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
#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 {
};
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