302 lines
				
				9.3 KiB
			
		
		
			
		
	
	
					302 lines
				
				9.3 KiB
			| 
											6 years ago
										 | /*
 | ||
|  |  * 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
 | ||
|  | {
 | ||
|  | public:
 | ||
|  |     typedef typename RECT::value_type TYPE;    
 | ||
|  |     static const TYPE max_value = 0x7FFFFFF;
 | ||
|  | 
 | ||
|  |     /* 
 | ||
|  |      * 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:
 | ||
|  |         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->top      + lhs.dy;
 | ||
|  |                 SpannerBase::lhs_tail = lhs.rects->bottom   + lhs.dy;
 | ||
|  |             }
 | ||
|  |             if (rhs.count) {
 | ||
|  |                 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) {
 | ||
|  |                 if (lhs.count) {
 | ||
|  |                     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;
 | ||
|  |                 if (rhs.count) {
 | ||
|  |                     SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
 | ||
|  |                     SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
 | ||
|  |                 }
 | ||
|  |             } else {
 | ||
|  |                 if (lhs.count) {
 | ||
|  |                     SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
 | ||
|  |                     SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
 | ||
|  |                 }
 | ||
|  |                 if (rhs.count) {
 | ||
|  |                     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 */
 |