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,
30 D2D_COMMAND_SET_ANTIALIAS_MODE
,
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
,
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
,
51 D2D_COMMAND_POP_LAYER
,
56 enum d2d_command_type op
;
60 struct d2d_command_set_antialias_mode
63 D2D1_ANTIALIAS_MODE mode
;
66 struct d2d_command_set_tags
72 struct d2d_command_set_text_antialias_mode
75 D2D1_TEXT_ANTIALIAS_MODE mode
;
78 struct d2d_command_set_text_rendering_params
81 IDWriteRenderingParams
*params
;
84 struct d2d_command_set_transform
87 D2D1_MATRIX_3X2_F transform
;
90 struct d2d_command_set_primitive_blend
93 D2D1_PRIMITIVE_BLEND primitive_blend
;
96 struct d2d_command_set_unit_mode
102 struct d2d_command_clear
104 struct d2d_command c
;
108 struct d2d_command_push_clip
110 struct d2d_command c
;
112 D2D1_ANTIALIAS_MODE mode
;
115 struct d2d_command_push_layer
117 struct d2d_command c
;
118 D2D1_LAYER_PARAMETERS1 params
;
122 struct d2d_command_draw_line
124 struct d2d_command c
;
125 D2D1_POINT_2F p0
, p1
;
128 ID2D1StrokeStyle
*stroke_style
;
131 struct d2d_command_draw_geometry
133 struct d2d_command c
;
134 ID2D1Geometry
*geometry
;
137 ID2D1StrokeStyle
*stroke_style
;
140 struct d2d_command_draw_rectangle
142 struct d2d_command c
;
146 ID2D1StrokeStyle
*stroke_style
;
149 struct d2d_command_fill_mesh
151 struct d2d_command c
;
156 struct d2d_command_fill_opacity_mask
158 struct d2d_command c
;
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
;
170 ID2D1Brush
*opacity_brush
;
173 struct d2d_command_fill_rectangle
175 struct d2d_command c
;
180 struct d2d_command_draw_glyph_run
182 struct d2d_command c
;
183 D2D1_POINT_2F origin
;
184 DWRITE_MEASURING_MODE measuring_mode
;
186 DWRITE_GLYPH_RUN run
;
187 DWRITE_GLYPH_RUN_DESCRIPTION
*run_desc
;
190 struct d2d_command_draw_bitmap
192 struct d2d_command c
;
194 D2D1_INTERPOLATION_MODE interpolation_mode
;
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
;
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
);
230 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
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
);
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
);
252 TRACE("%p decreasing refcount to %lu.\n", iface
, 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
);
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
;
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
)))
289 data
= command_list
->data
;
290 end
= (char *)command_list
->data
+ command_list
->size
;
293 const struct d2d_command
*command
= data
;
297 case D2D_COMMAND_SET_ANTIALIAS_MODE
:
299 const struct d2d_command_set_antialias_mode
*c
= data
;
300 hr
= ID2D1CommandSink_SetAntialiasMode(sink
, c
->mode
);
303 case D2D_COMMAND_SET_TAGS
:
305 const struct d2d_command_set_tags
*c
= data
;
306 hr
= ID2D1CommandSink_SetTags(sink
, c
->tag1
, c
->tag2
);
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
);
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
);
321 case D2D_COMMAND_SET_TRANSFORM
:
323 const struct d2d_command_set_transform
*c
= data
;
324 hr
= ID2D1CommandSink_SetTransform(sink
, &c
->transform
);
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
);
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
);
347 hr
= ID2D1CommandSink_SetPrimitiveBlend(sink
, D2D1_PRIMITIVE_BLEND_SOURCE_OVER
);
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
);
356 hr
= ID2D1CommandSink_SetPrimitiveBlend(sink
, D2D1_PRIMITIVE_BLEND_SOURCE_OVER
);
359 FIXME("Unexpected blend mode %u.\n", c
->primitive_blend
);
364 case D2D_COMMAND_SET_UNIT_MODE
:
366 const struct d2d_command_set_unit_mode
*c
= data
;
367 hr
= ID2D1CommandSink_SetUnitMode(sink
, c
->mode
);
370 case D2D_COMMAND_CLEAR
:
372 const struct d2d_command_clear
*c
= data
;
373 hr
= ID2D1CommandSink_Clear(sink
, &c
->color
);
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
);
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
,
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
,
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
,
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
);
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
);
417 case D2D_COMMAND_FILL_MESH
:
419 const struct d2d_command_fill_mesh
*c
= data
;
420 hr
= ID2D1CommandSink_FillMesh(sink
, c
->mesh
, c
->brush
);
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
);
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
);
435 case D2D_COMMAND_FILL_RECTANGLE
:
437 const struct d2d_command_fill_rectangle
*c
= data
;
438 hr
= ID2D1CommandSink_FillRectangle(sink
, &c
->rect
, c
->brush
);
441 case D2D_COMMAND_PUSH_CLIP
:
443 const struct d2d_command_push_clip
*c
= data
;
444 hr
= ID2D1CommandSink_PushAxisAlignedClip(sink
, &c
->rect
, c
->mode
);
447 case D2D_COMMAND_PUSH_LAYER
:
449 const struct d2d_command_push_layer
*c
= data
;
450 hr
= ID2D1CommandSink_PushLayer(sink
, &c
->params
, c
->layer
);
453 case D2D_COMMAND_POP_CLIP
:
454 hr
= ID2D1CommandSink_PopAxisAlignedClip(sink
);
456 case D2D_COMMAND_POP_LAYER
:
457 hr
= ID2D1CommandSink_PopLayer(sink
);
460 FIXME("Unhandled command %u.\n", command
->op
);
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 */
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
);
512 struct d2d_command_list
*unsafe_impl_from_ID2D1CommandList(ID2D1CommandList
*iface
)
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))
527 command
= (struct d2d_command
*)((char *)command_list
->data
+ command_list
->size
);
528 command
->size
= size
;
530 command_list
->size
+= size
;
535 static void d2d_command_list_reference_object(struct d2d_command_list
*command_list
, void *object
)
537 IUnknown
*obj
= object
;
541 if (!d2d_array_reserve((void **)&command_list
->objects
, &command_list
->objects_capacity
,
542 command_list
->objects_count
+ 1, sizeof(*command_list
->objects
)))
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
;
563 properties
.opacity
= brush
->opacity
;
564 properties
.transform
= brush
->transform
;
568 case D2D_BRUSH_TYPE_SOLID
:
569 hr
= ID2D1DeviceContext_CreateSolidColorBrush(context
, &brush
->u
.solid
.color
,
570 &properties
, (ID2D1SolidColorBrush
**)ret
);
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
);
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
);
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
);
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
);
604 FIXME("Unsupported brush type %u.\n", brush
->type
);
610 d2d_command_list_reference_object(command_list
, *ret
);
611 ID2D1Brush_Release(*ret
);
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
;
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
;
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
;
763 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
765 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
;
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
;
787 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
789 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
;
809 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
811 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
;
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
);
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
;
861 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
863 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
)
886 d2d_command_list_reference_object(command_list
, params
);
889 command_list
->flags
&= ~D2D_COMMAND_LIST_HAS_NULL_TEXT_RENDERING_PARAMS
;
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
)
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
;
932 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
934 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
);
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
;
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
;
983 d
= command
->run_desc
= (DWRITE_GLYPH_RUN_DESCRIPTION
*)data
;
984 memset(d
, 0, 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
;
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
;
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
;
1059 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
1061 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
;
1081 if (FAILED(d2d_command_list_create_brush(command_list
, context
, orig_brush
, &brush
)))
1083 command_list
->state
= D2D_COMMAND_LIST_STATE_ERROR
;
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
));