一、Region的定义和合法性检查
在Android系统中,定义了Region的概念,它代表屏幕上的一个区域,它是由一个或多个Rect组成的,代码位于frameworks/native/libs/ui/Region.cpp。而Rect则代表屏幕上的一个方形区域,这个区域可能是不可见的,部分可见或者完全不可见的。从代码实现的角度来看Region的实现,它拥有一个私有的数据成员变量:mStorage,它的类型为Vector<Rect>:
1. mStorage是一个有序数组,数组元素类型为Rect,除了包含构成Region区域的Rect外,还额外地包含一个元素,它就是这块区域的边界。
2. 如果Region只是一个简单的方形区域,则mStorage只包含这个Rect类型的元素。
从上述两点可知,mStorge的大小永远不可能为2,要想知道某个区域的边界大小,只需返回mStorage的最后一个元素。
3. Rect与Region的关系是is-a关系,反之则不成立。
inline bool isEmpty() const { return getBounds().isEmpty(); }
inline bool isRect() const { return mStorage.size() == 1; }
inline Rect getBounds() const { return mStorage[mStorage.size() - 1]; }
inline Rect bounds() const { return getBounds(); }
接下来研究的话题是Region的合法性。由于Region本身是由一系列Rect组成的,所以,首先,构成的Rect本身必须是合法的。其次,构成的Rect必须以Y方向和X方向排序,Y方向优先排序。这里引入另一个概念Span,它也是一个区域的概念,也是由一个或多个Rect组成,可以认为它是一种特殊的Region, 其本身也是构成Region的一部分,事实上,一个Region可以看成是由许多Span构成的。不过这些构成Span的Rect必须在Y方向上,top和bottom值与其他的Rect相同,即Y方向上不能重叠,在X上方向,left与right之间的覆盖的区域不能与其他的Rect之间有重叠。基于上述的描述,要检查一个Region是否合法,就要对上述的一些要求做检查,我们可以看Region的validate()函数,它实际上就是这样做的:
1. 首先检查构成Region的Rect本身的合法性。
...
if (cur->isValid() == false) {
ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
result = false;
}
if (cur->right > region_operator<Rect>::max_value) {
ALOGE_IF(!silent, "%s: rect->right > max_value", name);
result = false;
}
if (cur->bottom > region_operator<Rect>::max_value) {
ALOGE_IF(!silent, "%s: rect->right > max_value", name);
result = false;
}
...
2. 接下来,检查这些Rect是否是有序的。
if ((*prev < *cur) == false) {
ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
result = false;
}
3. 然后就是检查Span的合法性
if (cur->top == prev->top) {
if (cur->bottom != prev->bottom) {
ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
result = false;
} else if (cur->left < prev->right) {
ALOGE_IF(!silent,
"%s: spans overlap horizontally prev=%p, cur=%p",
name, prev, cur);
result = false;
}
} else if (cur->top < prev->bottom) {
ALOGE_IF(!silent,
"%s: spans overlap vertically prev&