mv canvas::mapRect to Matrix::transform_rectangle

This commit is contained in:
侯歌 2021-09-18 18:11:44 +08:00
parent 73536ec8fe
commit 3fae3783dc
15 changed files with 132 additions and 99 deletions

View File

@ -369,7 +369,7 @@ void Animation::getInvalidateRegion(int left, int top, int width, int height,
Rect previousRegion = mPreviousRegion;
invalidate.set(left, top, width, height);
//transformation.getMatrix().mapRect(invalidate);
transformation.getMatrix().transform_rectangle((const RectangleInt&)invalidate,(RectangleInt&)invalidate);
// Enlarge the invalidate region to account for rounding errors
invalidate.inflate(-1,-1);//inset(-1.0f, -1.0f);
tempRegion=invalidate;//.set(invalidate);

31
src/gui/cairomm/matrix.cc Normal file → Executable file
View File

@ -17,6 +17,7 @@
*/
#include <cairomm/matrix.h>
#include <cairomm/private.h>
#include <cmath>
namespace Cairo
{
@ -102,4 +103,34 @@ Matrix operator*(const Matrix& a, const Matrix& b)
return m;
}
void Matrix::transform_rectangle(const RectangleInt& from,Rectangle&to)const{
double pt[8];
pt[0] = pt[6] = from.x ;
pt[1] = pt[3] = from.y ;
pt[2] = pt[4] = from.x + from.width;
pt[5] = pt[7] = from.x + from.height;
double x1=INT_MAX,y1=INT_MAX;
double x2=INT_MIN,y2=INT_MIN;
for(int i=0;i<8;i+=2){
transform_point(pt[i],pt[i+1]);
x1 = std::min(x1,pt[i]);
y1 = std::min(y1,pt[i+1]);
x2 = std::max(x2,pt[i]);
y2 = std::max(y2,pt[i+1]);
}
to.x = (int)std::floor(x1);
to.y = (int)std::floor(y1);
to.width = (int)std::ceil(x2) - to.x;
to.height= (int)std::ceil(y2) - to.y;
}
void Matrix::transform_rectangle(const RectangleInt& from,RectangleInt&to)const{
Rectangle tof;
transform_rectangle(from,tof);
to.x= std::floor(tof.x);
to.y = (int)std::floor(tof.y);
to.width = (int)std::ceil(tof.width);
to.height= (int)std::ceil(tof.height);
}
} // namespace Cairo

6
src/gui/cairomm/matrix.h Normal file → Executable file
View File

