📄 cairo-win32-surface.c
字号:
}static void_cairo_win32_surface_release_source_image (void *abstract_surface, cairo_image_surface_t *image, void *image_extra){ cairo_win32_surface_t *local = image_extra; if (local) cairo_surface_destroy ((cairo_surface_t *)local);}static cairo_status_t_cairo_win32_surface_acquire_dest_image (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t **image_out, cairo_rectangle_int16_t *image_rect, void **image_extra){ cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *local = NULL; cairo_status_t status; RECT clip_box; int x1, y1, x2, y2; if (surface->image) { GdiFlush(); image_rect->x = 0; image_rect->y = 0; image_rect->width = surface->clip_rect.width; image_rect->height = surface->clip_rect.height; *image_out = (cairo_image_surface_t *)surface->image; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } if (GetClipBox (surface->dc, &clip_box) == ERROR) return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image"); x1 = clip_box.left; x2 = clip_box.right; y1 = clip_box.top; y2 = clip_box.bottom; if (interest_rect->x > x1) x1 = interest_rect->x; if (interest_rect->y > y1) y1 = interest_rect->y; if (interest_rect->x + interest_rect->width < x2) x2 = interest_rect->x + interest_rect->width; if (interest_rect->y + interest_rect->height < y2) y2 = interest_rect->y + interest_rect->height; if (x1 >= x2 || y1 >= y2) { *image_out = NULL; *image_extra = NULL; return CAIRO_STATUS_SUCCESS; } status = _cairo_win32_surface_get_subimage (abstract_surface, x1, y1, x2 - x1, y2 - y1, &local); if (status) return status; *image_out = (cairo_image_surface_t *)local->image; *image_extra = local; image_rect->x = x1; image_rect->y = y1; image_rect->width = x2 - x1; image_rect->height = y2 - y1; return CAIRO_STATUS_SUCCESS;}static void_cairo_win32_surface_release_dest_image (void *abstract_surface, cairo_rectangle_int16_t *interest_rect, cairo_image_surface_t *image, cairo_rectangle_int16_t *image_rect, void *image_extra){ cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *local = image_extra; if (!local) return; if (!BitBlt (surface->dc, image_rect->x, image_rect->y, image_rect->width, image_rect->height, local->dc, 0, 0, SRCCOPY)) _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image"); cairo_surface_destroy ((cairo_surface_t *)local);}#if !defined(AC_SRC_OVER)#define AC_SRC_OVER 0x00#pragma pack(1)typedef struct { BYTE BlendOp; BYTE BlendFlags; BYTE SourceConstantAlpha; BYTE AlphaFormat;}BLENDFUNCTION;#pragma pack()#endif/* for compatibility with VC++ 6 */#ifndef AC_SRC_ALPHA#define AC_SRC_ALPHA 0x01#endiftypedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int hHeightDest, HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, BLENDFUNCTION blendFunction);static cairo_int_status_t_composite_alpha_blend (cairo_win32_surface_t *dst, cairo_win32_surface_t *src, int alpha, int src_x, int src_y, int dst_x, int dst_y, int width, int height){ static unsigned alpha_blend_checked = FALSE; static cairo_alpha_blend_func_t alpha_blend = NULL; BLENDFUNCTION blend_function; /* Check for AlphaBlend dynamically to allow compiling on * MSVC 6 and use on older windows versions */ if (!alpha_blend_checked) { OSVERSIONINFO os; os.dwOSVersionInfoSize = sizeof (os); GetVersionEx (&os); /* If running on Win98, disable using AlphaBlend() * to avoid Win98 AlphaBlend() bug */ if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId || os.dwMajorVersion != 4 || os.dwMinorVersion != 10) { HMODULE msimg32_dll = LoadLibrary ("msimg32"); if (msimg32_dll != NULL) alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll, "AlphaBlend"); } alpha_blend_checked = TRUE; } if (alpha_blend == NULL) return CAIRO_INT_STATUS_UNSUPPORTED; if (GetDeviceCaps(dst->dc, SHADEBLENDCAPS) == SB_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; blend_function.BlendOp = AC_SRC_OVER; blend_function.BlendFlags = 0; blend_function.SourceConstantAlpha = alpha; blend_function.AlphaFormat = src->format == CAIRO_FORMAT_ARGB32 ? AC_SRC_ALPHA : 0; if (!alpha_blend (dst->dc, dst_x, dst_y, width, height, src->dc, src_x, src_y, width, height, blend_function)) return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); return CAIRO_STATUS_SUCCESS;}static cairo_int_status_t_cairo_win32_surface_composite (cairo_operator_t op, cairo_pattern_t *pattern, cairo_pattern_t *mask_pattern, void *abstract_dst, int src_x, int src_y, int mask_x, int mask_y, int dst_x, int dst_y, unsigned int width, unsigned int height){ cairo_win32_surface_t *dst = abstract_dst; cairo_win32_surface_t *src; cairo_surface_pattern_t *src_surface_pattern; int alpha; int integer_transform; int itx, ity; if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE || pattern->extend != CAIRO_EXTEND_NONE) return CAIRO_INT_STATUS_UNSUPPORTED; if (mask_pattern) { /* FIXME: When we fully support RENDER style 4-channel * masks we need to check r/g/b != 1.0. */ if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID) return CAIRO_INT_STATUS_UNSUPPORTED; alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8; } else { alpha = 255; } src_surface_pattern = (cairo_surface_pattern_t *)pattern; src = (cairo_win32_surface_t *)src_surface_pattern->surface; if (src->base.backend != dst->base.backend) return CAIRO_INT_STATUS_UNSUPPORTED; integer_transform = _cairo_matrix_is_integer_translation (&pattern->matrix, &itx, &ity); if (!integer_transform) return CAIRO_INT_STATUS_UNSUPPORTED; /* Fix up src coordinates; the src coords and size must be within the * bounds of the source surface. * XXX the region not covered should be appropriately rendered! * - for OVER/SOURCE with RGB24 source -> opaque black * - for SOURCE with ARGB32 source -> 100% transparent black */ src_x += itx; src_y += ity; if (src_x < 0) { width += src_x; dst_x -= src_x; src_x = 0; } if (src_y < 0) { height += src_y; dst_y -= src_y; src_y = 0; } if (src_x + width > src->extents.width) width = src->extents.width - src_x; if (src_y + height > src->extents.height) height = src->extents.height - src_y; if (alpha == 255 && (op == CAIRO_OPERATOR_SOURCE || (src->format == CAIRO_FORMAT_RGB24 && op == CAIRO_OPERATOR_OVER))) { if (!BitBlt (dst->dc, dst_x, dst_y, width, height, src->dc, src_x, src_y, SRCCOPY)) return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite"); return CAIRO_STATUS_SUCCESS; } else if ((src->format == CAIRO_FORMAT_RGB24 || src->format == CAIRO_FORMAT_ARGB32) && (dst->format == CAIRO_FORMAT_RGB24 || dst->format == CAIRO_FORMAT_ARGB32) && op == CAIRO_OPERATOR_OVER) { return _composite_alpha_blend (dst, src, alpha, src_x, src_y, dst_x, dst_y, width, height); } return CAIRO_INT_STATUS_UNSUPPORTED;}/* This big function tells us how to optimize operators for the * case of solid destination and constant-alpha source * * NOTE: This function needs revisiting if we add support for * super-luminescent colors (a == 0, r,g,b > 0) */static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }categorize_solid_dest_operator (cairo_operator_t op, unsigned short alpha){ enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source; if (alpha >= 0xff00) source = SOURCE_SOLID; else if (alpha < 0x100) source = SOURCE_TRANSPARENT; else source = SOURCE_OTHER; switch (op) { case CAIRO_OPERATOR_CLEAR: /* 0 0 */ case CAIRO_OPERATOR_OUT: /* 1 - Ab 0 */ return DO_CLEAR; break; case CAIRO_OPERATOR_SOURCE: /* 1 0 */ case CAIRO_OPERATOR_IN: /* Ab 0 */ return DO_SOURCE; break; case CAIRO_OPERATOR_OVER: /* 1 1 - Aa */ case CAIRO_OPERATOR_ATOP: /* Ab 1 - Aa */ if (source == SOURCE_SOLID) return DO_SOURCE; else if (source == SOURCE_TRANSPARENT) return DO_NOTHING; else return DO_UNSUPPORTED; break; case CAIRO_OPERATOR_DEST_OUT: /* 0 1 - Aa */ case CAIRO_OPERATOR_XOR: /* 1 - Ab 1 - Aa */ if (source == SOURCE_SOLID) return DO_CLEAR; else if (source == SOURCE_TRANSPARENT) return DO_NOTHING; else return DO_UNSUPPORTED; break; case CAIRO_OPERATOR_DEST: /* 0 1 */ case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab 1 */ case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa) 1 */ return DO_NOTHING; break; case CAIRO_OPERATOR_DEST_IN: /* 0 Aa */ case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab Aa */ if (source == SOURCE_SOLID) return DO_NOTHING; else if (source == SOURCE_TRANSPARENT) return DO_CLEAR; else return DO_UNSUPPORTED; break; case CAIRO_OPERATOR_ADD: /* 1 1 */ if (source == SOURCE_TRANSPARENT) return DO_NOTHING; else return DO_UNSUPPORTED; break; } ASSERT_NOT_REACHED; return DO_UNSUPPORTED;}static cairo_int_status_t_cairo_win32_surface_fill_rectangles (void *abstract_surface, cairo_operator_t op, const cairo_color_t *color, cairo_rectangle_int16_t *rects, int num_rects){ cairo_win32_surface_t *surface = abstract_surface; cairo_status_t status; COLORREF new_color; HBRUSH new_brush; int i; /* XXXperf If it's not RGB24, we need to do a little more checking * to figure out when we can use GDI. We don't have that checking * anywhere at the moment, so just bail and use the fallback * paths. */ if (surface->format != CAIRO_FORMAT_RGB24) return CAIRO_INT_STATUS_UNSUPPORTED; /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all * surfaces with alpha.) */ switch (categorize_solid_dest_operator (op, color->alpha_short)) { case DO_CLEAR: new_color = RGB (0, 0, 0); break; case DO_SOURCE: new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8); break; case DO_NOTHING: return CAIRO_STATUS_SUCCESS; case DO_UNSUPPORTED: default: return CAIRO_INT_STATUS_UNSUPPORTED; } new_brush = CreateSolidBrush (new_color); if (!new_brush) return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); for (i = 0; i < num_rects; i++) { RECT rect; rect.left = rects[i].x; rect.top = rects[i].y; rect.right = rects[i].x + rects[i].width; rect.bottom = rects[i].y + rects[i].height; if (!FillRect (surface->dc, &rect, new_brush)) goto FAIL; } DeleteObject (new_brush); return CAIRO_STATUS_SUCCESS; FAIL: status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles"); DeleteObject (new_brush);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -