static size_t WidgetRenderer_RenderChildren( LCUI_WidgetRenderer that ) { size_t count = 0; LCUI_Widget child; LinkedListNode *node; LCUI_RectF rect; LCUI_PaintContextRec paint; LCUI_WidgetRenderer renderer; LCUI_Rect actual_rect, paint_rect; /* 按照显示顺序,从底到顶,递归遍历子级部件 */ for( LinkedList_EachReverse( node, &that->target->children_show ) ) { child = node->data; if( !child->computed_style.visible || child->state != WSTATE_NORMAL ) { continue; } rect.width = child->box.graph.width; rect.height = child->box.graph.height; rect.x = that->x + child->box.graph.x + that->content_left; rect.y = that->y + child->box.graph.y + that->content_top; /* 栅格化部件区域,即:转换为相对于根级部件的实际区域 */ LCUIMetrics_ComputeRectActual( &actual_rect, &rect ); if( !LCUIRect_GetOverlayRect( &that->content_rect, &actual_rect, &paint_rect ) ) { continue; } if( !LCUIRect_GetOverlayRect( &that->root_paint->rect, &paint_rect, &paint_rect ) ) { continue; } if( that->has_content_graph ) { paint.with_alpha = TRUE; } else { paint.with_alpha = that->paint->with_alpha; } paint.rect = paint_rect; /* 转换绘制区域坐标为相对于自身图层区域 */ paint.rect.x -= actual_rect.x; paint.rect.y -= actual_rect.y; /* 转换绘制区域坐标为相对于部件内容区域,作为子部件的绘制区域 */ paint_rect.x -= that->root_paint->rect.x; paint_rect.y -= that->root_paint->rect.y; Graph_Quote( &paint.canvas, &that->root_paint->canvas, &paint_rect ); renderer = WidgetRenderer( child, &paint, that ); count += WidgetRenderer_Render( renderer ); WidgetRenderer_Delete( renderer ); } return count; }
void Graph_ClearShadowArea( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { int i; LCUI_Graph canvas; LCUI_Rect rect, box_area, rects[4]; rect.w = box->w; rect.h = box->h; rect.x = rect.y = 0; /* 获取内容框区域 */ box_area.x = box->x + BoxShadow_GetBoxX( shadow ); box_area.y = box->y + BoxShadow_GetBoxY( shadow ); box_area.w = BoxShadow_GetBoxWidth( shadow, box->w ); box_area.h = BoxShadow_GetBoxHeight( shadow, box->h ); /* 获取内容框外的阴影区域 */ LCUIRect_CutFourRect( &box_area, &rect, rects ); for( i=0; i<4; ++i ) { if( LCUIRect_GetOverlayRect( &paint->rect, &rects[i], &rects[i] ) ) { rects[i].x -= paint->rect.x; rects[i].y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &rects[i] ); Graph_FillRect( &canvas, ARGB(0,0,0,0), NULL, TRUE ); } } }
static void Graph_DrawBottomRightShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { LCUI_Graph canvas; LCUI_Rect bound; LCUI_Pos pos; bound.x = BoxShadow_GetX( shadow ) + BLUR_WIDTH(shadow); bound.x += BoxShadow_GetBoxWidth( shadow, box->w ); bound.x += INNER_SHADOW_WIDTH(shadow)*2; bound.y = BoxShadow_GetY( shadow ) + BLUR_WIDTH(shadow); bound.y += BoxShadow_GetBoxHeight( shadow, box->h ); bound.y += INNER_SHADOW_WIDTH(shadow)*2; bound.w = bound.h = BLUR_WIDTH(shadow); pos.x = 0; pos.y = 0; if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { bound.x -= paint->rect.x; bound.y -= paint->rect.y; pos.x -= paint->rect.x; pos.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &bound ); draw_circle( &canvas, pos, bound.w, shadow->color ); } }
static void Graph_DrawLeftShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { float v, a; LCUI_Color color; LCUI_Graph *graph; int s, t, x, y, bound_x, bound_y; LCUI_Rect shadow_area, box_area, paint_area, area; s = 255; t = BLUR_WIDTH(shadow); v = 512.0/t; a = 2*(v*t-s)/(t*t); color = shadow->color; box_area.x = BoxShadow_GetBoxX( shadow ); box_area.y = BoxShadow_GetBoxY( shadow ); box_area.w = BoxShadow_GetBoxWidth( shadow, box->w ); box_area.h = BoxShadow_GetBoxHeight( shadow, box->h ); shadow_area.x = BoxShadow_GetX( shadow ); shadow_area.y = BoxShadow_GetY( shadow ) + BLUR_WIDTH(shadow); shadow_area.w = BLUR_WIDTH(shadow); shadow_area.h = box_area.h + INNER_SHADOW_WIDTH(shadow)*2; box_area.x += box->x; box_area.y += box->y; shadow_area.x += box->x; shadow_area.y += box->y; if( !LCUIRect_GetOverlayRect( &shadow_area, &paint->rect, &area ) ) { return; } Graph_GetValidRect( &paint->canvas, &paint_area ); graph = Graph_GetQuote( &paint->canvas ); shadow_area.x -= paint->rect.x; shadow_area.y -= paint->rect.y; box_area.x -= paint->rect.x; box_area.y -= paint->rect.y; area.x -= paint->rect.x; area.y -= paint->rect.y; bound_x = area.x + area.width; bound_y = area.y + area.height; if( bound_x > paint_area.x + paint_area.width ) { bound_x = paint_area.x + paint_area.width; } if( bound_y > paint_area.y + paint_area.height ) { bound_y = paint_area.y + paint_area.height; } t -= area.x - shadow_area.x; for( x = area.x; x < bound_x; ++x, --t ) { color.alpha = (uchar_t)(s - (v*t - (a*t*t) / 2)); color.alpha *= shadow->color.a / 255.0; for( y = area.y; y < bound_y; ++y ) { if( y >= box_area.y && y < box_area.y + box_area.h && x >= box_area.x && x < box_area.x + box_area.w ) { continue; } Graph_SetPixel( graph, x, y, color ); } } }
static void Graph_DrawTopShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { float v, a; int s, t, x, y, bound_x, bound_y; LCUI_Color color; LCUI_Graph *graph; LCUI_Rect shadow_area, box_area, area; box_area.x = BoxShadow_GetBoxX( shadow ); box_area.y = BoxShadow_GetBoxY( shadow ); box_area.w = BoxShadow_GetBoxWidth( shadow, box->w ); box_area.h = BoxShadow_GetBoxHeight( shadow, box->h ); /* 计算需要绘制上边阴影的区域 */ shadow_area.x = BoxShadow_GetX( shadow ) + BLUR_WIDTH(shadow); shadow_area.y = BoxShadow_GetY( shadow ); shadow_area.w = box_area.w + INNER_SHADOW_WIDTH(shadow)*2; shadow_area.h = BLUR_WIDTH(shadow); color = shadow->color; bound_x = shadow_area.x + shadow_area.w; bound_y = shadow_area.y + shadow_area.h; graph = Graph_GetQuote( &paint->canvas ); Graph_GetValidRect( &paint->canvas, &area ); if( !LCUIRect_GetOverlayRect( &area, &paint->rect, &area ) ) { return; } /** * 这里采用匀减速直线运动的公式: s = vt - at²/2 * 加速度 a 的求值公式为:a = 2x(vt - s)/t² */ s = 255; t = BLUR_WIDTH(shadow); v = 512.0/t; a = 2*(v*t-s)/(t*t); for( y=shadow_area.y; y<bound_y; ++y,--t ) { /* 忽略不在有效区域内的像素 */ if( y < area.y || y >= area.y + area.h ) { continue; } /* 计算当前行阴影的透明度 */ color.alpha = (uchar_t)(s-(v*t-(a*t*t)/2)); color.alpha *= shadow->color.a/255.0; for( x=shadow_area.x; x<bound_x; ++x ) { if( x < area.x || x >= area.x + area.w ) { continue; } if( y >= box_area.y && y < box_area.y + box_area.h && x >= box_area.x && x < box_area.x + box_area.w ) { continue; } Graph_SetPixel( graph, x, y, color ); } } }
static void Graph_DrawInnerShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { int i; LCUI_Graph canvas; LCUI_Rect rsd, rb, rects[4]; rb.x = BoxShadow_GetBoxX( shadow ); rb.y = BoxShadow_GetBoxY( shadow ); rb.w = BoxShadow_GetBoxWidth( shadow, box->w ); rb.h = BoxShadow_GetBoxHeight( shadow, box->h ); rsd.x = BoxShadow_GetX( shadow ) + BLUR_WIDTH(shadow); rsd.y = BoxShadow_GetY( shadow ) + BLUR_WIDTH(shadow); rsd.w = rb.w + INNER_SHADOW_WIDTH(shadow)*2; rsd.h = rb.h + INNER_SHADOW_WIDTH(shadow)*2; /* 截取出与内容区重叠的区域 */ if( LCUIRect_GetOverlayRect(&rb, &rsd, &rb) ) { LCUIRect_CutFourRect( &rb, &rsd, rects ); /* 从阴影区域中排除部件占用的区域 */ for( i=0; i<4; ++i ) { if( !LCUIRect_GetOverlayRect( &paint->rect, &rects[i],&rects[i]) ) { continue; } rects[i].x -= paint->rect.x; rects[i].y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &rects[i] ); Graph_FillColor( &canvas, shadow->color ); } return; } /* 不重叠则直接填充 */ if( LCUIRect_GetOverlayRect(&paint->rect, &rsd, &rb) ) { rb.x -= paint->rect.x; rb.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &rb ); Graph_FillColor( &canvas, shadow->color ); } }
static int check_rect_correct( LCUI_Rect *corret, LCUI_Rect *actual ) { LCUI_Rect rect; if( LCUIRect_GetOverlayRect( corret, actual, &rect ) ) { if( rect.x == corret->x && rect.y == corret->y && rect.width == corret->width && rect.height == corret->height ) { return 1; } } return 0; }
static void Graph_DrawRightShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { float v, a; int s, t, x, y, bound_x, bound_y; LCUI_Color color; LCUI_Graph *graph; LCUI_Rect shadow_area, box_area, area; box_area.x = BoxShadow_GetBoxX( shadow ); box_area.y = BoxShadow_GetBoxY( shadow ); box_area.w = BoxShadow_GetBoxWidth( shadow, box->w ); box_area.h = BoxShadow_GetBoxHeight( shadow, box->h ); shadow_area.x = BoxShadow_GetX( shadow ) + SHADOW_WIDTH(shadow); shadow_area.x += box_area.w + INNER_SHADOW_WIDTH(shadow); shadow_area.y = BoxShadow_GetY( shadow ) + BLUR_WIDTH(shadow); shadow_area.w = BLUR_WIDTH(shadow); shadow_area.h = box_area.h + INNER_SHADOW_WIDTH(shadow)*2; color = shadow->color; bound_x = shadow_area.x + shadow_area.w; bound_y = shadow_area.y + shadow_area.h; graph = Graph_GetQuote( &paint->canvas ); Graph_GetValidRect( &paint->canvas, &area ); if( !LCUIRect_GetOverlayRect( &area, &paint->rect, &area ) ) { return; } s = 255; t = BLUR_WIDTH(shadow); v = 512.0/t; a = 2*(v*t-s)/(t*t); for( t=0,x=shadow_area.x; x<bound_x; ++x,++t ) { if( x < area.x || x >= area.x + area.w ) { continue; } color.alpha = (uchar_t)(s-(v*t-(a*t*t)/2)); color.alpha *= shadow->color.a/255.0; for( y=shadow_area.y; y<bound_y; ++y ) { if( y < area.y || y >= area.y + area.h ) { continue; } if( y >= box_area.y && y < box_area.y + box_area.h && x >= box_area.x && x < box_area.x + box_area.w ) { continue; } Graph_SetPixel( graph, x, y, color ); } } }
static void Graph_DrawTopLeftShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow) { LCUI_Pos pos; LCUI_Rect bound; LCUI_Graph canvas; bound.w = bound.h = BLUR_WIDTH(shadow); bound.x = box->x + BoxShadow_GetX( shadow ); bound.y = box->y + BoxShadow_GetY( shadow ); if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { Graph_Init( &canvas ); bound.x -= paint->rect.x; bound.y -= paint->rect.y; pos.x = bound.x + BLUR_WIDTH( shadow ); pos.y = bound.y + BLUR_WIDTH( shadow ); Graph_Quote( &canvas, &paint->canvas, &bound ); DrawCircle( &canvas, pos, bound.w, shadow->color ); } }
/** * 绘制上边阴影 * @param[in] paint 绘制上下文 * @param[in] box 可供绘制阴影的区域范围 * @param[in] shadow 阴影参数 */ static void Graph_DrawTopShadow( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_BoxShadow *shadow ) { float v, a; LCUI_Color color; LCUI_Graph *graph; int s, t, x, y, bound_x, bound_y; LCUI_Rect shadow_area, box_area, paint_area, area; /** * 这里采用匀减速直线运动的公式: s = vt - at²/2 * 加速度 a 的求值公式为:a = 2x(vt - s)/t² */ s = 255; t = BLUR_WIDTH( shadow ); v = 512.0 / t; a = 2 * (v*t - s) / (t*t); color = shadow->color; /* 计算阴影内框区域 */ box_area.x = BoxShadow_GetBoxX( shadow ); box_area.y = BoxShadow_GetBoxY( shadow ); box_area.w = BoxShadow_GetBoxWidth( shadow, box->w ); box_area.h = BoxShadow_GetBoxHeight( shadow, box->h ); /* 计算需要绘制的阴影区域 */ shadow_area.x = BoxShadow_GetX( shadow ) + BLUR_WIDTH(shadow); shadow_area.y = BoxShadow_GetY( shadow ); shadow_area.w = box_area.w + INNER_SHADOW_WIDTH(shadow)*2; shadow_area.h = BLUR_WIDTH(shadow); /* 调整坐标 */ box_area.x += box->x; box_area.y += box->y; shadow_area.x += box->x; shadow_area.y += box->y; /* 如果阴影区域不在绘制范围内 */ if( !LCUIRect_GetOverlayRect( &shadow_area, &paint->rect, &area ) ) { return; } /* 获取有效的绘制范围 */ Graph_GetValidRect( &paint->canvas, &paint_area ); graph = Graph_GetQuote( &paint->canvas ); /* 将坐标转换成相对于绘制区域 */ shadow_area.x -= paint->rect.x; shadow_area.y -= paint->rect.y; box_area.x -= paint->rect.x; box_area.y -= paint->rect.y; area.x -= paint->rect.x; area.y -= paint->rect.y; bound_x = area.x + area.width; bound_y = area.y + area.height; /* 避免超出绘制范围 */ if( bound_x > paint_area.x + paint_area.width ) { bound_x = paint_area.x + paint_area.width; } if( bound_y > paint_area.y + paint_area.height ) { bound_y = paint_area.y + paint_area.height; } t -= area.x - shadow_area.x; for( y = area.y; y < bound_y; ++y, --t ) { /* 计算当前行像素点的透明度 */ color.alpha = (uchar_t)(s - (v*t - (a*t*t) / 2)); color.alpha *= shadow->color.a / 255.0; for( x = area.x; x < bound_x; ++x ) { if( y >= box_area.y && y < box_area.y + box_area.h && x >= box_area.x && x < box_area.x + box_area.w ) { continue; } Graph_SetPixel( graph, x, y, color ); } } }
/** * 渲染指定部件呈现的图形内容 * @param[in] w 部件 * @param[in] paint 进行绘制时所需的上下文 */ void Widget_Render( LCUI_Widget w, LCUI_PaintContext paint ) { int i, content_left, content_top; LCUI_Rect content_rect; LCUI_Graph content_graph, self_graph, layer_graph; LCUI_BOOL has_overlay, has_content_graph = FALSE, has_self_graph = FALSE,has_layer_graph = FALSE, is_cover_border = FALSE; Graph_Init( &layer_graph ); Graph_Init( &self_graph ); Graph_Init( &content_graph ); /* 若部件本身是透明的 */ if( w->style.opacity < 1.0 ) { has_self_graph = TRUE; has_content_graph = TRUE; has_layer_graph = TRUE; } else { /* 若使用了圆角边框,则判断当前脏矩形区域是否在圆角边框内 ... if( ... ) { has_content_graph = TRUE; is_cover_border = TRUE; } */ } /* 如果需要缓存自身的位图 */ if( has_self_graph ) { LCUI_PaintContextRec_ self_paint; /* 有位图缓存则直接截取出来,否则绘制一次 */ if( Graph_IsValid(&w->graph) ) { Graph_Quote( &self_graph, &w->graph, &paint->rect ); } else { Graph_Create( &self_graph, paint->rect.width, paint->rect.height ); } self_paint.canvas = self_graph; self_paint.rect = paint->rect; Widget_OnPaint( w, &self_paint ); } else { /* 直接将部件绘制到目标位图缓存中 */ if( Graph_IsValid(&w->graph) ) { Graph_Quote( &self_graph, &w->graph, &paint->rect ); Graph_Mix( &paint->canvas, &self_graph, Pos(0,0) ); Graph_WritePNG( "1,paint_canvas.png", &paint->canvas ); Graph_WritePNG( "2,self_graph.png", &self_graph ); } else { Widget_OnPaint( w, paint ); } } /* 计算内容框相对于图层的坐标 */ content_left = w->base.box.content.x - w->base.box.graph.x; content_top = w->base.box.content.y - w->base.box.graph.y; /* 获取内容框 */ content_rect.x = content_left; content_rect.y = content_top; content_rect.width = w->base.box.content.width; content_rect.height = w->base.box.content.height; /* 获取内容框与脏矩形重叠的区域 */ has_overlay = LCUIRect_GetOverlayRect( &content_rect, &paint->rect, &content_rect ); /* 如果没有与内容框重叠,则跳过内容绘制 */ if( !has_overlay ) { goto content_paint_done; } /* 将换重叠区域的坐标转换为相对于脏矩形的坐标 */ content_rect.x -= paint->rect.x; content_rect.y -= paint->rect.y; /* 若需要部件内容区的位图缓存 */ if( has_content_graph ) { content_graph.color_type = COLOR_TYPE_ARGB; Graph_Create( &content_graph, content_rect.w, content_rect.h ); } else { /* 引用该区域的位图,作为内容框的位图 */ Graph_Quote( &content_graph, &paint->canvas, &content_rect ); } i = LinkedList_GetTotal( &w->children_show ); /* 按照显示顺序,从底到顶,递归遍历子级部件 */ while( i-- ) { LCUI_Widget child; LCUI_Rect child_rect; LCUI_PaintContextRec_ child_paint; child = (LCUI_Widget)LinkedList_Get( &w->children_show ); if( !child->style.visible ) { continue; } /* 将子部件的区域,由相对于内容框转换为相对于当前脏矩形 */ child_rect = child->base.box.graph; child_rect.x += (content_left - paint->rect.x); child_rect.y += (content_top - paint->rect.y); /* 获取于内容框重叠的区域,作为子部件的绘制区域 */ has_overlay = LCUIRect_GetOverlayRect( &content_rect, &child_rect, &child_paint.rect ); /* 区域无效则不绘制 */ if( !has_overlay ) { continue; } /* 将子部件绘制区域转换相对于当前部件内容框 */ child_rect.x = child_paint.rect.x - content_rect.x; child_rect.y = child_paint.rect.y - content_rect.y; child_rect.width = child_paint.rect.width; child_rect.height = child_paint.rect.height; /* 在内容位图中引用所需的区域,作为子部件的画布 */ Graph_Quote( &child_paint.canvas, &content_graph, &child_rect ); Widget_Render( child, &child_paint ); } /* 如果与圆角边框重叠,则裁剪掉边框外的内容 */ if( is_cover_border ) { /* content_graph ... */ } content_paint_done: /* 若需要绘制的是当前部件图层,则先混合部件自身位图和内容位图,得出当 * 前部件的图层,然后将该图层混合到输出的位图中 */ if( has_layer_graph ) { Graph_Init( &layer_graph ); layer_graph.color_type = COLOR_TYPE_ARGB; Graph_Copy( &layer_graph, &self_graph ); Graph_Mix( &layer_graph, &content_graph, Pos(content_rect.x, content_rect.y) ); layer_graph.opacity = w->style.opacity; Graph_Mix( &paint->canvas, &layer_graph, Pos(0,0) ); } else if( has_content_graph ) { Graph_Mix( &paint->canvas, &content_graph, Pos(content_rect.x, content_rect.y) ); } Graph_WritePNG( "layer_graph.png", &layer_graph ); Graph_WritePNG( "self_graph.png", &self_graph ); Graph_WritePNG( "content_graph.png", &content_graph ); Graph_Free( &layer_graph ); Graph_Free( &self_graph ); Graph_Free( &content_graph ); }
static int _Widget_ProcInvalidArea( LCUI_Widget w, LCUI_BOOL is_root, int x, int y, LCUI_Rect *valid_box, LCUI_DirtyRectList *rlist ) { int i, n, count; LCUI_Widget child; LCUI_Rect rect, child_box, *r; count = n = LinkedList_GetTotal( &w->dirty_rects ); /* 取出当前记录的脏矩形 */ for( i=0; i<n; ++i ) { LinkedList_Goto( &w->dirty_rects, 0 ); r = (LCUI_Rect*)LinkedList_Get( &w->dirty_rects ); /* 若有独立位图缓存,则重绘脏矩形区域 */ if( Graph_IsValid(&w->graph) ) { LCUI_PaintContextRec_ paint; paint.rect = *r; Graph_Quote( &paint.canvas, &w->graph, &paint.rect ); Widget_OnPaint( w, &paint ); } /* 转换为相对于父部件的坐标 */ rect.x = r->x; rect.y = r->y; /* 如果当前是根部件,则不用加上自身坐标 */ if( !is_root ) { rect.x += w->base.box.graph.x; rect.y += w->base.box.graph.y; } rect.w = r->w; rect.h = r->h; /* 取出与容器内有效区域相交的区域 */ if( LCUIRect_GetOverlayRect(&rect, valid_box, &rect) ) { /* 转换相对于根级部件的坐标 */ rect.x += x; rect.y += y; DirtyRectList_Add( rlist, &rect ); } LinkedList_Delete( &w->dirty_rects ); } /* 若子级部件没有脏矩形记录 */ if( !w->has_dirty_child ) { return count; } /* 缩小有效区域到当前部件内容框内,若没有重叠区域,则不向子级部件递归 */ if( !LCUIRect_GetOverlayRect(valid_box, &w->base.box.content, &child_box) ) { return count; } /* 转换有效区域的坐标,相对于当前部件的内容框 */ child_box.x -= w->base.box.content.x; child_box.y -= w->base.box.content.y; n = LinkedList_GetTotal( &w->children ); /* 向子级部件递归 */ for( i=0; i<n; ++i ) { child = (LCUI_Widget)LinkedList_Get( &w->children ); if( !child->style.visible ) { continue; } count += _Widget_ProcInvalidArea( child, FALSE, child->base.box.graph.x + x, child->base.box.graph.y + y, &child_box, rlist ); } return count; }
void Graph_DrawBackground( LCUI_PaintContext paint, const LCUI_Rect *box, LCUI_Background *bg ) { float scale; LCUI_Graph graph; LCUI_BOOL with_alpha; LCUI_Rect read_rect, paint_rect; int image_x, image_y, image_w, image_h; /* 计算背景图应有的尺寸 */ if( bg->size.using_value ) { switch( bg->size.value ) { case SV_CONTAIN: image_w = box->width; scale = 1.0 * bg->image.width / image_w; image_h = 1.0 * bg->image.height / scale; if( image_h > box->height ) { image_h = box->height; scale = 1.0 * bg->image.height / box->height; image_w = (int)(1.0 * bg->image.width / scale); } break; case SV_COVER: image_w = box->width; scale = 1.0 * bg->image.width / image_w; image_h = 1.0 * bg->image.height / scale; if( image_h < box->height ) { image_h = box->height; scale = 1.0 * bg->image.height / image_h; image_w = (int)(1.0 * bg->image.width / scale); } break; case SV_AUTO: default: image_w = bg->image.width; image_h = bg->image.height; break; } } else { switch( bg->size.w.type ) { case SVT_SCALE: image_w = box->w * bg->size.w.scale; break; case SVT_PX: image_w = bg->size.w.px; break; default: image_w = bg->image.width; break; } switch( bg->size.h.type ) { case SVT_SCALE: image_h = box->h * bg->size.h.scale; break; case SVT_PX: image_h = bg->size.h.px; break; default: image_h = bg->image.height; break; } } /* 计算背景图的像素坐标 */ if( bg->position.using_value ) { switch( bg->position.value ) { case SV_TOP: case SV_TOP_CENTER: image_x = (box->w - image_w) / 2; image_y = 0; break; case SV_TOP_RIGHT: image_x = box->w - image_w; image_y = 0; break; case SV_CENTER_LEFT: image_x = 0; image_y = (box->h - image_h) / 2; break; case SV_CENTER: case SV_CENTER_CENTER: image_x = (box->w - image_w) / 2; image_y = (box->h - image_h) / 2; break; case SV_CENTER_RIGHT: image_x = box->w - image_w; image_y = (box->h - image_h) / 2; break; case SV_BOTTOM_LEFT: image_x = 0; image_y = box->h - image_h; break; case SV_BOTTOM_CENTER: image_x = (box->w - image_w) / 2; image_y = box->h - image_h; break; case SV_BOTTOM_RIGHT: image_x = box->w - image_w; image_y = box->h - image_h; break; case SV_TOP_LEFT: default:image_x = image_y = 0; break; } } else { switch( bg->position.x.type ) { case SVT_SCALE: image_x = box->w - image_w; image_x *= bg->position.x.scale; break; case SVT_PX: image_x = bg->position.x.px; break; default:image_x = 0; break; } switch( bg->position.y.type ) { case SVT_SCALE: image_y = box->h - image_h; image_y *= bg->position.y.scale; break; case SVT_PX: image_y = bg->position.y.px; break; default:image_y = 0; break; } } /* 获取当前绘制区域与背景内容框的重叠区域 */ if( !LCUIRect_GetOverlayRect( box, &paint->rect, &paint_rect ) ) { return; } with_alpha = bg->color.alpha < 255; paint_rect.x -= paint->rect.x; paint_rect.y -= paint->rect.y; Graph_Quote( &graph, &paint->canvas, &paint_rect ); Graph_FillRect( &graph, bg->color, NULL, TRUE ); /* 将坐标转换为相对于背景内容框 */ paint_rect.x += paint->rect.x - box->x; paint_rect.y += paint->rect.y - box->y; /* 保存背景图像区域 */ read_rect.x = image_x; read_rect.y = image_y; read_rect.width = image_w; read_rect.height = image_h; /* 获取当前绘制区域与背景图像的重叠区域 */ if( !LCUIRect_GetOverlayRect( &read_rect, &paint_rect, &read_rect ) ) { return; } /* 转换成相对于图像的坐标 */ read_rect.x -= image_x; read_rect.y -= image_y; /* 如果尺寸没有变化则直接引用 */ if( image_w == bg->image.w && image_h == bg->image.h ) { Graph_Quote( &graph, &bg->image, &read_rect ); /* 转换成相对于当前绘制区域的坐标 */ image_x = image_x + box->x - paint->rect.x; image_y = image_y + box->y - paint->rect.y; image_x += read_rect.x; image_y += read_rect.y; Graph_Mix( &paint->canvas, &graph, image_x, image_y, with_alpha ); } else { float scale; LCUI_Graph buffer; LCUI_Rect quote_rect; Graph_Init( &buffer ); quote_rect = read_rect; /* 根据宽高的缩放比例,计算实际需要引用的区域 */ if( image_w != bg->image.w ) { scale = 1.0 * bg->image.width / image_w; quote_rect.x *= scale; quote_rect.width *= scale; } if( image_h != bg->image.h ) { scale = 1.0 * bg->image.height / image_h; quote_rect.y *= scale; quote_rect.height *= scale; } /* 引用源背景图像的一块区域 */ Graph_Quote( &graph, &bg->image, "e_rect ); image_w = read_rect.width; image_h = read_rect.height; /* 计算相对于绘制区域的坐标 */ image_x = read_rect.x + image_x; image_x = image_x + box->x - paint->rect.x; image_y = read_rect.y + image_y; image_y = image_y + box->y - paint->rect.y; /* 按比例进行缩放 */ Graph_Zoom( &graph, &buffer, FALSE, image_w, image_h ); Graph_Mix( &paint->canvas, &buffer, image_x, image_y, with_alpha ); Graph_Free( &buffer ); } }
static LCUI_WidgetRenderer WidgetRenderer( LCUI_Widget w, LCUI_PaintContext paint, LCUI_WidgetRenderer parent ) { LCUI_RectF rect; ASSIGN( that, LCUI_WidgetRenderer ); that->target = w; that->paint = paint; that->is_cover_border = FALSE; that->has_self_graph = FALSE; that->has_layer_graph = FALSE; that->has_content_graph = FALSE; if( parent ) { that->root_paint = parent->root_paint; that->x = parent->x + parent->content_left + w->box.graph.x; that->y = parent->y + parent->content_top + w->box.graph.y; } else { that->x = that->y = 0; that->root_paint = that->paint; } /* 若部件本身是透明的 */ if( w->computed_style.opacity < 1.0 ) { that->has_self_graph = TRUE; that->has_content_graph = TRUE; that->has_layer_graph = TRUE; } else { /* 若使用了圆角边框,则判断当前脏矩形区域是否在圆角边框内 ... if( ... ) { that->has_content_graph = TRUE; that->is_cover_border = TRUE; } */ } Graph_Init( &that->self_graph ); Graph_Init( &that->layer_graph ); Graph_Init( &that->content_graph ); that->layer_graph.color_type = COLOR_TYPE_ARGB; that->can_render_self = Widget_IsPaintable( w ); if( that->can_render_self ) { that->self_graph.color_type = COLOR_TYPE_ARGB; Graph_Create( &that->self_graph, that->paint->rect.width, that->paint->rect.height ); } /* 获取内容框相对于图层的间距 */ that->content_left = w->box.padding.x - w->box.graph.x; that->content_top = w->box.padding.y - w->box.graph.y; /* 获取内容区域,相对于根级部件 */ rect.x = that->x + that->content_left; rect.y = that->y + that->content_top; rect.width = w->box.padding.width; rect.height = w->box.padding.height; /* 栅格化内容区域 */ LCUIMetrics_ComputeRectActual( &that->content_rect, &rect ); rect.x -= that->x; rect.y -= that->y; LCUIMetrics_ComputeRectActual( &that->content_paint_rect, &rect ); /* 获取内容区域中实际需要绘制的区域 */ that->can_render_centent = LCUIRect_GetOverlayRect( &that->content_paint_rect, &that->paint->rect, &that->content_paint_rect ); /* 转换坐标为相对于绘制区域 */ that->content_paint_rect.x -= that->paint->rect.x; that->content_paint_rect.y -= that->paint->rect.y; if( !that->can_render_centent ) { return that; } /* 若需要部件内容区的位图缓存 */ if( that->has_content_graph ) { that->content_graph.color_type = COLOR_TYPE_ARGB; Graph_Create( &that->content_graph, that->content_paint_rect.width, that->content_paint_rect.height ); } return that; }
/** 绘制边框 */ int Graph_DrawBorder( LCUI_PaintContext paint, LCUI_Rect *box, LCUI_Border *border ) { int radius; LCUI_Rect bound; LCUI_Pos start, end; LCUI_Graph canvas; if( !Graph_IsValid(&paint->canvas) ) { return -1; } /* 绘制上边框线 */ bound.x = box->x + border->top_left_radius; bound.y = box->y; bound.width = box->width - border->top_right_radius; bound.width -= border->top_left_radius; bound.height = border->top.width; if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { bound.x -= paint->rect.x; bound.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &bound ); Graph_FillColor( &canvas, border->top.color ); } /* 绘制下边框线 */ bound.x = box->x; bound.y = box->y + box->height - border->bottom.width; bound.width = box->width - border->bottom_right_radius; bound.width -= border->bottom_left_radius; bound.height = border->bottom.width; if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { bound.x -= paint->rect.x; bound.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &bound ); Graph_FillColor( &canvas, border->bottom.color ); } /* 绘制左边框线 */ bound.y = box->y + border->top_left_radius; bound.x = box->x; bound.width = border->left.width; bound.height = box->height - border->top_left_radius; bound.height -= border->bottom_left_radius; if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { bound.x -= paint->rect.x; bound.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &bound ); Graph_FillColor( &canvas, border->left.color ); } /* 绘制右边框线 */ bound.x = box->x + box->width - border->right.width; bound.y = box->y + border->top_right_radius; bound.width = border->right.width; bound.height = box->height - border->top_right_radius; bound.height -= border->bottom_right_radius; if( LCUIRect_GetOverlayRect( &bound, &paint->rect, &bound ) ) { bound.x -= paint->rect.x; bound.y -= paint->rect.y; Graph_Quote( &canvas, &paint->canvas, &bound ); Graph_FillColor( &canvas, border->right.color ); } return 0; }