@ -19,7 +19,7 @@
#define __CAIROMM_MATRIX_H
#include <cairomm/cairommconfig.h>
#include <cairomm/types.h>
#include <cairo.h>
namespace Cairo
@ -159,6 +159,10 @@ public:
* @param y Y position. An in/out parameter
*/
void transform_point(double& x, double& y) const;
/*added by zhhou*/
void transform_rectangle(const RectangleInt& from,Rectangle&to)const;
void transform_rectangle(const RectangleInt& from,RectangleInt&to)const;
};
/** Returns a Matrix initialized to the identity matrix

View File

@ -32,6 +32,7 @@ static struct option app_options[]={
{"language",required_argument,0,0},
{"record" ,required_argument,0,0},
{"monkey" ,required_argument,0,0},
{"debug" ,no_argument ,0,0},
{0,0,0,0}
};
@ -77,17 +78,6 @@ App::App(int argc,const char*argv[],const struct option*extoptions){
InputEventSource*inputsource=new InputEventSource(getArg("record",""));
addEventHandler(inputsource);
inputsource->playback(getArg("monkey",""));
/*SignalSource*sigsource=new GenericSignalSource(false);
addEventSource(sigsource,[this](EventSource&s){
LOGI("Sig interrupt %d",((SignalSource&)s).signo);
this->exit(((SignalSource&)s).signo);
return false;
});
sigsource->add(SIGABRT);
sigsource->add(SIGINT);
sigsource->add(SIGTERM);
sigsource->add(SIGKILL);*/
}
App::~App(){

View File

@ -96,24 +96,6 @@ void Canvas::rotate(float degrees,float px,float py){
transform(mtx);
}
Rect Canvas::mapRect(const Matrix& mtx,const Rect& r){
double pt[8];
pt[0]=r.left ; pt[1]=r.top;
pt[2]=r.right(); pt[3]=r.top;
pt[4]=r.right(); pt[5]=r.bottom();
pt[6]=r.left; pt[7]=r.bottom();
double x1=INT_MAX,y1=INT_MAX;
double x2=INT_MIN,y2=INT_MIN;
for(int i=0;i<8;i+=2){
mtx.transform_point(pt[i],pt[i+1]);
x1 = std::min(x1,pt[i]);
y1 = std::min(y1,pt[i+1]);
x2 = std::max(x2,pt[i]);
y2 = std::max(y2,pt[i+1]);
}
return Rect::MakeLTRB((int)std::floor(x1),(int)std::floor(y1),(int)std::ceil(x2),(int)std::ceil(y2));
}
void Canvas::get_text_size(const std::string&text,int*width,int *height){
TextExtents te;
get_text_extents(text,te);

View File

@ -50,7 +50,6 @@ public:
void draw_ninepatch(const RefPtr<ImageSurface>img,const RECT& rect,const std::vector<NinePatchBlock>&horz,
const std::vector<NinePatchBlock>&vert);
void rotate(float degrees,float px,float py);
static Rect mapRect(const Matrix& mtx,const Rect& r);
void dump2png(const char*fname);
void invalidate(const Rect&r);
void invalidate(const RefPtr<Region>&rgn);

View File

@ -50,41 +50,35 @@ bool Rect::contains(int xx,int yy)const{
}
bool Rect::intersect(const Rect&a,const Rect&b){
if(a.empty()||b.empty()){
set(0,0,0,0);
int x1, y1, x2, y2;
x1 = std::max (a.left, b.left);
y1 = std::max (a.top , b.top);
/* Beware the unsigned promotion, fortunately we have bits to spare
* as (CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN) < UINT_MAX
*/
x2 = std::min (a.left + (int) a.width, b.left + (int) b.width);
y2 = std::min (a.top + (int) a.height, b.top + (int) b.height);
if (x1 >= x2 || y1 >= y2) {
left = 0;
top = 0;
width = 0;
height = 0;
return false;
} else {
left = x1;
top = y1;
width = x2 - x1;
height = y2 - y1;
return true;
}
//check if the 2 Rect intersect
if( a.left + a.width <= b.left || b.left + b.width <= a.left || a.top + a.height <= b.top || b.top + b.height <= a.top ){
// No intersection
set(0,0,0,0);
return false ;//Rect::emptyRect;
}
//calculate the coordinates of the intersection
int i_x = a.left > b.left ? a.left : b.left;
int i_y = a.top > b.top ? a.top : b.top;
int thisWBorder = a.left + a.width;
int otherWBorder = b.left + b.width;
int thisHBorder = a.top + a.height;
int otherHBorder = b.top + b.height;
int i_w = thisWBorder > otherWBorder ? otherWBorder - i_x : thisWBorder - i_x;
int i_h = thisHBorder > otherHBorder ? otherHBorder - i_y : thisHBorder - i_y;
set(i_x,i_y,i_w,i_h);
return true;
}
bool Rect::intersect(int l, int t, int w, int h) {
if (this->left < l+w && l < this->right() && this->top < t+h && t < this->bottom()) {
this->width = std::min(l+w,this->right())-this->left;
this->height= std::min(t+h,this->bottom())-this->top;
this->left = std::max(this->left,l);
this->top = std::max(this->top,t);
return true;
}
return false;
return intersect(*this,Make(l,t,w,h));
}
bool Rect::contains(const Rect&a)const{
@ -95,21 +89,24 @@ bool Rect::contains(const Rect&a)const{
}
void Rect::Union(const Rect&b){
const int mx=std::min(left,b.left);
const int my=std::min(top,b.top);
width = std::max(right(),b.right())-mx;
height= std::max(bottom(),b.bottom())-my;
left= mx;
top = my;
int x1, y1, x2, y2;
x1 = std::min (left, b.left);
y1 = std::min (top, b.top);
/* Beware the unsigned promotion, fortunately we have bits to spare
* as (CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN) < UINT_MAX
*/
x2 = std::max (b.left + (int) b.width, left + width);
y2 = std::max (b.top + (int) b.height, top + height);
left = x1;
top = y1;
width = x2 - x1;
height = y2 - y1;
}
void Rect::Union(int x,int y,int w,int h){
const int mx=std::min(left,x);
const int my=std::min(top,y);
width = std::max(right(),x+w)-mx;
height= std::max(bottom(),y+h)-my;
left= mx;
top = my;
Union(Make(x,y,w,h));
}
}//end namespace

View File

@ -644,7 +644,7 @@ void ImageView::onDraw(Canvas& canvas) {
LOGV("DrawMatrix=%.2f,%.2f, %.2f,%.2f, %.2f,%.2f",mDrawMatrix.xx,mDrawMatrix.yx,
mDrawMatrix.xy,mDrawMatrix.yy,mDrawMatrix.x0,mDrawMatrix.y0);
canvas.translate(mPaddingLeft, mPaddingTop);
canvas.set_matrix(mDrawMatrix);
canvas.transform(mDrawMatrix);
mDrawable->draw(canvas);
canvas.restore();

View File

@ -448,7 +448,7 @@ void ProgressBar::drawTrack(Canvas&canvas){
canvas.translate(mPaddingLeft, mPaddingTop);
}
const long time = SystemClock::uptimeMillis();//getDrawingTime();
const long time = getDrawingTime();
if (mHasAnimation) {
mAnimation->getTransformation(time, *mTransformation);
const float scale = mTransformation->getAlpha();

View File

@ -1902,10 +1902,12 @@ bool View::draw(Canvas&canvas,ViewGroup*parent,long drawingTime){
// Sets the flag as early as possible to allow draw() implementations
// to call invalidate() successfully when doing animations
mPrivateFlags |= PFLAG_DRAWN;
double cx1,cy1,cx2,cy2;
canvas.get_clip_extents(cx1,cy1,cx2,cy2);
Rect rcc=Rect::MakeLTRB(cx1,cy1,cx2,cy2);
if (!concatMatrix && (parentFlags & (ViewGroup::FLAG_SUPPORT_STATIC_TRANSFORMATIONS |
ViewGroup::FLAG_CLIP_CHILDREN)) == ViewGroup::FLAG_CLIP_CHILDREN &&
false/*canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW)*/ &&
rcc.intersect(mLeft, mTop, mWidth, mHeight)&& /*canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&*/
(mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {
mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;
return more;
@ -2050,7 +2052,7 @@ bool View::draw(Canvas&canvas,ViewGroup*parent,long drawingTime){
if (!scalingRequired || cache == nullptr) {
canvas.rectangle(0,0,getWidth(), getHeight());//canvas.clipRect(0, 0, getWidth(), getHeight());
} else {
//canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
//canvas.rectangle(0, 0, cache->getWidth(), cache->getHeight());
}
}
canvas.clip();
@ -4825,6 +4827,10 @@ void View::getDrawingRect(Rect& outRect) {
outRect.height=mHeight;
}
long View::getDrawingTime() const{
return mAttachInfo ? mAttachInfo->mDrawingTime : 0;
}
int View::getMeasuredWidth()const{
return mMeasuredWidth & MEASURED_SIZE_MASK;
}

View File

@ -527,6 +527,7 @@ public:
void getHitRect(Rect&);
bool pointInView(int localX,int localY,int slop);
const Rect getDrawingRect()const;
long getDrawingTime()const;
virtual void getFocusedRect(Rect&r);
virtual View& setPos(int x,int y);
virtual View& setSize(int x,int y);

View File

@ -1235,6 +1235,7 @@ void ViewGroup::drawInvalidateRegion(Canvas&canvas){
for(int i=0;i<num;i++){
RectangleInt r=mInvalidRgn->get_rectangle(i);
canvas.rectangle(r.x,r.y,r.width,r.height);
LOGV("%p:%d(%d,%d,%d,%d)%d",this,mID,r.x,r.y,r.width,r.height,DEBUG_DRAW);
}
canvas.stroke();
}
@ -1307,7 +1308,7 @@ void ViewGroup::dispatchDraw(Canvas&canvas){
int flags = mGroupFlags;
if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
bool buildCache = false;//!isHardwareAccelerated();
bool buildCache = !isHardwareAccelerated();
for (int i=0;i<mChildren.size();i++){
View* child=mChildren[i];
if ((child->mViewFlags & VISIBILITY_MASK) == VISIBLE) {
@ -1341,10 +1342,10 @@ void ViewGroup::dispatchDraw(Canvas&canvas){
// We will draw our child's animation, let's reset the flag
mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
bool more = false;
const long drawingTime = SystemClock::uptimeMillis();
const long drawingTime = getDrawingTime();
//if (usingRenderNodeProperties) canvas.insertReorderBarrier();
const int transientCount = mTransientIndices.size();
@ -1400,8 +1401,6 @@ void ViewGroup::dispatchDraw(Canvas&canvas){
if (DEBUG_DRAW) onDebugDraw(canvas);
if (DEBUG_DRAW) drawInvalidateRegion(canvas);
if (clipToPadding) {
while(clipSaveCount--)canvas.restore();
}
@ -1457,15 +1456,15 @@ void ViewGroup::invalidateChild(View*child,Rect&dirty){
}else{
transformMatrix=childMatrix;
}
Rect boundingRect =dirty;
dirty= Canvas::mapRect(transformMatrix,dirty);
LOGV("(%d,%d,%d,%d)-->(%d,%d,%d,%d) rotation=%f",boundingRect.left,boundingRect.top,boundingRect.width,boundingRect.height,
transformMatrix.transform_rectangle((const RectangleInt&)dirty,(RectangleInt&)dirty);
LOGV("(1.%d,%d,%d,%d)-->(%d,%d,%d,%d) rotation=%f",boundingRect.left,boundingRect.top,boundingRect.width,boundingRect.height,
dirty.left,dirty.top,dirty.width,dirty.height,child->getRotation());
}
View* view = parent;
do {
view=parent;
View*view=parent;
if (drawAnimation) {
if (view) {
view->mPrivateFlags |= PFLAG_DRAW_ANIMATION;
@ -1488,21 +1487,20 @@ void ViewGroup::invalidateChild(View*child,Rect&dirty){
parent = parent->invalidateChildInParent(location, dirty);
if ( view && !view->hasIdentityMatrix() ) { // Account for transform on current parent
Matrix m = view->getMatrix();
dirty= Canvas::mapRect(m,dirty);
m.transform_rectangle((const RectangleInt&)dirty,(RectangleInt&)dirty);
}
} while (parent);
//set invalidate region to rootview
dynamic_cast<ViewGroup*>(view)->mInvalidRgn->do_union((const RectangleInt&)dirty);
getRootView()->mInvalidRgn->do_union((const RectangleInt&)dirty);
}
ViewGroup*ViewGroup::invalidateChildInParent(int* location, Rect& dirty){
if (1||(mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {//0x20 0x8000
// either DRAWN, or DRAWING_CACHE_VALID
if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
!= FLAG_OPTIMIZE_INVALIDATE) {
dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
location[CHILD_TOP_INDEX] - mScrollY);
//mGroupFlags &=~ FLAG_CLIP_CHILDREN;
if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) != FLAG_OPTIMIZE_INVALIDATE) {
dirty.offset(location[CHILD_LEFT_INDEX]-mScrollX,location[CHILD_TOP_INDEX]-mScrollY);
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
dirty.Union(0, 0, mWidth,mHeight);
}

View File

@ -67,9 +67,11 @@ void Window::setRegion(const RefPtr<Region>&rgn){
}
void Window::draw(){
getCanvas();
ViewGroup::draw(*mAttachInfo->mCanvas);
mAttachInfo->mCanvas->invalidate(mInvalidRgn);
Canvas*canvas=getCanvas();
mAttachInfo->mDrawingTime=SystemClock::uptimeMillis();
ViewGroup::draw(*canvas);
if(DEBUG_DRAW)drawInvalidateRegion(*canvas);
canvas->invalidate(mInvalidRgn);
mInvalidRgn->subtract(mInvalidRgn);
}
@ -555,4 +557,4 @@ View*Window::inflate(Context*ctx,std::istream&stream){
return pd.rootView;
}
} // namespace ui
} //endof namespace

View File

@ -16,9 +16,14 @@ class RECTTEST:public testing::Test{
TEST_F(RECTTEST,intersect){
RECT rc1={0,0,100,100};
RECT rc2={-40,-40,100,100};
RECT rc2={-40,-50,100,100};
rc2.intersect(rc1);
printf("%d,%d %d,%d\r\n",rc2.left,rc2.top,rc2.width,rc2.height);
ASSERT_EQ(rc2.left,0);
ASSERT_EQ(rc2.top,0);
ASSERT_EQ(rc2.width,60);
ASSERT_EQ(rc2.height,50);
}
TEST_F(RECTTEST,intersect2){
RECT rc1={0,0,100,100};
@ -26,3 +31,10 @@ TEST_F(RECTTEST,intersect2){
rc1.intersect(rc2);
printf("%d,%d %d,%d\r\n",rc1.left,rc1.top,rc1.width,rc1.height);
}
TEST_F(RECTTEST,Union){
RECT rc1={-83,-83,566,566};
RECT rc2={0,0,800,600};
rc1.Union(rc2);
printf("%d,%d %d,%d\r\n",rc1.left,rc1.top,rc1.width,rc1.height);
}

View File

@ -159,6 +159,17 @@ TEST_F(CONTEXT,Clip1){
ctx->get_target()->write_to_png("clip1.png");
}
TEST_F(CONTEXT,Clip2){
ctx->reset_clip();
ctx->arc(100,100,50,0,M_PI*2.f);
ctx->clip();
double x1=0,y1=0,x2=0,y2=0;
ctx->get_clip_extents(x1,y1,x2,y2);
std::vector<Rectangle>lst;
ctx->copy_clip_rectangle_list(lst);
printf("CLIPS(%f,%f,%f,%f) lst.size=%d\r\n",x1,y1,x2,y2,lst.size());
}
TEST_F(CONTEXT,Mask){
RefPtr<ImageSurface>img=ImageSurface::create_from_png("im_game.png");