| Index: cc/android_region_helper.h
|
| diff --git a/cc/android_region_helper.h b/cc/android_region_helper.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3aefacfb057c2c86270f8a953de5a4b79abbb5d3
|
| --- /dev/null
|
| +++ b/cc/android_region_helper.h
|
| @@ -0,0 +1,300 @@
|
| +/*
|
| + * 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, typename TYPE>
|
| +class region_operator
|
| +{
|
| + 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.fTop, current.fBottom);
|
| + spannerInner.prepare(inside);
|
| + do {
|
| + TYPE left, right;
|
| + int inside = spannerInner.next(current.fLeft, current.fRight);
|
| + if ((op_mask >> inside) & 1) {
|
| + if (current.fLeft < current.fRight &&
|
| + current.fTop < current.fBottom) {
|
| + rasterizer(current);
|
| + }
|
| + }
|
| + } while(!spannerInner.isDone());
|
| + } while(!spanner.isDone());
|
| + }
|
| +
|
| +private:
|
| + uint32_t op_mask;
|
| +
|
| + class SpannerBase
|
| + {
|
| + public:
|
| + SpannerBase()
|
| + : lhs_head(max_value), lhs_tail(max_value),
|
| + rhs_head(max_value), rhs_tail(max_value) {
|
| + }
|
| +
|
| + 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)
|
| + {
|
| + if (lhs.count) {
|
| + SpannerBase::lhs_head = lhs.rects->fTop + lhs.dy;
|
| + SpannerBase::lhs_tail = lhs.rects->fBottom + lhs.dy;
|
| + }
|
| + if (rhs.count) {
|
| + SpannerBase::rhs_head = rhs.rects->fTop + rhs.dy;
|
| + SpannerBase::rhs_tail = rhs.rects->fBottom + 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->fTop;
|
| + while (rects != end && rects->fTop == top) {
|
| + rects++;
|
| + count--;
|
| + }
|
| + if (rects != end) {
|
| + aTop = rects->fTop + reg.dy;
|
| + aBottom = rects->fBottom + 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) {
|
| + if (lhs.count) {
|
| + SpannerBase::lhs_head = lhs.rects->fLeft + lhs.dx;
|
| + SpannerBase::lhs_tail = lhs.rects->fRight + 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;
|
| + if (rhs.count) {
|
| + SpannerBase::rhs_head = rhs.rects->fLeft + rhs.dx;
|
| + SpannerBase::rhs_tail = rhs.rects->fRight + rhs.dx;
|
| + }
|
| + } else {
|
| + if (lhs.count) {
|
| + SpannerBase::lhs_head = lhs.rects->fLeft + lhs.dx;
|
| + SpannerBase::lhs_tail = lhs.rects->fRight + lhs.dx;
|
| + }
|
| + if (rhs.count) {
|
| + SpannerBase::rhs_head = rhs.rects->fLeft + rhs.dx;
|
| + SpannerBase::rhs_tail = rhs.rects->fRight + 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->fTop;
|
| + reg.rects++;
|
| + reg.count--;
|
| + if (!reg.count || reg.rects->fTop != cur_span_top) {
|
| + left = max_value;
|
| + right = max_value;
|
| + } else {
|
| + left = reg.rects->fLeft + reg.dx;
|
| + right = reg.rects->fRight + reg.dx;
|
| + }
|
| + }
|
| + }
|
| + };
|
| +
|
| + Spanner spanner;
|
| +};
|
| +
|
| +// ----------------------------------------------------------------------------
|
| +};
|
| +
|
| +#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
|
|
|