static void AsyncLoadImage( LCUI_Widget widget, const char *path ) { ImageCache cache; LCUI_Task task = {0}; LCUI_Style *s = &widget->cached_style->sheet[key_background_image]; if( !is_inited ) { RBTree_Init( &images ); RBTree_Init( &refs ); RBTree_OnJudge( &refs, OnCompareWidget ); RBTree_OnJudge( &images, OnComparePath ); RBTree_OnDestroy( &refs, free ); RBTree_OnDestroy( &images, OnDestroyCache ); is_inited = TRUE; } if( s->is_valid && s->type == SVT_STRING ) { cache = RBTree_CustomGetData( &images, s->string ); if( cache ) { DelRef( widget, cache ); } } cache = RBTree_CustomGetData( &images, path ); if( cache ) { AddRef( widget, cache ); Graph_Quote( &widget->computed_style.background.image, &cache->image, NULL ); Widget_AddTask( widget, WTT_BODY ); return; } task.func = ExecLoadImage; task.arg[0] = widget; task.arg[1] = strdup( path ); LCUI_AddTask( &task ); }
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 ); } }
int Graph_Replace( LCUI_Graph *back, const LCUI_Graph *fore, LCUI_Pos pos ) { LCUI_Graph write_slot; LCUI_Rect read_rect,write_rect; if( !Graph_IsValid(back) || !Graph_IsValid(fore) ) { return -1; } write_rect.x = pos.x; write_rect.y = pos.y; write_rect.width = fore->width; write_rect.height = fore->height; Graph_Quote( &write_slot, back, &write_rect ); Graph_GetValidRect( &write_slot, &write_rect ); Graph_GetValidRect( fore, &read_rect ); if( write_rect.width <= 0 || write_rect.height <= 0 || read_rect.width <= 0 || read_rect.height <= 0 ) { return -2; } pos.x = read_rect.x; pos.y = read_rect.y; fore = Graph_GetQuote( fore ); back = Graph_GetQuote( back ); switch( fore->color_type ) { case COLOR_TYPE_RGB888: return Graph_RGBReplaceRGB( back, write_rect, fore, pos ); case COLOR_TYPE_ARGB8888: return Graph_ARGBReplaceARGB( back, write_rect, fore, pos ); default:break; } return -1; }
int Graph_FillRectRGB( LCUI_Graph *graph, LCUI_Color color, LCUI_Rect rect ) { int x, y; LCUI_Graph canvas; uchar_t *rowbytep, *bytep; if(!Graph_IsValid(graph)) { return -1; } Graph_Quote( &canvas, graph, &rect ); Graph_GetValidRect( &canvas, &rect ); graph = Graph_GetQuote( &canvas ); rowbytep = graph->bytes + rect.y*graph->bytes_per_row; rowbytep += rect.x*graph->bytes_per_pixel; for( y=0; y<rect.h; ++y ) { bytep = rowbytep; for( x=0; x<rect.w; ++x ) { *bytep++ = color.blue; *bytep++ = color.green; *bytep++ = color.red; } rowbytep += graph->bytes_per_row; } return 0; }
int Graph_Mix( LCUI_Graph *back, const LCUI_Graph *fore, LCUI_Pos pos ) { LCUI_Graph write_slot; LCUI_Rect read_rect, write_rect; void (*mixer)(LCUI_Graph*, LCUI_Rect, const LCUI_Graph *, LCUI_Pos) = NULL; /* 预先进行有效性判断 */ if( !Graph_IsValid(back) || !Graph_IsValid(fore) ) { return -1; } write_rect.x = pos.x; write_rect.y = pos.y; write_rect.width = fore->width; write_rect.height = fore->height; LCUIRect_GetCutArea( Size( back->width, back->height ), write_rect, &read_rect ); write_rect.x += read_rect.x; write_rect.y += read_rect.y; write_rect.width = read_rect.width; write_rect.height = read_rect.height; Graph_Quote( &write_slot, back, &write_rect ); /* 获取实际操作区域 */ Graph_GetValidRect( &write_slot, &write_rect ); Graph_GetValidRect( fore, &read_rect ); /* 若读或写的区域无效 */ if( write_rect.width <= 0 || write_rect.height <= 0 || read_rect.width <= 0 || read_rect.height <= 0 ) { return -2; } pos.x = read_rect.x; pos.y = read_rect.y; /* 获取引用的源图像 */ fore = Graph_GetQuote( fore ); back = Graph_GetQuote( back ); switch( fore->color_type ) { case COLOR_TYPE_RGB888: if( back->color_type == COLOR_TYPE_RGB888 ) { mixer = Graph_RGBReplaceRGB; } else { mixer = Graph_ARGBReplaceRGB; } break; case COLOR_TYPE_ARGB8888: if( back->color_type == COLOR_TYPE_RGB888 ) { mixer = Graph_RGBMixARGB; } else { mixer = Graph_ARGBMixARGB; } default:break; } if( mixer ) { mixer( back, write_rect, fore, pos ); return 0; } return -3; }
/** 计算背景样式 */ void Widget_ComputeBackgroundStyle( LCUI_Widget widget ) { LCUI_Style *s; LCUI_StyleSheet ss = widget->style; LCUI_Background *bg = &widget->computed_style.background; int key = key_background_start + 1; for( ; key < key_background_end; ++key ) { s = &ss->sheet[key]; if( !s->is_valid ) { continue; } switch( key ) { case key_background_color: bg->color = s->color; break; case key_background_image: switch( s->type ) { case SVT_IMAGE: if( !s->image ) { Graph_Init( &bg->image ); break; } Graph_Quote( &bg->image, s->image, NULL ); break; case SVT_STRING: AsyncLoadImage( widget, s->string ); default: break; } break; case key_background_position: bg->position.using_value = TRUE; bg->position.value = s->value; break; case key_background_position_x: bg->position.using_value = FALSE; bg->position.x = *s; break; case key_background_position_y: bg->position.using_value = FALSE; bg->position.y = *s; break; case key_background_size: bg->size.using_value = TRUE; bg->position.value = s->value; break; case key_background_size_width: bg->size.using_value = FALSE; bg->size.w = *s; break; case key_background_size_height: bg->size.using_value = FALSE; bg->size.h = *s; break; default: break; } } Widget_AddTask( widget, WTT_BODY ); }
LCUI_PaintContext LCUIPainter_Begin( LCUI_Graph *canvas, LCUI_Rect *rect ) { ASSIGN( paint, LCUI_PaintContext ); paint->rect = *rect; paint->with_alpha = FALSE; Graph_Init( &paint->canvas ); Graph_Quote( &paint->canvas, canvas, &paint->rect ); return paint; }
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; }
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 ); } }
/** 清除已记录的无效矩形 */ void TextLayer_ClearInvalidRect( LCUI_TextLayer layer ) { LinkedListNode *node; LCUI_Graph invalid_graph; if( !layer->is_using_buffer ) { RectList_Clear( &layer->dirty_rect ); return; } for( LinkedList_Each( node, &layer->dirty_rect ) ) { Graph_Quote( &invalid_graph, &layer->graph, node->data ); Graph_FillAlpha( &invalid_graph, 0 ); } RectList_Clear( &layer->dirty_rect ); }
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 ); } }
static void ExecLoadImage( void *arg1, void *arg2 ) { char *path = arg2; LCUI_Graph image; LCUI_Widget widget = arg1; ImageCache cache; Graph_Init( &image ); if( Graph_LoadImage( path, &image ) != 0 ) { return; } cache = NEW(ImageCacheRec, 1); cache->ref_count = 0; cache->image = image; cache->path = path; RBTree_CustomInsert( &images, path, cache ); AddRef( widget, cache ); Graph_Quote( &widget->computed_style.background.image, &cache->image, NULL ); Widget_AddTask( widget, WTT_BODY ); }
Resize_Frames(LCUI_Frames *p, LCUI_Size new_size) /* 功能:调整动画的容器尺寸 */ { int i, total; LCUI_Pos pos; LCUI_Frame *frame; LCUI_Graph *graph; LCUI_Size size; if(new_size.w <= 0 || new_size.h <= 0) { return -1; } if( !p ) { return -2; } p->size = new_size; total = Queue_GetTotal(&p->pic); for(i=0; i<total; ++i){ frame = Queue_Get(&p->pic, i); graph = frame->pic->src; size = Graph_GetSize(graph); pos = Frames_GetFrameMixPos(p, frame); if(pos.x+size.w > new_size.w){ size.w = new_size.w - pos.x; size.w<0 ? size.w=0 :1; } if(pos.y+size.h > new_size.h){ size.h = new_size.h - pos.y; size.h<0 ? size.h=0 :1; } Graph_Quote(frame->pic, graph, Rect(0,0,size.w, size.h)); } Graph_Create(&p->slot, new_size.w, new_size.h); Frames_UpdateGraphSlot( p, p->current ); Frames_CallFunc( p ); return 0; }
/** 清除已记录的无效矩形 */ void TextLayer_ClearInvalidRect( LCUI_TextLayer *layer ) { int n; LCUI_Rect *rect_ptr; LCUI_Graph invalid_graph; if( !layer->is_using_buffer ) { DirtyRectList_Destroy( &layer->dirty_rect ); DirtyRectList_Init( &layer->dirty_rect ); return; } n = LinkedList_GetTotal( &layer->dirty_rect ); LinkedList_Goto( &layer->dirty_rect, 0 ); while(n--) { rect_ptr = (LCUI_Rect*)LinkedList_Get( &layer->dirty_rect ); Graph_Quote( &invalid_graph, &layer->graph, rect_ptr ); Graph_FillAlpha( &invalid_graph, 0 ); LinkedList_ToNext( &layer->dirty_rect ); } DirtyRectList_Destroy( &layer->dirty_rect ); DirtyRectList_Init( &layer->dirty_rect ); }
/** 绘制边框 */ 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; }
TextLayer_Draw( LCUI_Widget *widget, LCUI_TextLayer *layer, int mode ) /* 将文本图层绘制到目标部件的图层上 */ { LCUI_Rect area; LCUI_Pos pos, mix_pos; LCUI_BOOL draw_all = FALSE, redraw_row; int i, j, n, rows, size; LCUI_RGB color; LCUI_Graph slot, *graph; LCUI_CharData *p_data; Text_RowData *p_row; //clock_t start; //start = clock(); //_DEBUG_MSG("enter\n"); graph = Widget_GetSelfGraph( widget ); /* 如果文本缓存区内有数据 */ if( layer->need_proc_buff ) { __TextLayer_Text( layer ); layer->need_proc_buff = FALSE; } /* 如果需要滚动图层 */ if( layer->need_scroll_layer ) { layer->need_scroll_layer = FALSE; //_DEBUG_MSG("layer->need_scroll_layer\n"); /* 根据之前记录的偏移坐标,刷新文本图层 */ __TextLayer_OldArea_Erase( layer, Widget_GetSelfGraph( widget ) ); draw_all = TRUE; } //_DEBUG_MSG("1, use time: %ld\n", clock() - start ); //start = clock(); Graph_Init( &slot ); /* 先处理需要清空的区域 */ n = Queue_GetTotal( &layer->clear_area ); for(i=0; i<n; ++i) { RectQueue_Get( &area, 0 , &layer->clear_area ); area.x += layer->offset_pos.x; area.y += layer->offset_pos.y; Queue_Delete( &layer->clear_area, 0 ); Graph_Quote( &slot, graph, area ); /* 将该区域的alpha通道填充为0 */ Graph_FillAlpha( &slot, 0 ); Widget_InvalidArea( widget, area ); //printf("refresh area: %d,%d,%d,%d\n", //area.x, area.y, area.width, area.height); } //_DEBUG_MSG("2, use time: %ld\n", clock() - start ); //start = clock(); /* 开始绘制文本位图至目标图层上 */ rows = Queue_GetTotal( &layer->rows_data ); for(pos.y=layer->offset_pos.y,i=0; i<rows; ++i) { redraw_row = FALSE; p_row = Queue_Get( &layer->rows_data, i ); if( !p_row ) { continue; } n = Queue_GetTotal( &p_row->string ); /* 如果当前字的位图的Y轴跨距不在有效绘制区域内 */ if( pos.y + p_row->max_size.h <= 0 ) { pos.y += p_row->max_size.h; continue; } for(pos.x=layer->offset_pos.x,j=0; j<n; ++j) { /* 如果设置了屏蔽符 */ p_data = Queue_Get( &p_row->string, j ); if( !p_data ) { continue; } if( layer->password_char.char_code > 0 ) { layer->password_char.need_update = p_data->need_update; p_data = &layer->password_char; } /* 如果当前字的位图的X轴跨距不在有效绘制区域内 */ if( pos.x + p_data->bitmap->advance.x <= 0) { pos.x += p_data->bitmap->advance.x; continue; } /* 获取该字体位图的大致尺寸 */ if( p_data->data ) { size = p_data->data->pixel_size; size += 2; color = p_data->data->fore_color; } else { size = layer->default_data.pixel_size + 2; color = layer->default_data.fore_color; } /* 如果字体位图已标记更新,则绘制它 */ if( p_data->need_update || draw_all ) { p_data->need_update = FALSE; if( !redraw_row ) { area.x = pos.x; area.height = p_row->max_size.h; redraw_row = TRUE; } mix_pos.x = pos.x + p_data->bitmap->left; mix_pos.y = pos.y + p_row->max_size.h-1; mix_pos.y -= p_data->bitmap->top; /* 贴上字体位图 */ FontBMP_Mix( graph, mix_pos, p_data->bitmap, color, mode ); } pos.x += p_data->bitmap->advance.x; if( pos.x > widget->size.w ) { break; } } if(redraw_row) { area.y = pos.y; area.width = pos.x - area.x; //_DEBUG_MSG("area:%d,%d,%d,%d\n", //area.x, area.y, area.width, area.height); Widget_InvalidArea( widget, area ); } pos.y += p_row->max_size.h; if( pos.y > widget->size.h ) { break; } } //_DEBUG_MSG("3, use time: %ld\n", clock() - start ); //_DEBUG_MSG("quit\n"); }
static void DrawCircle( LCUI_Graph *graph, LCUI_Pos center, int r, LCUI_ARGB color ) { int x, y; int t = r; int s = 255; float v = 512.0/t; float a = 2*(v*t-s)/(t*t); LCUI_Rect area, box_rect; LCUI_Graph *src, box_graph; LCUI_ARGB tmp_px, *px; uchar_t *px_row_bytes; LCUI_Rect2 circle; tmp_px = color; Graph_GetValidRect( graph, &area ); src = Graph_GetQuote( graph ); center.x += area.x; center.y += area.y; circle.r = center.x + r; circle.l = center.x - r; circle.b = center.y + r; circle.t = center.y - r; /* 先填充 圆外切矩形 外的矩形区域 */ box_rect.x = area.x; box_rect.y = area.y; box_rect.w = area.w; box_rect.h = circle.t - area.y; Graph_Quote( &box_graph, src, &box_rect ); Graph_FillAlpha( &box_graph, 0 ); box_rect.y = circle.t; box_rect.w = circle.l - area.x; box_rect.h = area.y + area.h - circle.t; Graph_Quote( &box_graph, src, &box_rect ); Graph_FillAlpha( &box_graph, 0 ); /* 调整圆的区域 */ if( circle.l < area.x ) { circle.l = area.x; } if( circle.t < area.y ) { circle.t = area.y; } if( circle.r > area.x + area.w ) { circle.r = area.x + area.w; } if( circle.b > area.y + area.h ) { circle.b = area.y + area.h; } if( src->color_type != COLOR_TYPE_ARGB ) { return; } px_row_bytes = src->bytes + circle.top*src->bytes_per_row; px_row_bytes += circle.left * src->bytes_per_pixel; /* 遍历区域内每个像素点,根据点到圆心的距离,计算其alpha透明度 */ for( y=circle.top; y<circle.bottom; ++y ) { px = (LCUI_ARGB*)px_row_bytes; for( x=circle.left; x<circle.right; ++x ) { t = (y-center.y)*(y-center.y); t += (x-center.x)*(x-center.x); t = (int)((double)sqrt(1.0*t)+0.5); if( t <= r ) { tmp_px.a = (uchar_t)(s-(v*t-(a*t*t)/2)); tmp_px.a *= color.a/255.0; } else { tmp_px.alpha = 0; } *px++ = tmp_px; } px_row_bytes += src->bytes_per_row; } }
/** * 渲染指定部件呈现的图形内容 * @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; }
/* 在PictureBox部件更新时进行附加处理 */ static void PictureBox_ExecUpdate(LCUI_Widget *widget) { LCUI_Pos pos; LCUI_PictureBox *pic_box; LCUI_Graph graph, *widget_graph, *p; pos = Pos(0,0); Graph_Init(&graph); pic_box = (LCUI_PictureBox*)Widget_GetPrivData(widget); widget_graph = Widget_GetSelfGraph( widget ); //print_widget_info(widget); //Graph_PrintInfo(widget_graph); //Graph_PrintInfo(pic_box->image); //printf("PictureBox_ExecUpdate(): 1\n"); if(! Graph_IsValid(pic_box->image)) { return; } //printf("PictureBox_ExecUpdate(): widget size: w: %d, h: %d\n", widget->size.w, widget->size.h); //printf("PictureBox_ExecUpdate(): read box: %d,%d,%d,%d\n", //pic_box->read_box.x, pic_box->read_box.y, //pic_box->read_box.width, pic_box->read_box.height); switch(pic_box->size_mode) { case SIZE_MODE_BLOCK_ZOOM: case SIZE_MODE_ZOOM: /* 裁剪图像 */ if(pic_box->scale == 1.00) p = pic_box->image; else p = &pic_box->buff_graph; if(! Graph_IsValid(p)) { //printf("! Graph_IsValid(p)\n"); return; } pos.x = (widget->size.w - pic_box->read_box.width)/2.0; pos.y = (widget->size.h - pic_box->read_box.height)/2.0; /* 引用图像中指定区域的图形 */ Graph_Quote(&graph, p, pic_box->read_box); break; case SIZE_MODE_NORMAL:/* 正常模式 */ Graph_Quote(&graph, pic_box->image, pic_box->read_box); break; case SIZE_MODE_STRETCH:/* 拉伸模式 */ /* 开始缩放图片 */ Graph_Zoom( pic_box->image, &graph, FALSE, widget->size ); break; case SIZE_MODE_TILE:/* 平铺模式 */ Graph_Tile( pic_box->image, &graph, TRUE ); break; case SIZE_MODE_CENTER: /* 判断图像的尺寸是否小于图片盒子的尺寸,并计算坐标位置 */ if(pic_box->image->w < widget->size.w) { pic_box->read_box.x = 0; pic_box->read_box.width = pic_box->image->w; pos.x = (widget->size.w - pic_box->image->w)/2 + 0.5; } if(pic_box->image->h < widget->size.h) { pos.y = (widget->size.h - pic_box->image->h)/2 + 0.5; pic_box->read_box.y = 0; pic_box->read_box.height = pic_box->image->h; } if(pic_box->read_box.y + pic_box->read_box.height >= pic_box->image->h) /* 如果读取区域的尺寸大于图片尺寸 */ pic_box->read_box.y = pic_box->image->h - pic_box->read_box.height; if(pic_box->read_box.x + pic_box->read_box.width >= pic_box->image->w) pic_box->read_box.x = pic_box->image->w - pic_box->read_box.width; Graph_Quote(&graph, pic_box->image, pic_box->read_box); break; default : break; } // 用于调试 //printf("PictureBox_ExecUpdate(): read box: %d,%d,%d,%d; %d/%d, %d/%d\n", //pic_box->read_box.x, pic_box->read_box.y, //pic_box->read_box.width, pic_box->read_box.height, //pic_box->read_box.x + pic_box->read_box.width, pic_box->buff_graph.w, //pic_box->read_box.y + pic_box->read_box.height, pic_box->buff_graph.h); if(!Graph_IsValid(&widget->background.image)) { Graph_Replace( widget_graph, &graph, pos ); } else { Graph_Mix( widget_graph, &graph, pos ); } Graph_Free(&graph); //printf("scale: %.4f\n", pic_box->scale); //printf("PictureBox_ExecUpdate(): end\n"); Widget_Refresh(widget); }
LCUI_API int Graph_DrawBorder( LCUI_Graph *des, LCUI_Border border ) /* 简单的为图形边缘绘制边框 */ { int radius; LCUI_Rect rect; LCUI_Pos start, end; LCUI_Graph des_area; if( !Graph_IsValid(des) ) { return -1; } /* 绘制左上角的圆角,先引用左上角区域,再将圆绘制到这个区域里 */ radius = border.top_left_radius; rect = Rect( 0, 0, radius, radius ); Graph_Quote( &des_area, des, rect ); Graph_Draw_RoundBorder_LeftTop( &des_area , Pos( radius, radius ), radius , border.left_width, border.left_color , TRUE ); Graph_Draw_RoundBorder_TopLeft( &des_area , Pos( radius, radius ), radius , border.top_width, border.top_color , TRUE ); /* 右上角 */ radius = border.top_right_radius; rect = Rect( des->width-radius-1, 0, radius, radius ); Graph_Quote( &des_area, des, rect ); Graph_Draw_RoundBorder_RightTop( &des_area , Pos( 0, radius ), radius , border.right_width, border.right_color , TRUE ); Graph_Draw_RoundBorder_TopRight( &des_area , Pos( 0, radius ), radius , border.top_width, border.top_color , TRUE ); /* 左下角 */ radius = border.bottom_left_radius; rect = Rect( 0, des->height-radius-1, radius, radius ); Graph_Quote( &des_area, des, rect ); Graph_Draw_RoundBorder_LeftBottom( &des_area , Pos( radius, 0 ), radius , border.left_width, border.left_color , TRUE ); Graph_Draw_RoundBorder_BottomLeft( &des_area , Pos( radius, 0 ), radius , border.bottom_width, border.bottom_color , TRUE ); /* 右下角 */ radius = border.bottom_left_radius; rect = Rect( des->width-radius-1, des->height-radius-1, radius, radius ); Graph_Quote( &des_area, des, rect ); Graph_Draw_RoundBorder_RightBottom( &des_area , Pos( 0, 0 ), radius , border.right_width, border.right_color , TRUE ); Graph_Draw_RoundBorder_BottomRight( &des_area , Pos( 0, 0 ), radius , border.bottom_width, border.bottom_color , TRUE ); start.x = border.top_left_radius; start.y = 0; end.x = des->width - border.top_right_radius; /* 绘制上边框 */ Graph_DrawHorizLine( des, border.top_color, border.top_width, start, end.x ); /* 绘制下边的线 */ start.y = des->height - border.bottom_width; end.x = des->width - border.bottom_right_radius; Graph_DrawHorizLine( des, border.top_color, border.bottom_width, start, end.x ); /* 绘制左边的线 */ start.x = start.y = 0; end.y = des->height - border.bottom_left_radius; Graph_DrawVertiLine( des, border.left_color, border.left_width, start, end.y ); /* 绘制右边的线 */ start.x = des->width - border.right_width; start.y = border.top_right_radius; end.y = des->height - border.bottom_right_radius; Graph_DrawVertiLine( des, border.right_color, border.right_width, start, end.y ); /* 边框线绘制完成 */ return 0; }
LCUI_API int GraphLayer_GetGraph( LCUI_GraphLayer *ctnr, LCUI_Graph *graph_buff, LCUI_Rect rect ) { int i, total; uchar_t tmp_alpha, alpha; LCUI_Pos pos, glayer_pos; LCUI_GraphLayer *glayer; LCUI_Queue glayerQ; LCUI_Rect valid_area; LCUI_Graph tmp_graph; /* 检测这个区域是否有效 */ if (rect.x < 0 || rect.y < 0) { return -1; } if (rect.x + rect.width > ctnr->graph.w || rect.y + rect.height > ctnr->graph.h ) { return -1; } if (rect.width <= 0 || rect.height <= 0) { return -2; } if( !Graph_IsValid(graph_buff) ) { graph_buff->color_type = COLOR_TYPE_ARGB; Graph_Create( graph_buff, rect.width, rect.height ); } Graph_Init( &tmp_graph ); Queue_Init( &glayerQ, 0, NULL); Queue_UsingPointer( &glayerQ ); /* 获取rect区域内的图层列表 */ GraphLayer_GetLayers( ctnr, rect, &glayerQ ); total = Queue_GetTotal( &glayerQ ); DEBUG_MSG( "total: %d\n", total ); /* 若记录数为零,则表明该区域没有图层 */ if( total <= 0 ) { /* 若没有父图层,则填充白色 */ if( ctnr == NULL ) { Graph_FillColor( graph_buff, RGB(255,255,255) ); } else { /* 否则使用父图层的图形 */ Graph_Cut( &ctnr->graph, rect, graph_buff ); } /* 销毁记录 */ Queue_Destroy( &glayerQ ); return 0; } /* 从顶层到底层遍历图层,排除被其它图层完全遮挡或者自身完全透明的图层 */ for(i=total-1; i>=0; --i) { glayer = (LCUI_GraphLayer*)Queue_Get( &glayerQ, i ); valid_area = GraphLayer_GetValidRect( ctnr, glayer ); glayer_pos = GraphLayer_GetGlobalPos( ctnr, glayer ); valid_area.x += glayer_pos.x; valid_area.y += glayer_pos.y; alpha = GraphLayer_GetRealAlpha( glayer ); /* 当前图层的透明度小于255的话,就跳过 */ if( alpha < 255 ) { continue; } /* 跳过有alpha通道的图层 */ if( glayer->graph.color_type == COLOR_TYPE_ARGB ) { continue; } /* 如果该图层的有效区域包含目标区域 */ if( rect.x >= valid_area.x && rect.y >= valid_area.y && rect.x + rect.w <= valid_area.x + valid_area.w && rect.y + rect.h <= valid_area.y + valid_area.h ) { /* 移除底层的图层,因为已经被完全遮挡 */ for(total=i-1;total>=0; --total) { Queue_DeletePointer( &glayerQ, 0 ); } goto skip_loop; } } skip_loop: total = Queue_GetTotal( &glayerQ ); DEBUG_MSG( "total: %d\n", total ); if(i <= 0 && ctnr ) { Graph_Cut( &ctnr->graph, rect, graph_buff ); } /* 获取图层列表中的图层 */ for(i=0; i<total; ++i) { glayer = (LCUI_GraphLayer*)Queue_Get( &glayerQ, i ); //_DEBUG_MSG("%p = Queue_Get( %p, %d )\n", glayer, &glayerQ, i); if( !glayer ) { continue; } DEBUG_MSG("%d,%d,%d,%d\n", glayer->pos.x, glayer->pos.y, glayer->graph.w, glayer->graph.h); /* 获取该图层的有效区域及全局坐标 */ pos = GraphLayer_GetGlobalPos( ctnr, glayer ); valid_area = GraphLayer_GetValidRect( ctnr, glayer ); /* 引用该图层的有效区域内的图像 */ Graph_Quote( &tmp_graph, &glayer->graph, valid_area ); //_DEBUG_MSG("valid area: %d,%d,%d,%d, pos: %d,%d, size: %d,%d\n", // valid_area.x, valid_area.y, valid_area.width, valid_area.height, // pos.x, pos.y, glayer->graph.w, glayer->graph.h // ); /* 获取相对坐标 */ pos.x = pos.x - rect.x + valid_area.x; pos.y = pos.y - rect.y + valid_area.y; //_DEBUG_MSG("mix pos: %d,%d\n", pos.x, pos.y); /* 如果该图层没有继承父图层的透明度 */ if( !glayer->inherit_alpha ) { /* 直接叠加至graph_buff */ Graph_Mix( graph_buff, &tmp_graph, pos ); } else { /* 否则,计算该图层应有的透明度 */ alpha = GraphLayer_GetRealAlpha( glayer ); /* 备份该图层的全局透明度 */ tmp_alpha = glayer->graph.alpha; /* 将实际透明度作为全局透明度,参与图像叠加 */ glayer->graph.alpha = alpha; Graph_Mix( graph_buff, &tmp_graph, pos ); /* 还原全局透明度 */ glayer->graph.alpha = tmp_alpha; } } Queue_Destroy( &glayerQ ); return 0; }
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 ); } }