/
graphicsd2d.cpp
4750 lines (3880 loc) · 144 KB
/
graphicsd2d.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/graphicsd2d.cpp
// Purpose: Implementation of Direct2D Render Context
// Author: Pana Alexandru <astronothing@gmail.com>
// Created: 2014-05-20
// Copyright: (c) 2014 wxWidgets development team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#if wxUSE_GRAPHICS_DIRECT2D
// Minimum supported client: Windows 8 and Platform Update for Windows 7
#define wxD2D_DEVICE_CONTEXT_SUPPORTED 0
// Ensure no previous defines interfere with the Direct2D API headers
#undef GetHwnd
// We load these functions at runtime from the d2d1.dll.
// However, since they are also used inside the d2d1.h header we must provide
// implementations matching the exact declarations. These defines ensures we
// are not violating the ODR rule.
#define D2D1CreateFactory wxD2D1CreateFactory
#define D2D1MakeRotateMatrix wxD2D1MakeRotateMatrix
#define D2D1MakeSkewMatrix wxD2D1MakeSkewMatrix
#define D2D1IsMatrixInvertible wxD2D1IsMatrixInvertible
#define D2D1InvertMatrix wxD2D1InvertMatrix
// There are clashes between the names of the member fields and parameters
// in the standard d2d1helper.h header resulting in C4458 with VC14,
// so disable this warning for this file as there is no other way to
// avoid it.
#ifdef __VISUALC__
#pragma warning(push)
#pragma warning(disable:4458) // declaration of 'xxx' hides class member
#endif
#include <d2d1.h>
#include <dwrite.h>
#include <wincodec.h>
#if wxD2D_DEVICE_CONTEXT_SUPPORTED
#include <D3D11.h>
#include <D2d1_1.h>
#include <DXGI1_2.h>
#endif
#ifdef __VISUALC__
#pragma warning(pop)
#endif
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include <float.h> // for FLT_MAX, FLT_MIN
#ifndef WX_PRECOMP
#include "wx/dc.h"
#include "wx/dcclient.h"
#include "wx/dcmemory.h"
#include "wx/image.h"
#include "wx/module.h"
#include "wx/window.h"
#include "wx/msw/private.h"
#endif // !WX_PRECOMP
#include "wx/graphics.h"
#include "wx/dynlib.h"
#include "wx/msw/private/comptr.h"
#include "wx/private/graphics.h"
#include "wx/stack.h"
#include "wx/sharedptr.h"
// This must be the last header included to only affect the DEFINE_GUID()
// occurrences below but not any GUIDs declared in the standard files included
// above.
#include <initguid.h>
// Generic error message for a failed direct2d operation
#define wxFAILED_HRESULT_MSG(result) \
wxString::Format("Direct2D failed with HRESULT %x", (result))
// Checks a HRESULT value for success, otherwise displays an error message and
// returns from the enclosing function.
#define wxCHECK_HRESULT_RET(result) \
wxCHECK_RET(SUCCEEDED(result), wxFAILED_HRESULT_MSG(result))
#define wxCHECK2_HRESULT_RET(result, returnValue) \
wxCHECK2_MSG(SUCCEEDED(result), return returnValue, \
wxFAILED_HRESULT_MSG(result))
// Variation of wxCHECK_HRESULT_RET for functions which must return a pointer
#define wxCHECK_HRESULT_RET_PTR(result) wxCHECK2_HRESULT_RET(result, NULL)
// Checks the precondition of wxManagedResourceHolder::AcquireResource, namely
// that it is bound to a manager.
#define wxCHECK_RESOURCE_HOLDER_PRE() \
{ \
if (IsResourceAcquired()) return; \
wxCHECK_RET(IsBound(), \
"Cannot acquire a native resource without being bound to a manager"); \
}
// Checks the postcondition of wxManagedResourceHolder::AcquireResource, namely
// that it was successful in acquiring the native resource.
#define wxCHECK_RESOURCE_HOLDER_POST() \
wxCHECK_RET(m_nativeResource != NULL, "Could not acquire native resource");
// Helper class used to check for direct2d availability at runtime and to
// dynamically load the required symbols from d2d1.dll and dwrite.dll
class wxDirect2D
{
public:
enum wxD2DVersion
{
wxD2D_VERSION_1_0,
wxD2D_VERSION_1_1,
wxD2D_VERSION_NONE
};
static bool Initialize()
{
if (!m_initialized)
{
m_hasDirect2DSupport = LoadLibraries();
m_initialized = true;
}
return m_hasDirect2DSupport;
}
static bool HasDirect2DSupport()
{
Initialize();
return m_hasDirect2DSupport;
}
static wxD2DVersion GetDirect2DVersion()
{
return m_D2DRuntimeVersion;
}
private:
static bool LoadLibraries()
{
if ( !m_dllDirect2d.Load(wxT("d2d1.dll"), wxDL_VERBATIM | wxDL_QUIET) )
return false;
if ( !m_dllDirectWrite.Load(wxT("dwrite.dll"), wxDL_VERBATIM | wxDL_QUIET) )
return false;
#define wxLOAD_FUNC(dll, name) \
name = (name##_t)dll.RawGetSymbol(#name); \
if ( !name ) \
return false;
wxLOAD_FUNC(m_dllDirect2d, D2D1CreateFactory);
wxLOAD_FUNC(m_dllDirect2d, D2D1MakeRotateMatrix);
wxLOAD_FUNC(m_dllDirect2d, D2D1MakeSkewMatrix);
wxLOAD_FUNC(m_dllDirect2d, D2D1IsMatrixInvertible);
wxLOAD_FUNC(m_dllDirect2d, D2D1InvertMatrix);
wxLOAD_FUNC(m_dllDirectWrite, DWriteCreateFactory);
m_D2DRuntimeVersion = wxD2D_VERSION_1_0;
return true;
}
public:
typedef HRESULT (WINAPI *D2D1CreateFactory_t)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS*, void**);
static D2D1CreateFactory_t D2D1CreateFactory;
typedef void (WINAPI *D2D1MakeRotateMatrix_t)(FLOAT, D2D1_POINT_2F, D2D1_MATRIX_3X2_F*);
static D2D1MakeRotateMatrix_t D2D1MakeRotateMatrix;
typedef void (WINAPI *D2D1MakeSkewMatrix_t)(FLOAT, FLOAT, D2D1_POINT_2F, D2D1_MATRIX_3X2_F*);
static D2D1MakeSkewMatrix_t D2D1MakeSkewMatrix;
typedef BOOL (WINAPI *D2D1IsMatrixInvertible_t)(const D2D1_MATRIX_3X2_F*);
static D2D1IsMatrixInvertible_t D2D1IsMatrixInvertible;
typedef BOOL (WINAPI *D2D1InvertMatrix_t)(D2D1_MATRIX_3X2_F*);
static D2D1InvertMatrix_t D2D1InvertMatrix;
typedef HRESULT (WINAPI *DWriteCreateFactory_t)(DWRITE_FACTORY_TYPE, REFIID, IUnknown**);
static DWriteCreateFactory_t DWriteCreateFactory;
private:
static bool m_initialized;
static bool m_hasDirect2DSupport;
static wxD2DVersion m_D2DRuntimeVersion;
static wxDynamicLibrary m_dllDirect2d;
static wxDynamicLibrary m_dllDirectWrite;
};
// define the members
bool wxDirect2D::m_initialized = false;
bool wxDirect2D::m_hasDirect2DSupport = false;
wxDirect2D::wxD2DVersion wxDirect2D::m_D2DRuntimeVersion = wxD2D_VERSION_NONE;
wxDynamicLibrary wxDirect2D::m_dllDirect2d;
wxDynamicLibrary wxDirect2D::m_dllDirectWrite;
// define the (not yet imported) functions
wxDirect2D::D2D1CreateFactory_t wxDirect2D::D2D1CreateFactory = NULL;
wxDirect2D::D2D1MakeRotateMatrix_t wxDirect2D::D2D1MakeRotateMatrix = NULL;
wxDirect2D::D2D1MakeSkewMatrix_t wxDirect2D::D2D1MakeSkewMatrix = NULL;
wxDirect2D::D2D1IsMatrixInvertible_t wxDirect2D::D2D1IsMatrixInvertible = NULL;
wxDirect2D::D2D1InvertMatrix_t wxDirect2D::D2D1InvertMatrix = NULL;
wxDirect2D::DWriteCreateFactory_t wxDirect2D::DWriteCreateFactory = NULL;
// define the interface GUIDs
DEFINE_GUID(wxIID_IWICImagingFactory,
0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70);
DEFINE_GUID(wxIID_IDWriteFactory,
0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48);
DEFINE_GUID(wxIID_IWICBitmapSource,
0x00000120, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94);
// Implementation of the Direct2D functions
HRESULT WINAPI wxD2D1CreateFactory(
D2D1_FACTORY_TYPE factoryType,
REFIID riid,
CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
void **ppIFactory)
{
if (!wxDirect2D::Initialize())
return S_FALSE;
return wxDirect2D::D2D1CreateFactory(
factoryType,
riid,
pFactoryOptions,
ppIFactory);
}
void WINAPI wxD2D1MakeRotateMatrix(
FLOAT angle,
D2D1_POINT_2F center,
D2D1_MATRIX_3X2_F *matrix)
{
if (!wxDirect2D::Initialize())
return;
wxDirect2D::D2D1MakeRotateMatrix(angle, center, matrix);
}
void WINAPI wxD2D1MakeSkewMatrix(
FLOAT angleX,
FLOAT angleY,
D2D1_POINT_2F center,
D2D1_MATRIX_3X2_F *matrix)
{
if (!wxDirect2D::Initialize())
return;
wxDirect2D::D2D1MakeSkewMatrix(angleX, angleY, center, matrix);
}
BOOL WINAPI wxD2D1IsMatrixInvertible(
const D2D1_MATRIX_3X2_F *matrix)
{
if (!wxDirect2D::Initialize())
return FALSE;
return wxDirect2D::D2D1IsMatrixInvertible(matrix);
}
BOOL WINAPI wxD2D1InvertMatrix(
D2D1_MATRIX_3X2_F *matrix)
{
if (!wxDirect2D::Initialize())
return FALSE;
return wxDirect2D::D2D1InvertMatrix(matrix);
}
static IWICImagingFactory* gs_WICImagingFactory = NULL;
IWICImagingFactory* wxWICImagingFactory()
{
if (gs_WICImagingFactory == NULL) {
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
wxIID_IWICImagingFactory,
(LPVOID*)&gs_WICImagingFactory);
wxCHECK_HRESULT_RET_PTR(hr);
}
return gs_WICImagingFactory;
}
static IDWriteFactory* gs_IDWriteFactory = NULL;
IDWriteFactory* wxDWriteFactory()
{
if (!wxDirect2D::Initialize())
return NULL;
if (gs_IDWriteFactory == NULL)
{
wxDirect2D::DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
wxIID_IDWriteFactory,
reinterpret_cast<IUnknown**>(&gs_IDWriteFactory)
);
}
return gs_IDWriteFactory;
}
extern WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen;
extern WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush;
// We use the notion of a context supplier because the context
// needed to create Direct2D resources (namely the RenderTarget)
// is itself device-dependent and might change during the lifetime
// of the resources which were created from it.
template <typename C>
class wxContextSupplier
{
public:
typedef C ContextType;
virtual C GetContext() = 0;
};
typedef wxContextSupplier<ID2D1RenderTarget*> wxD2DContextSupplier;
// A resource holder manages a generic resource by acquiring
// and releasing it on demand.
class wxResourceHolder
{
public:
// Acquires the managed resource if necessary (not already acquired)
virtual void AcquireResource() = 0;
// Releases the managed resource
virtual void ReleaseResource() = 0;
// Checks if the resources was previously acquired
virtual bool IsResourceAcquired() = 0;
// Returns the managed resource or NULL if the resources
// was not previously acquired
virtual void* GetResource() = 0;
virtual ~wxResourceHolder(){};
};
class wxD2DResourceManager;
class wxD2DManagedObject
{
public:
virtual void Bind(wxD2DResourceManager* manager) = 0;
virtual void UnBind() = 0;
virtual bool IsBound() = 0;
virtual wxD2DResourceManager* GetManager() = 0;
virtual ~wxD2DManagedObject() {};
};
class wxManagedResourceHolder : public wxResourceHolder, public wxD2DManagedObject
{
public:
virtual ~wxManagedResourceHolder() {};
};
// A Direct2D resource manager handles the device-dependent
// resource holders attached to it by requesting them to
// release their resources when the API invalidates.
// NOTE: We're using a list because we expect to have multiple
// insertions but very rarely a traversal (if ever).
WX_DECLARE_LIST(wxManagedResourceHolder, wxManagedResourceListType);
#include <wx/listimpl.cpp>
WX_DEFINE_LIST(wxManagedResourceListType);
class wxD2DResourceManager: public wxD2DContextSupplier
{
public:
void RegisterResourceHolder(wxManagedResourceHolder* resourceHolder)
{
m_resources.push_back(resourceHolder);
}
void UnregisterResourceHolder(wxManagedResourceHolder* resourceHolder)
{
m_resources.remove(resourceHolder);
}
void ReleaseResources()
{
wxManagedResourceListType::iterator it;
for (it = m_resources.begin(); it != m_resources.end(); ++it)
{
(*it)->ReleaseResource();
}
// Check that all resources were released
for (it = m_resources.begin(); it != m_resources.end(); ++it)
{
wxCHECK_RET(!(*it)->IsResourceAcquired(), "One or more device-dependent resources failed to release");
}
}
virtual ~wxD2DResourceManager()
{
while (!m_resources.empty())
{
m_resources.front()->ReleaseResource();
m_resources.front()->UnBind();
}
}
private:
wxManagedResourceListType m_resources;
};
// A Direct2D resource holder manages device dependent resources
// by storing any information necessary for acquiring the resource
// and releasing the resource when the API invalidates it.
template<typename T>
class wxD2DResourceHolder: public wxManagedResourceHolder
{
public:
wxD2DResourceHolder() : m_resourceManager(NULL)
{
}
virtual ~wxD2DResourceHolder()
{
UnBind();
ReleaseResource();
}
bool IsResourceAcquired() wxOVERRIDE
{
return m_nativeResource != NULL;
}
void* GetResource() wxOVERRIDE
{
return GetD2DResource();
}
wxCOMPtr<T>& GetD2DResource()
{
if (!IsResourceAcquired())
{
AcquireResource();
}
return m_nativeResource;
}
void AcquireResource() wxOVERRIDE
{
wxCHECK_RESOURCE_HOLDER_PRE();
DoAcquireResource();
wxCHECK_RESOURCE_HOLDER_POST();
}
void ReleaseResource() wxOVERRIDE
{
m_nativeResource.reset();
}
wxD2DContextSupplier::ContextType GetContext()
{
return m_resourceManager->GetContext();
}
void Bind(wxD2DResourceManager* manager) wxOVERRIDE
{
if (IsBound())
return;
m_resourceManager = manager;
m_resourceManager->RegisterResourceHolder(this);
}
void UnBind() wxOVERRIDE
{
if (!IsBound())
return;
m_resourceManager->UnregisterResourceHolder(this);
m_resourceManager = NULL;
}
bool IsBound() wxOVERRIDE
{
return m_resourceManager != NULL;
}
wxD2DResourceManager* GetManager() wxOVERRIDE
{
return m_resourceManager;
}
protected:
virtual void DoAcquireResource() = 0;
private:
wxD2DResourceManager* m_resourceManager;
protected:
wxCOMPtr<T> m_nativeResource;
};
// Used as super class for graphics data objects
// to forward the bindings to their internal resource holder.
class wxD2DManagedGraphicsData : public wxD2DManagedObject
{
public:
void Bind(wxD2DResourceManager* manager) wxOVERRIDE
{
GetManagedObject()->Bind(manager);
}
void UnBind() wxOVERRIDE
{
GetManagedObject()->UnBind();
}
bool IsBound() wxOVERRIDE
{
return GetManagedObject()->IsBound();
}
wxD2DResourceManager* GetManager() wxOVERRIDE
{
return GetManagedObject()->GetManager();
}
virtual wxD2DManagedObject* GetManagedObject() = 0;
~wxD2DManagedGraphicsData() {};
};
D2D1_CAP_STYLE wxD2DConvertPenCap(wxPenCap cap)
{
switch (cap)
{
case wxCAP_ROUND:
return D2D1_CAP_STYLE_ROUND;
case wxCAP_PROJECTING:
return D2D1_CAP_STYLE_SQUARE;
case wxCAP_BUTT:
return D2D1_CAP_STYLE_FLAT;
case wxCAP_INVALID:
return D2D1_CAP_STYLE_FLAT;
}
wxFAIL_MSG("unknown pen cap");
return D2D1_CAP_STYLE_FLAT;
}
D2D1_LINE_JOIN wxD2DConvertPenJoin(wxPenJoin join)
{
switch (join)
{
case wxJOIN_BEVEL:
return D2D1_LINE_JOIN_BEVEL;
case wxJOIN_MITER:
return D2D1_LINE_JOIN_MITER;
case wxJOIN_ROUND:
return D2D1_LINE_JOIN_ROUND;
case wxJOIN_INVALID:
return D2D1_LINE_JOIN_MITER;
}
wxFAIL_MSG("unknown pen join");
return D2D1_LINE_JOIN_MITER;
}
D2D1_DASH_STYLE wxD2DConvertPenStyle(wxPenStyle dashStyle)
{
switch (dashStyle)
{
case wxPENSTYLE_SOLID:
return D2D1_DASH_STYLE_SOLID;
case wxPENSTYLE_DOT:
return D2D1_DASH_STYLE_DOT;
case wxPENSTYLE_LONG_DASH:
return D2D1_DASH_STYLE_DASH;
case wxPENSTYLE_SHORT_DASH:
return D2D1_DASH_STYLE_DASH;
case wxPENSTYLE_DOT_DASH:
return D2D1_DASH_STYLE_DASH_DOT;
case wxPENSTYLE_USER_DASH:
return D2D1_DASH_STYLE_CUSTOM;
// NB: These styles cannot be converted to a D2D1_DASH_STYLE
// and must be handled separately.
case wxPENSTYLE_TRANSPARENT:
wxFALLTHROUGH;
case wxPENSTYLE_INVALID:
wxFALLTHROUGH;
case wxPENSTYLE_STIPPLE_MASK_OPAQUE:
wxFALLTHROUGH;
case wxPENSTYLE_STIPPLE_MASK:
wxFALLTHROUGH;
case wxPENSTYLE_STIPPLE:
wxFALLTHROUGH;
case wxPENSTYLE_BDIAGONAL_HATCH:
wxFALLTHROUGH;
case wxPENSTYLE_CROSSDIAG_HATCH:
wxFALLTHROUGH;
case wxPENSTYLE_FDIAGONAL_HATCH:
wxFALLTHROUGH;
case wxPENSTYLE_CROSS_HATCH:
wxFALLTHROUGH;
case wxPENSTYLE_HORIZONTAL_HATCH:
wxFALLTHROUGH;
case wxPENSTYLE_VERTICAL_HATCH:
return D2D1_DASH_STYLE_SOLID;
}
wxFAIL_MSG("unknown pen style");
return D2D1_DASH_STYLE_SOLID;
}
D2D1_COLOR_F wxD2DConvertColour(wxColour colour)
{
return D2D1::ColorF(
colour.Red() / 255.0f,
colour.Green() / 255.0f,
colour.Blue() / 255.0f,
colour.Alpha() / 255.0f);
}
D2D1_ANTIALIAS_MODE wxD2DConvertAntialiasMode(wxAntialiasMode antialiasMode)
{
switch (antialiasMode)
{
case wxANTIALIAS_NONE:
return D2D1_ANTIALIAS_MODE_ALIASED;
case wxANTIALIAS_DEFAULT:
return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
}
wxFAIL_MSG("unknown antialias mode");
return D2D1_ANTIALIAS_MODE_ALIASED;
}
#if wxD2D_DEVICE_CONTEXT_SUPPORTED
bool wxD2DCompositionModeSupported(wxCompositionMode compositionMode)
{
if (compositionMode == wxCOMPOSITION_CLEAR || compositionMode == wxCOMPOSITION_INVALID)
{
return false;
}
return true;
}
D2D1_COMPOSITE_MODE wxD2DConvertCompositionMode(wxCompositionMode compositionMode)
{
switch (compositionMode)
{
case wxCOMPOSITION_SOURCE:
return D2D1_COMPOSITE_MODE_SOURCE_COPY;
case wxCOMPOSITION_OVER:
return D2D1_COMPOSITE_MODE_SOURCE_OVER;
case wxCOMPOSITION_IN:
return D2D1_COMPOSITE_MODE_SOURCE_IN;
case wxCOMPOSITION_OUT:
return D2D1_COMPOSITE_MODE_SOURCE_OUT;
case wxCOMPOSITION_ATOP:
return D2D1_COMPOSITE_MODE_SOURCE_ATOP;
case wxCOMPOSITION_DEST_OVER:
return D2D1_COMPOSITE_MODE_DESTINATION_OVER;
case wxCOMPOSITION_DEST_IN:
return D2D1_COMPOSITE_MODE_DESTINATION_IN;
case wxCOMPOSITION_DEST_OUT:
return D2D1_COMPOSITE_MODE_DESTINATION_OUT;
case wxCOMPOSITION_DEST_ATOP:
return D2D1_COMPOSITE_MODE_DESTINATION_ATOP;
case wxCOMPOSITION_XOR:
return D2D1_COMPOSITE_MODE_XOR;
case wxCOMPOSITION_ADD:
return D2D1_COMPOSITE_MODE_PLUS;
// unsupported composition modes
case wxCOMPOSITION_DEST:
wxFALLTHROUGH;
case wxCOMPOSITION_CLEAR:
wxFALLTHROUGH;
case wxCOMPOSITION_INVALID:
return D2D1_COMPOSITE_MODE_SOURCE_COPY;
}
wxFAIL_MSG("unknown composition mode");
return D2D1_COMPOSITE_MODE_SOURCE_COPY;
}
#endif // wxD2D_DEVICE_CONTEXT_SUPPORTED
// Direct2D 1.1 introduces a new enum for specifying the interpolation quality
// which is only used with the ID2D1DeviceContext::DrawImage method.
#if wxD2D_DEVICE_CONTEXT_SUPPORTED
D2D1_INTERPOLATION_MODE wxD2DConvertInterpolationMode(wxInterpolationQuality interpolationQuality)
{
switch (interpolationQuality)
{
case wxINTERPOLATION_DEFAULT:
wxFALLTHROUGH;
case wxINTERPOLATION_NONE:
wxFALLTHROUGH;
case wxINTERPOLATION_FAST:
return D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
case wxINTERPOLATION_GOOD:
return D2D1_INTERPOLATION_MODE_LINEAR;
case wxINTERPOLATION_BEST:
return D2D1_INTERPOLATION_MODE_CUBIC;
}
wxFAIL_MSG("unknown interpolation quality");
return D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
}
#endif // wxD2D_DEVICE_CONTEXT_SUPPORTED
D2D1_BITMAP_INTERPOLATION_MODE wxD2DConvertBitmapInterpolationMode(wxInterpolationQuality interpolationQuality)
{
switch (interpolationQuality)
{
case wxINTERPOLATION_DEFAULT:
wxFALLTHROUGH;
case wxINTERPOLATION_NONE:
wxFALLTHROUGH;
case wxINTERPOLATION_FAST:
wxFALLTHROUGH;
case wxINTERPOLATION_GOOD:
return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
case wxINTERPOLATION_BEST:
return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
}
wxFAIL_MSG("unknown interpolation quality");
return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
}
D2D1_RECT_F wxD2DConvertRect(const wxRect& rect)
{
return D2D1::RectF(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
}
wxCOMPtr<ID2D1Geometry> wxD2DConvertRegionToGeometry(ID2D1Factory* direct2dFactory, const wxRegion& region)
{
// Build the array of geometries
HRESULT hr;
int i;
ID2D1Geometry** geometries;
int rectCount;
if ( region.IsEmpty() )
{
// Empty region is skipped by iterator
// so we have to create it in a special way.
rectCount = 1;
geometries = new ID2D1Geometry*[rectCount];
geometries[0] = NULL;
hr = direct2dFactory->CreateRectangleGeometry(
D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F),
(ID2D1RectangleGeometry**)(&geometries[0]));
wxFAILED_HRESULT_MSG(hr);
}
else
{
// Count the number of rectangles which compose the region
wxRegionIterator regionIterator(region);
rectCount = 0;
while(regionIterator++)
rectCount++;
geometries = new ID2D1Geometry*[rectCount];
regionIterator.Reset(region);
i = 0;
while(regionIterator)
{
geometries[i] = NULL;
wxRect rect = regionIterator.GetRect();
rect.SetWidth(rect.GetWidth() + 1);
rect.SetHeight(rect.GetHeight() + 1);
hr = direct2dFactory->CreateRectangleGeometry(
wxD2DConvertRect(rect),
(ID2D1RectangleGeometry**)(&geometries[i]));
wxFAILED_HRESULT_MSG(hr);
i++;
++regionIterator;
}
}
// Create a geometry group to hold all the rectangles
wxCOMPtr<ID2D1GeometryGroup> resultGeometry;
hr = direct2dFactory->CreateGeometryGroup(
D2D1_FILL_MODE_WINDING,
geometries,
rectCount,
&resultGeometry);
wxFAILED_HRESULT_MSG(hr);
// Cleanup temporaries
for (i = 0; i < rectCount; ++i)
{
geometries[i]->Release();
}
delete[] geometries;
return wxCOMPtr<ID2D1Geometry>(resultGeometry);
}
class wxD2DOffsetHelper
{
public:
wxD2DOffsetHelper(wxGraphicsContext* g) : m_context(g)
{
if (m_context->ShouldOffset())
{
m_context->Translate(0.5, 0.5);
}
}
~wxD2DOffsetHelper()
{
if (m_context->ShouldOffset())
{
m_context->Translate(-0.5, -0.5);
}
}
private:
wxGraphicsContext* m_context;
};
bool operator==(const D2D1::Matrix3x2F& lhs, const D2D1::Matrix3x2F& rhs)
{
return
lhs._11 == rhs._11 && lhs._12 == rhs._12 &&
lhs._21 == rhs._21 && lhs._22 == rhs._22 &&
lhs._31 == rhs._31 && lhs._32 == rhs._32;
}
//-----------------------------------------------------------------------------
// wxD2DMatrixData declaration
//-----------------------------------------------------------------------------
class wxD2DMatrixData : public wxGraphicsMatrixData
{
public:
wxD2DMatrixData(wxGraphicsRenderer* renderer);
wxD2DMatrixData(wxGraphicsRenderer* renderer, const D2D1::Matrix3x2F& matrix);
virtual wxGraphicsObjectRefData* Clone() const wxOVERRIDE;
void Concat(const wxGraphicsMatrixData* t) wxOVERRIDE;
void Set(wxDouble a = 1.0, wxDouble b = 0.0, wxDouble c = 0.0, wxDouble d = 1.0,
wxDouble tx = 0.0, wxDouble ty = 0.0) wxOVERRIDE;
void Get(wxDouble* a = NULL, wxDouble* b = NULL, wxDouble* c = NULL,
wxDouble* d = NULL, wxDouble* tx = NULL, wxDouble* ty = NULL) const wxOVERRIDE;
void Invert() wxOVERRIDE;
bool IsEqual(const wxGraphicsMatrixData* t) const wxOVERRIDE;
bool IsIdentity() const wxOVERRIDE;
void Translate(wxDouble dx, wxDouble dy) wxOVERRIDE;
void Scale(wxDouble xScale, wxDouble yScale) wxOVERRIDE;
void Rotate(wxDouble angle) wxOVERRIDE;
void TransformPoint(wxDouble* x, wxDouble* y) const wxOVERRIDE;
void TransformDistance(wxDouble* dx, wxDouble* dy) const wxOVERRIDE;
void* GetNativeMatrix() const wxOVERRIDE;
D2D1::Matrix3x2F GetMatrix3x2F() const;
private:
D2D1::Matrix3x2F m_matrix;
};
//-----------------------------------------------------------------------------
// wxD2DMatrixData implementation
//-----------------------------------------------------------------------------
wxD2DMatrixData::wxD2DMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
{
m_matrix = D2D1::Matrix3x2F::Identity();
}
wxD2DMatrixData::wxD2DMatrixData(wxGraphicsRenderer* renderer, const D2D1::Matrix3x2F& matrix) :
wxGraphicsMatrixData(renderer), m_matrix(matrix)
{
}
wxGraphicsObjectRefData* wxD2DMatrixData::Clone() const
{
return new wxD2DMatrixData(GetRenderer(), m_matrix);
}
void wxD2DMatrixData::Concat(const wxGraphicsMatrixData* t)
{
// Elements of resulting matrix are modified in-place in SetProduct()
// so multiplied matrices cannot be the instances of the resulting matrix.
// Note that parameter matrix (t) is the multiplicand.
const D2D1::Matrix3x2F m1(static_cast<const wxD2DMatrixData*>(t)->m_matrix);
const D2D1::Matrix3x2F m2(m_matrix);
m_matrix.SetProduct(m1, m2);
}
void wxD2DMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, wxDouble tx, wxDouble ty)
{
m_matrix._11 = a;
m_matrix._12 = b;
m_matrix._21 = c;
m_matrix._22 = d;
m_matrix._31 = tx;
m_matrix._32 = ty;
}
void wxD2DMatrixData::Get(wxDouble* a, wxDouble* b, wxDouble* c, wxDouble* d, wxDouble* tx, wxDouble* ty) const
{
*a = m_matrix._11;
*b = m_matrix._12;
*c = m_matrix._21;
*d = m_matrix._22;
*tx = m_matrix._31;
*ty = m_matrix._32;
}
void wxD2DMatrixData::Invert()
{
m_matrix.Invert();
}
bool wxD2DMatrixData::IsEqual(const wxGraphicsMatrixData* t) const
{
return m_matrix == static_cast<const wxD2DMatrixData*>(t)->m_matrix;
}
bool wxD2DMatrixData::IsIdentity() const
{
return m_matrix.IsIdentity();
}
void wxD2DMatrixData::Translate(wxDouble dx, wxDouble dy)
{
m_matrix = D2D1::Matrix3x2F::Translation(dx, dy) * m_matrix;
}
void wxD2DMatrixData::Scale(wxDouble xScale, wxDouble yScale)
{
m_matrix = D2D1::Matrix3x2F::Scale(xScale, yScale) * m_matrix;
}
void wxD2DMatrixData::Rotate(wxDouble angle)
{
m_matrix = D2D1::Matrix3x2F::Rotation(wxRadToDeg(angle)) * m_matrix;
}
void wxD2DMatrixData::TransformPoint(wxDouble* x, wxDouble* y) const
{
D2D1_POINT_2F result = m_matrix.TransformPoint(D2D1::Point2F(*x, *y));
*x = result.x;
*y = result.y;
}
void wxD2DMatrixData::TransformDistance(wxDouble* dx, wxDouble* dy) const
{
D2D1::Matrix3x2F noTranslationMatrix = m_matrix;
noTranslationMatrix._31 = 0;
noTranslationMatrix._32 = 0;
D2D1_POINT_2F result = noTranslationMatrix.TransformPoint(D2D1::Point2F(*dx, *dy));
*dx = result.x;
*dy = result.y;
}
void* wxD2DMatrixData::GetNativeMatrix() const