server: Send WM_WINE_SETCURSOR with the thread input cursor handle.
[wine.git] / dlls / d2d1 / command_list.c
blobbed650516acdc6fe78b8c3736bf27087f8b16071
1 /*
2 * Copyright 2022 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "d2d1_private.h"
21 WINE_DEFAULT_DEBUG_CHANNEL(d2d);
23 enum d2d_command_list_flags
25 D2D_COMMAND_LIST_HAS_NULL_TEXT_RENDERING_PARAMS = 0x1,
28 enum d2d_command_type
30 D2D_COMMAND_SET_ANTIALIAS_MODE,
31 D2D_COMMAND_SET_TAGS,
32 D2D_COMMAND_SET_TEXT_ANTIALIAS_MODE,
33 D2D_COMMAND_SET_TEXT_RENDERING_PARAMS,
34 D2D_COMMAND_SET_TRANSFORM,
35 D2D_COMMAND_SET_PRIMITIVE_BLEND,
36 D2D_COMMAND_SET_UNIT_MODE,
37 D2D_COMMAND_CLEAR,
38 D2D_COMMAND_DRAW_GLYPH_RUN,
39 D2D_COMMAND_DRAW_LINE,
40 D2D_COMMAND_DRAW_GEOMETRY,
41 D2D_COMMAND_DRAW_RECTANGLE,
42 D2D_COMMAND_DRAW_BITMAP,
43 D2D_COMMAND_DRAW_IMAGE,
44 D2D_COMMAND_FILL_MESH,
45 D2D_COMMAND_FILL_OPACITY_MASK,
46 D2D_COMMAND_FILL_GEOMETRY,
47 D2D_COMMAND_FILL_RECTANGLE,
48 D2D_COMMAND_PUSH_CLIP,
49 D2D_COMMAND_PUSH_LAYER,
50 D2D_COMMAND_POP_CLIP,
51 D2D_COMMAND_POP_LAYER,
54 struct d2d_command
56 enum d2d_command_type op;
57 size_t size;
60 struct d2d_command_set_antialias_mode
62 struct d2d_command c;
63 D2D1_ANTIALIAS_MODE mode;
66 struct d2d_command_set_tags
68 struct d2d_command c;
69 D2D1_TAG tag1, tag2;
72 struct d2d_command_set_text_antialias_mode
74 struct d2d_command c;
75 D2D1_TEXT_ANTIALIAS_MODE mode;
78 struct d2d_command_set_text_rendering_params
80 struct d2d_command c;
81 IDWriteRenderingParams *params;
84 struct d2d_command_set_transform
86 struct d2d_command c;
87 D2D1_MATRIX_3X2_F transform;
90 struct d2d_command_set_primitive_blend
92 struct d2d_command c;
93 D2D1_PRIMITIVE_BLEND primitive_blend;
96 struct d2d_command_set_unit_mode
98 struct d2d_command c;
99 D2D1_UNIT_MODE mode;
102 struct d2d_command_clear
104 struct d2d_command c;
105 D2D1_COLOR_F color;
108 struct d2d_command_push_clip
110 struct d2d_command c;
111 D2D1_RECT_F rect;
112 D2D1_ANTIALIAS_MODE mode;
115 struct d2d_command_push_layer
117 struct d2d_command c;
118 D2D1_LAYER_PARAMETERS1 params;
119 ID2D1Layer *layer;
122 struct d2d_command_draw_line
124 struct d2d_command c;
125 D2D1_POINT_2F p0, p1;
126 ID2D1Brush *brush;
127 float stroke_width;
128 ID2D1StrokeStyle *stroke_style;
131 struct d2d_command_draw_geometry
133 struct d2d_command c;
134 ID2D1Geometry *geometry;
135 ID2D1Brush *brush;
136 float stroke_width;
137 ID2D1StrokeStyle *stroke_style;
140 struct d2d_command_draw_rectangle
142 struct d2d_command c;
143 D2D1_RECT_F rect;
144 ID2D1Brush *brush;
145 float stroke_width;
146 ID2D1StrokeStyle *stroke_style;
149 struct d2d_command_fill_mesh
151 struct d2d_command c;
152 ID2D1Mesh *mesh;
153 ID2D1Brush *brush;
156 struct d2d_command_fill_opacity_mask
158 struct d2d_command c;
159 ID2D1Bitmap *bitmap;
160 ID2D1Brush *brush;
161 D2D1_RECT_F *dst_rect;
162 D2D1_RECT_F *src_rect;
165 struct d2d_command_fill_geometry
167 struct d2d_command c;
168 ID2D1Geometry *geometry;
169 ID2D1Brush *brush;
170 ID2D1Brush *opacity_brush;
173 struct d2d_command_fill_rectangle
175 struct d2d_command c;
176 D2D1_RECT_F rect;
177 ID2D1Brush *brush;
180 struct d2d_command_draw_glyph_run
182 struct d2d_command c;
183 D2D1_POINT_2F origin;
184 DWRITE_MEASURING_MODE measuring_mode;
185 ID2D1Brush *brush;
186 DWRITE_GLYPH_RUN run;
187 DWRITE_GLYPH_RUN_DESCRIPTION *run_desc;
190 struct d2d_command_draw_bitmap
192 struct d2d_command c;
193 float opacity;
194 D2D1_INTERPOLATION_MODE interpolation_mode;
195 ID2D1Bitmap *bitmap;
196 D2D1_RECT_F *dst_rect;
197 D2D1_RECT_F *src_rect;
198 D2D1_MATRIX_4X4_F *perspective_transform;
201 struct d2d_command_draw_image
203 struct d2d_command c;
204 ID2D1Image *image;
205 D2D1_INTERPOLATION_MODE interpolation_mode;
206 D2D1_COMPOSITE_MODE composite_mode;
207 D2D1_POINT_2F *target_offset;
208 D2D1_RECT_F *image_rect;
211 static inline struct d2d_command_list *impl_from_ID2D1CommandList(ID2D1CommandList *iface)
213 return CONTAINING_RECORD(iface, struct d2d_command_list, ID2D1CommandList_iface);
216 static HRESULT STDMETHODCALLTYPE d2d_command_list_QueryInterface(ID2D1CommandList *iface, REFIID iid, void **out)
218 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
220 if (IsEqualGUID(iid, &IID_ID2D1CommandList)
221 || IsEqualGUID(iid, &IID_ID2D1Image)
222 || IsEqualGUID(iid, &IID_ID2D1Resource)
223 || IsEqualGUID(iid, &IID_IUnknown))
225 ID2D1CommandList_AddRef(iface);
226 *out = iface;
227 return S_OK;
230 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
232 *out = NULL;
233 return E_NOINTERFACE;
236 static ULONG STDMETHODCALLTYPE d2d_command_list_AddRef(ID2D1CommandList *iface)
238 struct d2d_command_list *command_list = impl_from_ID2D1CommandList(iface);
239 ULONG refcount = InterlockedIncrement(&command_list->refcount);
241 TRACE("%p increasing refcount to %lu.\n", iface, refcount);
243 return refcount;
246 static ULONG STDMETHODCALLTYPE d2d_command_list_Release(ID2D1CommandList *iface)
248 struct d2d_command_list *command_list = impl_from_ID2D1CommandList(iface);
249 ULONG refcount = InterlockedDecrement(&command_list->refcount);
250 size_t i;
252 TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
254 if (!refcount)
256 ID2D1Factory_Release(command_list->factory);
257 for (i = 0; i < command_list->objects_count; ++i)
258 IUnknown_Release(command_list->objects[i]);
259 free(command_list->objects);
260 free(command_list->data);
261 free(command_list);
264 return refcount;
267 static void STDMETHODCALLTYPE d2d_command_list_GetFactory(ID2D1CommandList *iface, ID2D1Factory **factory)
269 struct d2d_command_list *command_list = impl_from_ID2D1CommandList(iface);
271 TRACE("iface %p, factory %p.\n", iface, factory);
273 ID2D1Factory_AddRef(*factory = command_list->factory);
276 static HRESULT STDMETHODCALLTYPE d2d_command_list_Stream(ID2D1CommandList *iface, ID2D1CommandSink *sink)
278 struct d2d_command_list *command_list = impl_from_ID2D1CommandList(iface);
279 const void *data, *end;
280 HRESULT hr;
282 TRACE("iface %p, sink %p.\n", iface, sink);
284 if (command_list->state != D2D_COMMAND_LIST_STATE_CLOSED) return S_OK;
286 if (FAILED(hr = ID2D1CommandSink_BeginDraw(sink)))
287 return hr;
289 data = command_list->data;
290 end = (char *)command_list->data + command_list->size;
291 while (data < end)
293 const struct d2d_command *command = data;
295 switch (command->op)
297 case D2D_COMMAND_SET_ANTIALIAS_MODE:
299 const struct d2d_command_set_antialias_mode *c = data;
300 hr = ID2D1CommandSink_SetAntialiasMode(sink, c->mode);
301 break;
303 case D2D_COMMAND_SET_TAGS:
305 const struct d2d_command_set_tags *c = data;
306 hr = ID2D1CommandSink_SetTags(sink, c->tag1, c->tag2);
307 break;
309 case D2D_COMMAND_SET_TEXT_ANTIALIAS_MODE:
311 const struct d2d_command_set_text_antialias_mode *c = data;
312 hr = ID2D1CommandSink_SetTextAntialiasMode(sink, c->mode);
313 break;
315 case D2D_COMMAND_SET_TEXT_RENDERING_PARAMS:
317 const struct d2d_command_set_text_rendering_params *c = data;
318 hr = ID2D1CommandSink_SetTextRenderingParams(sink, c->params);
319 break;
321 case D2D_COMMAND_SET_TRANSFORM:
323 const struct d2d_command_set_transform *c = data;
324 hr = ID2D1CommandSink_SetTransform(sink, &c->transform);
325 break;
327 case D2D_COMMAND_SET_PRIMITIVE_BLEND:
329 const struct d2d_command_set_primitive_blend *c = data;
330 ID2D1CommandSink1 *sink1;
331 ID2D1CommandSink4 *sink4;
333 switch (c->primitive_blend)
335 case D2D1_PRIMITIVE_BLEND_SOURCE_OVER:
336 case D2D1_PRIMITIVE_BLEND_COPY:
337 hr = ID2D1CommandSink_SetPrimitiveBlend(sink, c->primitive_blend);
338 break;
339 case D2D1_PRIMITIVE_BLEND_MIN:
340 case D2D1_PRIMITIVE_BLEND_ADD:
341 if (SUCCEEDED(ID2D1CommandSink_QueryInterface(sink, &IID_ID2D1CommandSink1, (void **)&sink1)))
343 hr = ID2D1CommandSink1_SetPrimitiveBlend1(sink1, c->primitive_blend);
344 ID2D1CommandSink1_Release(sink1);
346 else
347 hr = ID2D1CommandSink_SetPrimitiveBlend(sink, D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
348 break;
349 case D2D1_PRIMITIVE_BLEND_MAX:
350 if (SUCCEEDED(ID2D1CommandSink_QueryInterface(sink, &IID_ID2D1CommandSink4, (void **)&sink4)))
352 hr = ID2D1CommandSink4_SetPrimitiveBlend2(sink4, c->primitive_blend);
353 ID2D1CommandSink4_Release(sink4);
355 else
356 hr = ID2D1CommandSink_SetPrimitiveBlend(sink, D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
357 break;
358 default:
359 FIXME("Unexpected blend mode %u.\n", c->primitive_blend);
360 hr = E_UNEXPECTED;
362 break;
364 case D2D_COMMAND_SET_UNIT_MODE:
366 const struct d2d_command_set_unit_mode *c = data;
367 hr = ID2D1CommandSink_SetUnitMode(sink, c->mode);
368 break;
370 case D2D_COMMAND_CLEAR:
372 const struct d2d_command_clear *c = data;
373 hr = ID2D1CommandSink_Clear(sink, &c->color);
374 break;
376 case D2D_COMMAND_DRAW_GLYPH_RUN:
378 const struct d2d_command_draw_glyph_run *c = data;
379 hr = ID2D1CommandSink_DrawGlyphRun(sink, c->origin, &c->run, c->run_desc, c->brush, c->measuring_mode);
380 break;
382 case D2D_COMMAND_DRAW_LINE:
384 const struct d2d_command_draw_line *c = data;
385 hr = ID2D1CommandSink_DrawLine(sink, c->p0, c->p1, c->brush, c->stroke_width,
386 c->stroke_style);
387 break;
389 case D2D_COMMAND_DRAW_GEOMETRY:
391 const struct d2d_command_draw_geometry *c = data;
392 hr = ID2D1CommandSink_DrawGeometry(sink, c->geometry, c->brush, c->stroke_width,
393 c->stroke_style);
394 break;
396 case D2D_COMMAND_DRAW_RECTANGLE:
398 const struct d2d_command_draw_rectangle *c = data;
399 hr = ID2D1CommandSink_DrawRectangle(sink, &c->rect, c->brush, c->stroke_width,
400 c->stroke_style);
401 break;
403 case D2D_COMMAND_DRAW_BITMAP:
405 const struct d2d_command_draw_bitmap *c = data;
406 hr = ID2D1CommandSink_DrawBitmap(sink, c->bitmap, c->dst_rect, c->opacity,
407 c->interpolation_mode, c->src_rect, c->perspective_transform);
408 break;
410 case D2D_COMMAND_DRAW_IMAGE:
412 const struct d2d_command_draw_image *c = data;
413 hr = ID2D1CommandSink_DrawImage(sink, c->image, c->target_offset, c->image_rect,
414 c->interpolation_mode, c->composite_mode);
415 break;
417 case D2D_COMMAND_FILL_MESH:
419 const struct d2d_command_fill_mesh *c = data;
420 hr = ID2D1CommandSink_FillMesh(sink, c->mesh, c->brush);
421 break;
423 case D2D_COMMAND_FILL_OPACITY_MASK:
425 const struct d2d_command_fill_opacity_mask *c = data;
426 hr = ID2D1CommandSink_FillOpacityMask(sink, c->bitmap, c->brush, c->dst_rect, c->src_rect);
427 break;
429 case D2D_COMMAND_FILL_GEOMETRY:
431 const struct d2d_command_fill_geometry *c = data;
432 hr = ID2D1CommandSink_FillGeometry(sink, c->geometry, c->brush, c->opacity_brush);
433 break;
435 case D2D_COMMAND_FILL_RECTANGLE:
437 const struct d2d_command_fill_rectangle *c = data;
438 hr = ID2D1CommandSink_FillRectangle(sink, &c->rect, c->brush);
439 break;
441 case D2D_COMMAND_PUSH_CLIP:
443 const struct d2d_command_push_clip *c = data;
444 hr = ID2D1CommandSink_PushAxisAlignedClip(sink, &c->rect, c->mode);
445 break;
447 case D2D_COMMAND_PUSH_LAYER:
449 const struct d2d_command_push_layer *c = data;
450 hr = ID2D1CommandSink_PushLayer(sink, &c->params, c->layer);
451 break;
453 case D2D_COMMAND_POP_CLIP:
454 hr = ID2D1CommandSink_PopAxisAlignedClip(sink);
455 break;
456 case D2D_COMMAND_POP_LAYER:
457 hr = ID2D1CommandSink_PopLayer(sink);
458 break;
459 default:
460 FIXME("Unhandled command %u.\n", command->op);
461 hr = E_UNEXPECTED;
464 if (FAILED(hr)) return hr;
466 data = (char *)data + command->size;
469 return ID2D1CommandSink_EndDraw(sink);
472 static HRESULT STDMETHODCALLTYPE d2d_command_list_Close(ID2D1CommandList *iface)
474 struct d2d_command_list *command_list = impl_from_ID2D1CommandList(iface);
476 FIXME("iface %p stub.\n", iface);
478 if (command_list->state != D2D_COMMAND_LIST_STATE_OPEN)
479 return D2DERR_WRONG_STATE;
481 command_list->state = D2D_COMMAND_LIST_STATE_CLOSED;
483 /* FIXME: reset as a target */
485 return S_OK;
488 static const ID2D1CommandListVtbl d2d_command_list_vtbl =
490 d2d_command_list_QueryInterface,
491 d2d_command_list_AddRef,
492 d2d_command_list_Release,
493 d2d_command_list_GetFactory,
494 d2d_command_list_Stream,
495 d2d_command_list_Close,
498 HRESULT d2d_command_list_create(ID2D1Factory *factory, struct d2d_command_list **command_list)
500 if (!(*command_list = calloc(1, sizeof(**command_list))))
501 return E_OUTOFMEMORY;
503 (*command_list)->ID2D1CommandList_iface.lpVtbl = &d2d_command_list_vtbl;
504 (*command_list)->refcount = 1;
505 ID2D1Factory_AddRef((*command_list)->factory = factory);
507 TRACE("Created command list %p.\n", *command_list);
509 return S_OK;
512 struct d2d_command_list *unsafe_impl_from_ID2D1CommandList(ID2D1CommandList *iface)
514 if (!iface)
515 return NULL;
516 assert(iface->lpVtbl == (ID2D1CommandListVtbl *)&d2d_command_list_vtbl);
517 return CONTAINING_RECORD(iface, struct d2d_command_list, ID2D1CommandList_iface);
520 static void * d2d_command_list_require_space(struct d2d_command_list *command_list, size_t size)
522 struct d2d_command *command;
524 if (!d2d_array_reserve(&command_list->data, &command_list->capacity, command_list->size + size, 1))
525 return NULL;
527 command = (struct d2d_command *)((char *)command_list->data + command_list->size);
528 command->size = size;
530 command_list->size += size;
532 return command;
535 static void d2d_command_list_reference_object(struct d2d_command_list *command_list, void *object)
537 IUnknown *obj = object;
539 if (!obj) return;
541 if (!d2d_array_reserve((void **)&command_list->objects, &command_list->objects_capacity,
542 command_list->objects_count + 1, sizeof(*command_list->objects)))
544 return;
547 command_list->objects[command_list->objects_count++] = obj;
548 IUnknown_AddRef(obj);
551 static HRESULT d2d_command_list_create_brush(struct d2d_command_list *command_list,
552 const struct d2d_device_context *ctx, ID2D1Brush *orig_brush, ID2D1Brush **ret)
554 ID2D1DeviceContext *context = (ID2D1DeviceContext *)&ctx->ID2D1DeviceContext1_iface;
555 struct d2d_brush *brush = unsafe_impl_from_ID2D1Brush(orig_brush);
556 D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linear_properties;
557 D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radial_properties;
558 D2D1_BITMAP_BRUSH_PROPERTIES1 bitmap_properties;
559 D2D1_IMAGE_BRUSH_PROPERTIES image_properties;
560 D2D1_BRUSH_PROPERTIES properties;
561 HRESULT hr;
563 properties.opacity = brush->opacity;
564 properties.transform = brush->transform;
566 switch (brush->type)
568 case D2D_BRUSH_TYPE_SOLID:
569 hr = ID2D1DeviceContext_CreateSolidColorBrush(context, &brush->u.solid.color,
570 &properties, (ID2D1SolidColorBrush **)ret);
571 break;
572 case D2D_BRUSH_TYPE_LINEAR:
573 linear_properties.startPoint = brush->u.linear.start;
574 linear_properties.endPoint = brush->u.linear.end;
575 hr = ID2D1DeviceContext_CreateLinearGradientBrush(context, &linear_properties,
576 &properties, &brush->u.linear.gradient->ID2D1GradientStopCollection_iface,
577 (ID2D1LinearGradientBrush **)ret);
578 break;
579 case D2D_BRUSH_TYPE_RADIAL:
580 radial_properties.center = brush->u.radial.centre;
581 radial_properties.gradientOriginOffset = brush->u.radial.offset;
582 radial_properties.radiusX = brush->u.radial.radius.x;
583 radial_properties.radiusY = brush->u.radial.radius.y;
584 hr = ID2D1DeviceContext_CreateRadialGradientBrush(context, &radial_properties,
585 &properties, &brush->u.radial.gradient->ID2D1GradientStopCollection_iface,
586 (ID2D1RadialGradientBrush **)ret);
587 break;
588 case D2D_BRUSH_TYPE_BITMAP:
589 bitmap_properties.extendModeX = brush->u.bitmap.extend_mode_x;
590 bitmap_properties.extendModeY = brush->u.bitmap.extend_mode_y;
591 bitmap_properties.interpolationMode = brush->u.bitmap.interpolation_mode;
592 hr = ID2D1DeviceContext_CreateBitmapBrush(context, (ID2D1Bitmap *)&brush->u.bitmap.bitmap->ID2D1Bitmap1_iface,
593 &bitmap_properties, &properties, (ID2D1BitmapBrush1 **)ret);
594 break;
595 case D2D_BRUSH_TYPE_IMAGE:
596 image_properties.sourceRectangle = brush->u.image.source_rect;
597 image_properties.extendModeX = brush->u.image.extend_mode_x;
598 image_properties.extendModeY = brush->u.image.extend_mode_y;
599 image_properties.interpolationMode = brush->u.image.interpolation_mode;
600 hr = ID2D1DeviceContext_CreateImageBrush(context, brush->u.image.image,
601 &image_properties, &properties, (ID2D1ImageBrush **)ret);
602 break;
603 default:
604 FIXME("Unsupported brush type %u.\n", brush->type);
605 return E_UNEXPECTED;
608 if (SUCCEEDED(hr))
610 d2d_command_list_reference_object(command_list, *ret);
611 ID2D1Brush_Release(*ret);
614 return hr;
617 void d2d_command_list_set_antialias_mode(struct d2d_command_list *command_list,
618 D2D1_ANTIALIAS_MODE mode)
620 struct d2d_command_set_antialias_mode *command;
622 command = d2d_command_list_require_space(command_list, sizeof(*command));
623 command->c.op = D2D_COMMAND_SET_ANTIALIAS_MODE;
624 command->mode = mode;
627 void d2d_command_list_set_primitive_blend(struct d2d_command_list *command_list,
628 D2D1_PRIMITIVE_BLEND primitive_blend)
630 struct d2d_command_set_primitive_blend *command;
632 command = d2d_command_list_require_space(command_list, sizeof(*command));
633 command->c.op = D2D_COMMAND_SET_PRIMITIVE_BLEND;
634 command->primitive_blend = primitive_blend;
637 void d2d_command_list_set_unit_mode(struct d2d_command_list *command_list, D2D1_UNIT_MODE mode)
639 struct d2d_command_set_unit_mode *command;
641 command = d2d_command_list_require_space(command_list, sizeof(*command));
642 command->c.op = D2D_COMMAND_SET_UNIT_MODE;
643 command->mode = mode;
646 void d2d_command_list_set_text_antialias_mode(struct d2d_command_list *command_list,
647 D2D1_TEXT_ANTIALIAS_MODE mode)
649 struct d2d_command_set_text_antialias_mode *command;
651 command = d2d_command_list_require_space(command_list, sizeof(*command));
652 command->c.op = D2D_COMMAND_SET_TEXT_ANTIALIAS_MODE;
653 command->mode = mode;
656 void d2d_command_list_set_tags(struct d2d_command_list *command_list, D2D1_TAG tag1, D2D1_TAG tag2)
658 struct d2d_command_set_tags *command;
660 command = d2d_command_list_require_space(command_list, sizeof(*command));
661 command->c.op = D2D_COMMAND_SET_TAGS;
662 command->tag1 = tag1;
663 command->tag2 = tag2;
666 void d2d_command_list_set_transform(struct d2d_command_list *command_list,
667 const D2D1_MATRIX_3X2_F *transform)
669 struct d2d_command_set_transform *command;
671 command = d2d_command_list_require_space(command_list, sizeof(*command));
672 command->c.op = D2D_COMMAND_SET_TRANSFORM;
673 command->transform = *transform;
676 void d2d_command_list_begin_draw(struct d2d_command_list *command_list,
677 const struct d2d_device_context *context)
679 if (command_list->state != D2D_COMMAND_LIST_STATE_INITIAL)
681 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
682 return;
685 d2d_command_list_set_antialias_mode(command_list, context->drawing_state.antialiasMode);
686 d2d_command_list_set_primitive_blend(command_list, context->drawing_state.primitiveBlend);
687 d2d_command_list_set_unit_mode(command_list, context->drawing_state.unitMode);
688 d2d_command_list_set_text_antialias_mode(command_list, context->drawing_state.textAntialiasMode);
689 d2d_command_list_set_tags(command_list, context->drawing_state.tag1, context->drawing_state.tag2);
690 d2d_command_list_set_transform(command_list, &context->drawing_state.transform);
691 d2d_command_list_set_text_rendering_params(command_list, context->text_rendering_params);
693 command_list->state = D2D_COMMAND_LIST_STATE_OPEN;
696 void d2d_command_list_push_clip(struct d2d_command_list *command_list, const D2D1_RECT_F *rect,
697 D2D1_ANTIALIAS_MODE mode)
699 struct d2d_command_push_clip *command;
701 command = d2d_command_list_require_space(command_list, sizeof(*command));
702 command->c.op = D2D_COMMAND_PUSH_CLIP;
703 command->rect = *rect;
704 command->mode = mode;
707 void d2d_command_list_pop_clip(struct d2d_command_list *command_list)
709 struct d2d_command *command;
711 command = d2d_command_list_require_space(command_list, sizeof(*command));
712 command->op = D2D_COMMAND_POP_CLIP;
715 void d2d_command_list_push_layer(struct d2d_command_list *command_list, const struct d2d_device_context *context,
716 const D2D1_LAYER_PARAMETERS1 *params, ID2D1Layer *layer)
718 struct d2d_command_push_layer *command;
719 ID2D1Brush *opacity_brush = NULL;
721 if (params->opacityBrush && FAILED(d2d_command_list_create_brush(command_list, context,
722 params->opacityBrush, &opacity_brush)))
724 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
725 return;
728 d2d_command_list_reference_object(command_list, layer);
729 d2d_command_list_reference_object(command_list, params->geometricMask);
731 command = d2d_command_list_require_space(command_list, sizeof(*command));
732 command->c.op = D2D_COMMAND_PUSH_LAYER;
733 command->params = *params;
734 command->params.opacityBrush = opacity_brush;
735 command->layer = layer;
738 void d2d_command_list_pop_layer(struct d2d_command_list *command_list)
740 struct d2d_command *command;
742 command = d2d_command_list_require_space(command_list, sizeof(*command));
743 command->op = D2D_COMMAND_POP_LAYER;
746 void d2d_command_list_clear(struct d2d_command_list *command_list, const D2D1_COLOR_F *color)
748 struct d2d_command_clear *command;
750 command = d2d_command_list_require_space(command_list, sizeof(*command));
751 command->c.op = D2D_COMMAND_CLEAR;
752 if (color) command->color = *color;
753 else memset(&command->color, 0, sizeof(command->color));
756 void d2d_command_list_draw_line(struct d2d_command_list *command_list,
757 const struct d2d_device_context *context, D2D1_POINT_2F p0, D2D1_POINT_2F p1,
758 ID2D1Brush *orig_brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
760 struct d2d_command_draw_line *command;
761 ID2D1Brush *brush;
763 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
765 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
766 return;
769 d2d_command_list_reference_object(command_list, stroke_style);
771 command = d2d_command_list_require_space(command_list, sizeof(*command));
772 command->c.op = D2D_COMMAND_DRAW_LINE;
773 command->p0 = p0;
774 command->p1 = p1;
775 command->brush = brush;
776 command->stroke_width = stroke_width;
777 command->stroke_style = stroke_style;
780 void d2d_command_list_draw_geometry(struct d2d_command_list *command_list,
781 const struct d2d_device_context *context, ID2D1Geometry *geometry, ID2D1Brush *orig_brush,
782 float stroke_width, ID2D1StrokeStyle *stroke_style)
784 struct d2d_command_draw_geometry *command;
785 ID2D1Brush *brush;
787 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
789 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
790 return;
793 d2d_command_list_reference_object(command_list, geometry);
794 d2d_command_list_reference_object(command_list, stroke_style);
796 command = d2d_command_list_require_space(command_list, sizeof(*command));
797 command->c.op = D2D_COMMAND_DRAW_GEOMETRY;
798 command->brush = brush;
799 command->stroke_width = stroke_width;
800 command->stroke_style = stroke_style;
803 void d2d_command_list_draw_rectangle(struct d2d_command_list *command_list, const struct d2d_device_context *context,
804 const D2D1_RECT_F *rect, ID2D1Brush *orig_brush, float stroke_width, ID2D1StrokeStyle *stroke_style)
806 struct d2d_command_draw_rectangle *command;
807 ID2D1Brush *brush;
809 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
811 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
812 return;
815 d2d_command_list_reference_object(command_list, stroke_style);
817 command = d2d_command_list_require_space(command_list, sizeof(*command));
818 command->c.op = D2D_COMMAND_DRAW_RECTANGLE;
819 command->rect = *rect;
820 command->brush = brush;
821 command->stroke_width = stroke_width;
822 command->stroke_style = stroke_style;
825 void d2d_command_list_fill_geometry(struct d2d_command_list *command_list,
826 const struct d2d_device_context *context, ID2D1Geometry *geometry, ID2D1Brush *orig_brush,
827 ID2D1Brush *orig_opacity_brush)
829 ID2D1Brush *brush, *opacity_brush = NULL;
830 struct d2d_command_fill_geometry *command;
832 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
834 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
835 return;
838 if (orig_opacity_brush && FAILED(d2d_command_list_create_brush(command_list, context,
839 orig_opacity_brush, &opacity_brush)))
841 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
842 ID2D1Brush_Release(brush);
843 return;
846 d2d_command_list_reference_object(command_list, geometry);
848 command = d2d_command_list_require_space(command_list, sizeof(*command));
849 command->c.op = D2D_COMMAND_FILL_GEOMETRY;
850 command->geometry = geometry;
851 command->brush = brush;
852 command->opacity_brush = opacity_brush;
855 void d2d_command_list_fill_rectangle(struct d2d_command_list *command_list,
856 const struct d2d_device_context *context, const D2D1_RECT_F *rect, ID2D1Brush *orig_brush)
858 struct d2d_command_fill_rectangle *command;
859 ID2D1Brush *brush;
861 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
863 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
864 return;
867 command = d2d_command_list_require_space(command_list, sizeof(*command));
868 command->c.op = D2D_COMMAND_FILL_RECTANGLE;
869 command->rect = *rect;
870 command->brush = brush;
873 static void d2d_command_list_set_text_rendering_params_internal(struct d2d_command_list *command_list,
874 BOOL allow_null, IDWriteRenderingParams *params)
876 struct d2d_command_set_text_rendering_params *command;
878 if (!params && !allow_null) return;
880 if ((command_list->flags & D2D_COMMAND_LIST_HAS_NULL_TEXT_RENDERING_PARAMS)
881 && !params)
883 return;
886 d2d_command_list_reference_object(command_list, params);
888 if (params)
889 command_list->flags &= ~D2D_COMMAND_LIST_HAS_NULL_TEXT_RENDERING_PARAMS;
890 else
891 command_list->flags |= D2D_COMMAND_LIST_HAS_NULL_TEXT_RENDERING_PARAMS;
893 command = d2d_command_list_require_space(command_list, sizeof(*command));
894 command->c.op = D2D_COMMAND_SET_TEXT_RENDERING_PARAMS;
895 command->params = params;
898 void d2d_command_list_set_text_rendering_params(struct d2d_command_list *command_list,
899 IDWriteRenderingParams *params)
901 d2d_command_list_set_text_rendering_params_internal(command_list, FALSE, params);
904 static inline void d2d_command_list_write_field(BYTE **data, void *dst, const void *src, size_t size)
906 void **ptr = dst;
908 if (!src)
910 *ptr = NULL;
911 return;
914 *ptr = *data;
915 memcpy(*data, src, size);
916 *data = *data + size;
919 void d2d_command_list_draw_glyph_run(struct d2d_command_list *command_list,
920 const struct d2d_device_context *context, D2D1_POINT_2F origin, const DWRITE_GLYPH_RUN *run,
921 const DWRITE_GLYPH_RUN_DESCRIPTION *run_desc, ID2D1Brush *orig_brush,
922 DWRITE_MEASURING_MODE measuring_mode)
924 struct d2d_command_draw_glyph_run *command;
925 DWRITE_GLYPH_RUN_DESCRIPTION *d;
926 DWRITE_GLYPH_RUN *r;
927 UINT32 glyph_count;
928 ID2D1Brush *brush;
929 size_t size;
930 BYTE *data;
932 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
934 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
935 return;
938 /* Set rendering parameters automatically. Explicitly set null parameters are not recorded,
939 either separately or as a part of a restored state block. Forcing parameters update on
940 DrawGlyphRun() ensures that state is reset correctly. */
942 d2d_command_list_set_text_rendering_params_internal(command_list, TRUE,
943 context->text_rendering_params);
945 /* Get combined size of variable data. */
947 glyph_count = run->glyphCount;
948 size = sizeof(*command);
949 if (run->glyphIndices) size += glyph_count * sizeof(*run->glyphIndices);
950 if (run->glyphAdvances) size += glyph_count * sizeof(*run->glyphAdvances);
951 if (run->glyphOffsets) size += glyph_count * sizeof(*run->glyphOffsets);
952 if (run_desc)
954 size += sizeof(*run_desc);
955 if (run_desc->localeName) size += (wcslen(run_desc->localeName) + 1) * sizeof(*run_desc->localeName);
956 if (run_desc->string) size += run_desc->stringLength * sizeof(*run_desc->string);
957 if (run_desc->clusterMap) size += run_desc->stringLength * sizeof(*run_desc->clusterMap);
958 size += sizeof(run_desc->stringLength);
959 size += sizeof(run_desc->textPosition);
962 d2d_command_list_reference_object(command_list, run->fontFace);
964 command = d2d_command_list_require_space(command_list, size);
965 command->c.op = D2D_COMMAND_DRAW_GLYPH_RUN;
966 r = &command->run;
968 r->fontFace = run->fontFace;
969 r->fontEmSize = run->fontEmSize;
970 r->glyphCount = run->glyphCount;
971 r->isSideways = run->isSideways;
972 r->bidiLevel = run->bidiLevel;
974 data = (BYTE *)(command + 1);
976 d2d_command_list_write_field(&data, &r->glyphIndices, run->glyphIndices, glyph_count * sizeof(*r->glyphIndices));
977 d2d_command_list_write_field(&data, &r->glyphAdvances, run->glyphAdvances, glyph_count * sizeof(*r->glyphAdvances));
978 d2d_command_list_write_field(&data, &r->glyphOffsets, run->glyphOffsets, glyph_count * sizeof(*r->glyphOffsets));
980 command->run_desc = NULL;
981 if (run_desc)
983 d = command->run_desc = (DWRITE_GLYPH_RUN_DESCRIPTION *)data;
984 memset(d, 0, sizeof(*d));
985 data += sizeof(*d);
987 d2d_command_list_write_field(&data, &d->localeName, run_desc->localeName, (wcslen(run_desc->localeName) + 1) * sizeof(*run_desc->localeName));
988 d2d_command_list_write_field(&data, &d->string, run_desc->string, run_desc->stringLength * sizeof(*run_desc->string));
989 d->stringLength = run_desc->stringLength;
990 d2d_command_list_write_field(&data, &d->clusterMap, run_desc->clusterMap, run_desc->stringLength * sizeof(*run_desc->clusterMap));
991 d->textPosition = run_desc->textPosition;
994 command->brush = brush;
995 command->origin = origin;
996 command->measuring_mode = measuring_mode;
999 void d2d_command_list_draw_bitmap(struct d2d_command_list *command_list, ID2D1Bitmap *bitmap,
1000 const D2D1_RECT_F *dst_rect, float opacity, D2D1_INTERPOLATION_MODE interpolation_mode,
1001 const D2D1_RECT_F *src_rect, const D2D1_MATRIX_4X4_F *perspective_transform)
1003 struct d2d_command_draw_bitmap *command;
1004 size_t size;
1005 BYTE *data;
1007 size = sizeof(*command);
1008 if (dst_rect) size += sizeof(*dst_rect);
1009 if (src_rect) size += sizeof(*src_rect);
1010 if (perspective_transform) size += sizeof(*perspective_transform);
1012 d2d_command_list_reference_object(command_list, bitmap);
1014 command = d2d_command_list_require_space(command_list, size);
1015 command->c.op = D2D_COMMAND_DRAW_BITMAP;
1016 command->bitmap = bitmap;
1017 command->opacity = opacity;
1018 command->interpolation_mode = interpolation_mode;
1020 data = (BYTE *)(command + 1);
1022 d2d_command_list_write_field(&data, &command->dst_rect, dst_rect, sizeof(*dst_rect));
1023 d2d_command_list_write_field(&data, &command->src_rect, src_rect, sizeof(*src_rect));
1024 d2d_command_list_write_field(&data, &command->perspective_transform, perspective_transform, sizeof(*perspective_transform));
1027 void d2d_command_list_draw_image(struct d2d_command_list *command_list, ID2D1Image *image,
1028 const D2D1_POINT_2F *target_offset, const D2D1_RECT_F *image_rect, D2D1_INTERPOLATION_MODE interpolation_mode,
1029 D2D1_COMPOSITE_MODE composite_mode)
1031 struct d2d_command_draw_image *command;
1032 size_t size;
1033 BYTE *data;
1035 size = sizeof(*command);
1036 if (target_offset) size += sizeof(*target_offset);
1037 if (image_rect) size += sizeof(*image_rect);
1039 d2d_command_list_reference_object(command_list, image);
1041 command = d2d_command_list_require_space(command_list, size);
1042 command->c.op = D2D_COMMAND_DRAW_IMAGE;
1043 command->image = image;
1044 command->interpolation_mode = interpolation_mode;
1045 command->composite_mode = composite_mode;
1047 data = (BYTE *)(command + 1);
1049 d2d_command_list_write_field(&data, &command->target_offset, target_offset, sizeof(*target_offset));
1050 d2d_command_list_write_field(&data, &command->image_rect, image_rect, sizeof(*image_rect));
1053 void d2d_command_list_fill_mesh(struct d2d_command_list *command_list, const struct d2d_device_context *context,
1054 ID2D1Mesh *mesh, ID2D1Brush *orig_brush)
1056 struct d2d_command_fill_mesh *command;
1057 ID2D1Brush *brush;
1059 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
1061 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
1062 return;
1065 d2d_command_list_reference_object(command_list, mesh);
1067 command = d2d_command_list_require_space(command_list, sizeof(*command));
1068 command->c.op = D2D_COMMAND_FILL_MESH;
1069 command->mesh = mesh;
1070 command->brush = brush;
1073 void d2d_command_list_fill_opacity_mask(struct d2d_command_list *command_list, const struct d2d_device_context *context,
1074 ID2D1Bitmap *bitmap, ID2D1Brush *orig_brush, const D2D1_RECT_F *dst_rect, const D2D1_RECT_F *src_rect)
1076 struct d2d_command_fill_opacity_mask *command;
1077 ID2D1Brush *brush;
1078 size_t size;
1079 BYTE *data;
1081 if (FAILED(d2d_command_list_create_brush(command_list, context, orig_brush, &brush)))
1083 command_list->state = D2D_COMMAND_LIST_STATE_ERROR;
1084 return;
1087 size = sizeof(*command);
1088 if (dst_rect) size += sizeof(*dst_rect);
1089 if (src_rect) size += sizeof(*src_rect);
1091 d2d_command_list_reference_object(command_list, bitmap);
1093 command = d2d_command_list_require_space(command_list, size);
1094 command->c.op = D2D_COMMAND_FILL_OPACITY_MASK;
1095 command->bitmap = bitmap;
1096 command->brush = brush;
1098 data = (BYTE *)(command + 1);
1100 d2d_command_list_write_field(&data, &command->dst_rect, dst_rect, sizeof(*dst_rect));
1101 d2d_command_list_write_field(&data, &command->src_rect, src_rect, sizeof(*src_rect));