mass rename and rebranding from xwt to ibex - fixed to use ixt files
[org.ibex.core.git] / src / org / ibex / util / DirtyList.java
1 // Copyright (C) 2003 Adam Megacz <adam@ibex.org> all rights reserved.
2 //
3 // You may modify, copy, and redistribute this code under the terms of
4 // the GNU Library Public License version 2.1, with the exception of
5 // the portion of clause 6a after the semicolon (aka the "obnoxious
6 // relink clause")
7
8 package org.ibex.util;
9
10 /** 
11  *  A general-purpose data structure for holding a list of rectangular
12  *  regions that need to be repainted, with intelligent coalescing.
13  *
14  *  DirtyList will unify two regions A and B if the smallest rectangle
15  *  enclosing both A and B occupies no more than epsilon + Area_A +
16  *  Area_B. Failing this, if two corners of A fall within B, A will be
17  *  shrunk to exclude the union of A and B.
18  */
19 public class DirtyList {
20
21     public DirtyList() { }
22     
23     /** The dirty regions (each one is an int[4]). */
24     private int[][] dirties = new int[10][];
25
26     /** The number of dirty regions */
27     private int numdirties = 0;
28
29     /** See class comment */
30     private static final int epsilon = 50 * 50;
31
32     public int num() { return numdirties; }
33     
34     /** grows the array */
35     private void grow() {
36         int[][] newdirties = new int[dirties.length * 2][];
37         System.arraycopy(dirties, 0, newdirties, 0, numdirties);
38         dirties = newdirties;
39     }
40
41     /** Add a new rectangle to the dirty list; returns false if the
42      *  region fell completely within an existing rectangle or set of
43      *  rectangles (ie did not expand the dirty area)
44      */
45     public synchronized boolean dirty(int x, int y, int w, int h) {
46         if (numdirties == dirties.length) grow();
47
48         // we attempt the "lossless" combinations first
49         for(int i=0; i<numdirties; i++) {
50             int[] cur = dirties[i];
51
52             // new region falls completely within existing region
53             if (x >= cur[0] && y >= cur[1] && x + w <= cur[0] + cur[2] && y + h <= cur[1] + cur[3]) {
54                 return false;
55
56             // existing region falls completely within new region
57             } else if (x <= cur[0] && y <= cur[1] && x + w >= cur[0] + cur[2] && y + h >= cur[1] + cur[3]) {
58                 dirties[i][2] = 0;
59                 dirties[i][3] = 0;
60
61             // left end of new region falls within existing region
62             } else if (x >= cur[0] && x < cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {
63                 w = x + w - (cur[0] + cur[2]);
64                 x = cur[0] + cur[2];
65                 i = -1; continue;
66                 
67             // right end of new region falls within existing region
68             } else if (x + w > cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y + h <= cur[1] + cur[3]) {
69                 w = cur[0] - x;
70                 i = -1; continue;
71                 
72             // top end of new region falls within existing region
73             } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y >= cur[1] && y < cur[1] + cur[3]) {
74                 h = y + h - (cur[1] + cur[3]);
75                 y = cur[1] + cur[3];
76                 i = -1; continue;
77                 
78             // bottom end of new region falls within existing region
79             } else if (x >= cur[0] && x + w <= cur[0] + cur[2] && y + h > cur[1] && y + h <= cur[1] + cur[3]) {
80                 h = cur[1] - y;
81                 i = -1; continue;
82                 
83             // left end of existing region falls within new region
84             } else if (dirties[i][0] >= x && dirties[i][0] < x + w && dirties[i][1] >= y && dirties[i][1] + dirties[i][3] <= y + h) {
85                 dirties[i][2] = dirties[i][2] - (x + w - dirties[i][0]);
86                 dirties[i][0] = x + w;
87                 i = -1; continue;
88                 
89             // right end of existing region falls within new region
90             } else if (dirties[i][0] + dirties[i][2] > x && dirties[i][0] + dirties[i][2] <= x + w &&
91                        dirties[i][1] >= y && dirties[i][1] + dirties[i][3] <= y + h) {
92                 dirties[i][2] = x - dirties[i][0];
93                 i = -1; continue;
94                 
95             // top end of existing region falls within new region
96             } else if (dirties[i][0] >= x && dirties[i][0] + dirties[i][2] <= x + w && dirties[i][1] >= y && dirties[i][1] < y + h) {
97                 dirties[i][3] = dirties[i][3] - (y + h - dirties[i][1]);
98                 dirties[i][1] = y + h;
99                 i = -1; continue;
100                 
101             // bottom end of existing region falls within new region
102             } else if (dirties[i][0] >= x && dirties[i][0] + dirties[i][2] <= x + w &&
103                        dirties[i][1] + dirties[i][3] > y && dirties[i][1] + dirties[i][3] <= y + h) {
104                 dirties[i][3] = y - dirties[i][1];
105                 i = -1; continue;
106             }
107
108         }
109
110         // then we attempt the "lossy" combinations
111         for(int i=0; i<numdirties; i++) {
112             int[] cur = dirties[i];
113             if (w > 0 && h > 0 && cur[2] > 0 && cur[3] > 0 &&
114                 ((max(x + w, cur[0] + cur[2]) - min(x, cur[0])) *
115                  (max(y + h, cur[1] + cur[3]) - min(y, cur[1])) <
116                  w * h + cur[2] * cur[3] + epsilon)) {
117                 int a = min(cur[0], x);
118                 int b = min(cur[1], y);
119                 int c = max(x + w, cur[0] + cur[2]) - min(cur[0], x);
120                 int d = max(y + h, cur[1] + cur[3]) - min(cur[1], y);
121                 dirties[i][2] = 0;
122                 dirties[i][3] = 0;
123                 return dirty(a, b, c, d);
124             }
125         }
126
127         dirties[numdirties++] = new int[] { x, y, w, h };
128         return true;
129     }
130
131     /** Returns true if there are no regions that need repainting */
132     public boolean empty() { return (numdirties == 0); }
133     
134     /**
135      *  Atomically returns the list of dirty rectangles as an array of
136      *  four-int arrays and clears the internal dirty-rectangle
137      *  list. Note that some of the regions returned may be null, or
138      *  may have zero height or zero width, and do not need to be
139      *  repainted.
140      */
141     public synchronized int[][] flush() {
142         if (numdirties == 0) return null;
143         int[][] ret = dirties;
144         for(int i=numdirties; i<ret.length; i++) ret[i] = null;
145         dirties = new int[dirties.length][];
146         numdirties = 0;
147         return ret;
148     }
149
150     /** included here so that it can be inlined */
151     private static final int min(int a, int b) {
152         if (a<b) return a;
153         else return b;
154     }
155     
156     /** included here so that it can be inlined */
157     private static final int max(int a, int b) {
158         if (a>b) return a;
159         else return b;
160     }
161     
162     /** included here so that it can be inlined */
163     private static final int min(int a, int b, int c) {
164         if (a<=b && a<=c) return a;
165         else if (b<=c && b<=a) return b;
166         else return c;
167     }
168     
169     /** included here so that it can be inlined */
170     private static final int max(int a, int b, int c) {
171         if (a>=b && a>=c) return a;
172         else if (b>=c && b>=a) return b;
173         else return c;
174     }
175     
176     /** included here so that it can be inlined */
177     private static final int bound(int a, int b, int c) {
178         if (a > b) return a;
179         if (c < b) return c;
180         return b;
181     }
182
183 }