📄 cairo-win32-surface.c
字号:
return status;}static cairo_int_status_t_cairo_win32_surface_set_clip_region (void *abstract_surface, pixman_region16_t *region){ cairo_win32_surface_t *surface = abstract_surface; cairo_status_t status; /* If we are in-memory, then we set the clip on the image surface * as well as on the underlying GDI surface. */ if (surface->image) { unsigned int serial; serial = _cairo_surface_allocate_clip_serial (surface->image); _cairo_surface_set_clip_region (surface->image, region, serial); } /* The semantics we want is that any clip set by cairo combines * is intersected with the clip on device context that the * surface was created for. To implement this, we need to * save the original clip when first setting a clip on surface. */ if (region == NULL) { /* Clear any clip set by cairo, return to the original */ if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)"); return CAIRO_STATUS_SUCCESS; } else { pixman_box16_t *boxes = pixman_region_rects (region); int num_boxes = pixman_region_num_rects (region); pixman_box16_t *extents = pixman_region_extents (region); RGNDATA *data; size_t data_size; RECT *rects; int i; HRGN gdi_region; /* Create a GDI region for the cairo region */ data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT); data = malloc (data_size); if (!data) return CAIRO_STATUS_NO_MEMORY; rects = (RECT *)data->Buffer; data->rdh.dwSize = sizeof (RGNDATAHEADER); data->rdh.iType = RDH_RECTANGLES; data->rdh.nCount = num_boxes; data->rdh.nRgnSize = num_boxes * sizeof (RECT); data->rdh.rcBound.left = extents->x1; data->rdh.rcBound.top = extents->y1; data->rdh.rcBound.right = extents->x2; data->rdh.rcBound.bottom = extents->y2; for (i = 0; i < num_boxes; i++) { rects[i].left = boxes[i].x1; rects[i].top = boxes[i].y1; rects[i].right = boxes[i].x2; rects[i].bottom = boxes[i].y2; } gdi_region = ExtCreateRegion (NULL, data_size, data); free (data); if (!gdi_region) return CAIRO_STATUS_NO_MEMORY; /* Combine the new region with the original clip */ if (surface->saved_clip) { if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR) goto FAIL; } if (SelectClipRgn (surface->dc, gdi_region) == ERROR) goto FAIL; DeleteObject (gdi_region); return CAIRO_STATUS_SUCCESS; FAIL: status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region"); DeleteObject (gdi_region); return status; }}static cairo_int_status_t_cairo_win32_surface_get_extents (void *abstract_surface, cairo_rectangle_int16_t *rectangle){ cairo_win32_surface_t *surface = abstract_surface; *rectangle = surface->extents; return CAIRO_STATUS_SUCCESS;}static cairo_status_t_cairo_win32_surface_flush (void *abstract_surface){ return _cairo_surface_reset_clip (abstract_surface);}#define STACK_GLYPH_SIZE 256static cairo_int_status_t_cairo_win32_surface_show_glyphs (void *surface, cairo_operator_t op, cairo_pattern_t *source, const cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font){ cairo_win32_surface_t *dst = surface; WORD glyph_buf_stack[STACK_GLYPH_SIZE]; WORD *glyph_buf = glyph_buf_stack; int dx_buf_stack[STACK_GLYPH_SIZE]; int *dx_buf = dx_buf_stack; BOOL win_result = 0; int i; double last_y = glyphs[0].y; cairo_solid_pattern_t *solid_pattern; COLORREF color; int output_count = 0; /* We can only handle win32 fonts */ if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32) return CAIRO_INT_STATUS_UNSUPPORTED; /* We can only handle opaque solid color sources */ if (!_cairo_pattern_is_opaque_solid(source)) return CAIRO_INT_STATUS_UNSUPPORTED; /* We can only handle operator SOURCE or OVER with the destination * having no alpha */ if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) || (dst->format != CAIRO_FORMAT_RGB24)) return CAIRO_INT_STATUS_UNSUPPORTED; /* If we have a fallback mask clip set on the dst, we have * to go through the fallback path */ if (dst->base.clip && (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION || dst->base.clip->surface != NULL)) return CAIRO_INT_STATUS_UNSUPPORTED; solid_pattern = (cairo_solid_pattern_t *)source; color = RGB(((int)solid_pattern->color.red_short) >> 8, ((int)solid_pattern->color.green_short) >> 8, ((int)solid_pattern->color.blue_short) >> 8); SaveDC(dst->dc); cairo_win32_scaled_font_select_font(scaled_font, dst->dc); SetTextColor(dst->dc, color); SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT); SetBkMode(dst->dc, TRANSPARENT); if (num_glyphs > STACK_GLYPH_SIZE) { glyph_buf = (WORD *)malloc(num_glyphs * sizeof(WORD)); dx_buf = (int *)malloc(num_glyphs * sizeof(int)); } for (i = 0; i < num_glyphs; ++i) { output_count++; glyph_buf[i] = glyphs[i].index; if (i == num_glyphs - 1) dx_buf[i] = 0; else dx_buf[i] = (glyphs[i+1].x - glyphs[i].x) * WIN32_FONT_LOGICAL_SCALE; if (i == num_glyphs - 1 || glyphs[i].y != glyphs[i+1].y) { const int offset = (i - output_count) + 1; win_result = ExtTextOutW(dst->dc, glyphs[offset].x * WIN32_FONT_LOGICAL_SCALE, last_y * WIN32_FONT_LOGICAL_SCALE, ETO_GLYPH_INDEX, NULL, glyph_buf + offset, output_count, dx_buf + offset); if (!win_result) { _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)"); goto FAIL; } output_count = 0; } last_y = glyphs[i].y; }FAIL: RestoreDC(dst->dc, -1); if (glyph_buf != glyph_buf_stack) { free(glyph_buf); free(dx_buf); } return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;}#undef STACK_GLYPH_SIZE/** * cairo_win32_surface_create: * @hdc: the DC to create a surface for * * Creates a cairo surface that targets the given DC. The DC will be * queried for its initial clip extents, and this will be used as the * size of the cairo surface. Also, if the DC is a raster DC, it will * be queried for its pixel format and the cairo surface format will * be set appropriately. * * Return value: the newly created surface **/cairo_surface_t *cairo_win32_surface_create (HDC hdc){ cairo_win32_surface_t *surface; RECT rect; int depth; cairo_format_t format; /* Try to figure out the drawing bounds for the Device context */ if (GetClipBox (hdc, &rect) == ERROR) { _cairo_win32_print_gdi_error ("cairo_win32_surface_create"); /* XXX: Can we make a more reasonable guess at the error cause here? */ _cairo_error (CAIRO_STATUS_NO_MEMORY); return &_cairo_surface_nil; } if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) { depth = GetDeviceCaps(hdc, BITSPIXEL); if (depth == 32) format = CAIRO_FORMAT_ARGB32; else if (depth == 24) format = CAIRO_FORMAT_RGB24; else if (depth == 16) format = CAIRO_FORMAT_RGB24; else if (depth == 8) format = CAIRO_FORMAT_A8; else if (depth == 1) format = CAIRO_FORMAT_A1; else { _cairo_win32_print_gdi_error("cairo_win32_surface_create(bad BITSPIXEL)"); _cairo_error (CAIRO_STATUS_NO_MEMORY); return &_cairo_surface_nil; } } else { format = CAIRO_FORMAT_RGB24; } surface = malloc (sizeof (cairo_win32_surface_t)); if (surface == NULL) { _cairo_error (CAIRO_STATUS_NO_MEMORY); return &_cairo_surface_nil; } surface->image = NULL; surface->format = format; surface->dc = hdc; surface->bitmap = NULL; surface->saved_dc_bitmap = NULL; surface->clip_rect.x = rect.left; surface->clip_rect.y = rect.top; surface->clip_rect.width = rect.right - rect.left; surface->clip_rect.height = rect.bottom - rect.top; if (surface->clip_rect.width == 0 || surface->clip_rect.height == 0) { surface->saved_clip = NULL; } else { surface->saved_clip = CreateRectRgn (0, 0, 0, 0); if (GetClipRgn (hdc, surface->saved_clip) == 0) { DeleteObject(surface->saved_clip); surface->saved_clip = NULL; } } surface->extents = surface->clip_rect; _cairo_surface_init (&surface->base, &cairo_win32_surface_backend, _cairo_content_from_format (format)); return (cairo_surface_t *)surface;}/** * cairo_win32_surface_create_with_dib: * @format: format of pixels in the surface to create * @width: width of the surface, in pixels * @height: height of the surface, in pixels * * Creates a device-independent-bitmap surface not associated with * any particular existing surface or device context. The created * bitmap will be unititialized. * * Return value: the newly created surface * * Since: 1.2 **/cairo_surface_t *cairo_win32_surface_create_with_dib (cairo_format_t format, int width, int height){ return _cairo_win32_surface_create_for_dc (NULL, format, width, height);}/** * _cairo_surface_is_win32: * @surface: a #cairo_surface_t * * Checks if a surface is an #cairo_win32_surface_t * * Return value: True if the surface is an win32 surface **/int_cairo_surface_is_win32 (cairo_surface_t *surface){ return surface->backend == &cairo_win32_surface_backend;}/** * cairo_win32_surface_get_dc * @surface: a #cairo_surface_t * * Returns the HDC associated with this surface, or NULL if none. * Also returns NULL if the surface is not a win32 surface. * * Return value: HDC or NULL if no HDC available. * * Since: 1.2 **/HDCcairo_win32_surface_get_dc (cairo_surface_t *surface){ cairo_win32_surface_t *winsurf; if (surface == NULL) return NULL; if (!_cairo_surface_is_win32(surface)) return NULL; winsurf = (cairo_win32_surface_t *) surface; return winsurf->dc;}static const cairo_surface_backend_t cairo_win32_surface_backend = { CAIRO_SURFACE_TYPE_WIN32, _cairo_win32_surface_create_similar, _cairo_win32_surface_finish, _cairo_win32_surface_acquire_source_image, _cairo_win32_surface_release_source_image, _cairo_win32_surface_acquire_dest_image, _cairo_win32_surface_release_dest_image, NULL, /* clone_similar */ _cairo_win32_surface_composite, _cairo_win32_surface_fill_rectangles, NULL, /* composite_trapezoids */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_win32_surface_set_clip_region, NULL, /* intersect_clip_path */ _cairo_win32_surface_get_extents, NULL, /* old_show_glyphs */ NULL, /* get_font_options */ _cairo_win32_surface_flush, NULL, /* mark_dirty_rectangle */ NULL, /* scaled_font_fini */ NULL, /* scaled_glyph_fini */ NULL, /* paint */ NULL, /* mask */ NULL, /* stroke */ NULL, /* fill */ _cairo_win32_surface_show_glyphs, NULL /* snapshot */};/* * Without pthread, on win32 we need to initialize all the 'mutex'es * before use. It is guaranteed that DllMain will get called single * threaded before any other function. * Initializing more than finally needed should not matter much. */#ifndef HAVE_PTHREAD_HCRITICAL_SECTION cairo_toy_font_face_hash_table_mutex;CRITICAL_SECTION cairo_scaled_font_map_mutex;CRITICAL_SECTION cairo_ft_unscaled_font_map_mutex;BOOL WINAPIDllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ switch (fdwReason) { case DLL_PROCESS_ATTACH: /* every 'mutex' from CAIRO_MUTEX_DECALRE needs to be initialized here */ InitializeCriticalSection (&cairo_toy_font_face_hash_table_mutex); InitializeCriticalSection (&cairo_scaled_font_map_mutex); InitializeCriticalSection (&cairo_ft_unscaled_font_map_mutex); break; case DLL_PROCESS_DETACH: DeleteCriticalSection (&cairo_toy_font_face_hash_table_mutex); DeleteCriticalSection (&cairo_scaled_font_map_mutex); DeleteCriticalSection (&cairo_ft_unscaled_font_map_mutex); break; } return TRUE;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -