285 lines
8.9 KiB
C++
285 lines
8.9 KiB
C++
/*
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ANDROID_UI_PRIVATE_REGION_HELPER_H
|
|
#define ANDROID_UI_PRIVATE_REGION_HELPER_H
|
|
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
|
|
namespace android {
|
|
// ----------------------------------------------------------------------------
|
|
|
|
template<typename RECT>
|
|
class region_operator
|
|
{
|
|
typedef typename RECT::value_type TYPE;
|
|
static const TYPE max_value = 0x7FFFFFF;
|
|
|
|
public:
|
|
/*
|
|
* Common boolean operations:
|
|
* value is computed as 0b101 op 0b110
|
|
* other boolean operation are possible, simply compute
|
|
* their corresponding value with the above formulae and use
|
|
* it when instantiating a region_operator.
|
|
*/
|
|
static const uint32_t LHS = 0x5; // 0b101
|
|
static const uint32_t RHS = 0x6; // 0b110
|
|
enum {
|
|
op_nand = LHS & ~RHS,
|
|
op_and = LHS & RHS,
|
|
op_or = LHS | RHS,
|
|
op_xor = LHS ^ RHS
|
|
};
|
|
|
|
struct region {
|
|
RECT const* rects;
|
|
size_t count;
|
|
TYPE dx;
|
|
TYPE dy;
|
|
inline region(const region& rhs)
|
|
: rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
|
|
inline region(RECT const* r, size_t c)
|
|
: rects(r), count(c), dx(), dy() { }
|
|
inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
|
|
: rects(r), count(c), dx(dx), dy(dy) { }
|
|
};
|
|
|
|
class region_rasterizer {
|
|
friend class region_operator;
|
|
virtual void operator()(const RECT& rect) = 0;
|
|
public:
|
|
virtual ~region_rasterizer() { };
|
|
};
|
|
|
|
inline region_operator(int op, const region& lhs, const region& rhs)
|
|
: op_mask(op), spanner(lhs, rhs)
|
|
{
|
|
}
|
|
|
|
void operator()(region_rasterizer& rasterizer) {
|
|
RECT current;
|
|
do {
|
|
SpannerInner spannerInner(spanner.lhs, spanner.rhs);
|
|
int inside = spanner.next(current.top, current.bottom);
|
|
spannerInner.prepare(inside);
|
|
do {
|
|
TYPE left, right;
|
|
int inside = spannerInner.next(current.left, current.right);
|
|
if ((op_mask >> inside) & 1) {
|
|
if (current.left < current.right &&
|
|
current.top < current.bottom) {
|
|
rasterizer(current);
|
|
}
|
|
}
|
|
} while(!spannerInner.isDone());
|
|
} while(!spanner.isDone());
|
|
}
|
|
|
|
private:
|
|
uint32_t op_mask;
|
|
|
|
class SpannerBase
|
|
{
|
|
public:
|
|
enum {
|
|
lhs_before_rhs = 0,
|
|
lhs_after_rhs = 1,
|
|
lhs_coincide_rhs = 2
|
|
};
|
|
|
|
protected:
|
|
TYPE lhs_head;
|
|
TYPE lhs_tail;
|
|
TYPE rhs_head;
|
|
TYPE rhs_tail;
|
|
|
|
inline int next(TYPE& head, TYPE& tail,
|
|
bool& more_lhs, bool& more_rhs)
|
|
{
|
|
int inside;
|
|
more_lhs = false;
|
|
more_rhs = false;
|
|
if (lhs_head < rhs_head) {
|
|
inside = lhs_before_rhs;
|
|
head = lhs_head;
|
|
if (lhs_tail <= rhs_head) {
|
|
tail = lhs_tail;
|
|
more_lhs = true;
|
|
} else {
|
|
lhs_head = rhs_head;
|
|
tail = rhs_head;
|
|
}
|
|
} else if (rhs_head < lhs_head) {
|
|
inside = lhs_after_rhs;
|
|
head = rhs_head;
|
|
if (rhs_tail <= lhs_head) {
|
|
tail = rhs_tail;
|
|
more_rhs = true;
|
|
} else {
|
|
rhs_head = lhs_head;
|
|
tail = lhs_head;
|
|
}
|
|
} else {
|
|
inside = lhs_coincide_rhs;
|
|
head = lhs_head;
|
|
if (lhs_tail <= rhs_tail) {
|
|
tail = rhs_head = lhs_tail;
|
|
more_lhs = true;
|
|
}
|
|
if (rhs_tail <= lhs_tail) {
|
|
tail = lhs_head = rhs_tail;
|
|
more_rhs = true;
|
|
}
|
|
}
|
|
return inside;
|
|
}
|
|
};
|
|
|
|
class Spanner : protected SpannerBase
|
|
{
|
|
friend class region_operator;
|
|
region lhs;
|
|
region rhs;
|
|
|
|
public:
|
|
inline Spanner(const region& lhs, const region& rhs)
|
|
: lhs(lhs), rhs(rhs)
|
|
{
|
|
SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
|
|
SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy;
|
|
SpannerBase::rhs_head = rhs.rects->top + rhs.dy;
|
|
SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy;
|
|
}
|
|
|
|
inline bool isDone() const {
|
|
return !rhs.count && !lhs.count;
|
|
}
|
|
|
|
inline int next(TYPE& top, TYPE& bottom)
|
|
{
|
|
bool more_lhs = false;
|
|
bool more_rhs = false;
|
|
int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
|
|
if (more_lhs) {
|
|
advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
|
|
}
|
|
if (more_rhs) {
|
|
advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
|
|
}
|
|
return inside;
|
|
}
|
|
|
|
private:
|
|
static inline
|
|
void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
|
|
// got to next span
|
|
size_t count = reg.count;
|
|
RECT const * rects = reg.rects;
|
|
RECT const * const end = rects + count;
|
|
const int top = rects->top;
|
|
while (rects != end && rects->top == top) {
|
|
rects++;
|
|
count--;
|
|
}
|
|
if (rects != end) {
|
|
aTop = rects->top + reg.dy;
|
|
aBottom = rects->bottom + reg.dy;
|
|
} else {
|
|
aTop = max_value;
|
|
aBottom = max_value;
|
|
}
|
|
reg.rects = rects;
|
|
reg.count = count;
|
|
}
|
|
};
|
|
|
|
class SpannerInner : protected SpannerBase
|
|
{
|
|
region lhs;
|
|
region rhs;
|
|
|
|
public:
|
|
inline SpannerInner(const region& lhs, const region& rhs)
|
|
: lhs(lhs), rhs(rhs)
|
|
{
|
|
}
|
|
|
|
inline void prepare(int inside) {
|
|
if (inside == SpannerBase::lhs_before_rhs) {
|
|
SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
|
|
SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
|
|
SpannerBase::rhs_head = max_value;
|
|
SpannerBase::rhs_tail = max_value;
|
|
} else if (inside == SpannerBase::lhs_after_rhs) {
|
|
SpannerBase::lhs_head = max_value;
|
|
SpannerBase::lhs_tail = max_value;
|
|
SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
|
|
SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
|
|
} else {
|
|
SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
|
|
SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
|
|
SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
|
|
SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
|
|
}
|
|
}
|
|
|
|
inline bool isDone() const {
|
|
return SpannerBase::lhs_head == max_value &&
|
|
SpannerBase::rhs_head == max_value;
|
|
}
|
|
|
|
inline int next(TYPE& left, TYPE& right)
|
|
{
|
|
bool more_lhs = false;
|
|
bool more_rhs = false;
|
|
int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
|
|
if (more_lhs) {
|
|
advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
|
|
}
|
|
if (more_rhs) {
|
|
advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
|
|
}
|
|
return inside;
|
|
}
|
|
|
|
private:
|
|
static inline
|
|
void advance(region& reg, TYPE& left, TYPE& right) {
|
|
if (reg.rects && reg.count) {
|
|
const int cur_span_top = reg.rects->top;
|
|
reg.rects++;
|
|
reg.count--;
|
|
if (!reg.count || reg.rects->top != cur_span_top) {
|
|
left = max_value;
|
|
right = max_value;
|
|
} else {
|
|
left = reg.rects->left + reg.dx;
|
|
right = reg.rects->right + reg.dx;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Spanner spanner;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
};
|
|
|
|
#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
|