1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/graphicsd2d.cpp
3 // Purpose:     Implementation of Direct2D Render Context
4 // Author:      Pana Alexandru <astronothing@gmail.com>
5 // Created:     2014-05-20
6 // Copyright:   (c) 2014 wxWidgets development team
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 #include "wx/wxprec.h"
11 
12 #if wxUSE_GRAPHICS_DIRECT2D
13 
14 // Minimum supported client: Windows 8 and Platform Update for Windows 7
15 #define wxD2D_DEVICE_CONTEXT_SUPPORTED 0
16 
17 // We load these functions at runtime from the d2d1.dll.
18 // However, since they are also used inside the d2d1.h header we must provide
19 // implementations matching the exact declarations. These defines ensures we
20 // are not violating the ODR rule.
21 #define D2D1CreateFactory wxD2D1CreateFactory
22 #define D2D1MakeRotateMatrix wxD2D1MakeRotateMatrix
23 #define D2D1MakeSkewMatrix wxD2D1MakeSkewMatrix
24 #define D2D1IsMatrixInvertible wxD2D1IsMatrixInvertible
25 #define D2D1InvertMatrix wxD2D1InvertMatrix
26 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
27 #define D3D11CreateDevice wxD3D11CreateDevice
28 #endif
29 
30 // There are clashes between the names of the member fields and parameters
31 // in the standard d2d1helper.h header resulting in C4458 with VC14,
32 // so disable this warning for this file as there is no other way to
33 // avoid it.
34 #ifdef __VISUALC__
35     #pragma warning(push)
36     #pragma warning(disable:4458) // declaration of 'xxx' hides class member
37 #endif
38 
39 #include "wx/msw/private/graphicsd2d.h"
40 
41 #ifdef __MINGW64_TOOLCHAIN__
42 #ifndef DWRITE_E_NOFONT
43 #define DWRITE_E_NOFONT _HRESULT_TYPEDEF_(0x88985002L)
44 #endif
45 #endif
46 
47 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
48 #include <d3d11.h>
49 #include <d2d1_1.h>
50 #include <dxgi1_2.h>
51 #endif
52 
53 #ifdef __VISUALC__
54     #pragma warning(pop)
55 #endif
56 
57 #include <float.h> // for FLT_MAX, FLT_MIN
58 
59 #ifndef WX_PRECOMP
60     #include "wx/dc.h"
61     #include "wx/dcclient.h"
62     #include "wx/dcmemory.h"
63     #include "wx/image.h"
64     #include "wx/module.h"
65     #include "wx/window.h"
66     #include "wx/msw/private.h"
67 #endif // !WX_PRECOMP
68 
69 #include "wx/graphics.h"
70 #include "wx/dynlib.h"
71 #include "wx/msw/ole/comimpl.h"
72 #include "wx/msw/private/comptr.h"
73 #include "wx/private/graphics.h"
74 #include "wx/stack.h"
75 #include "wx/sharedptr.h"
76 
77 // This must be the last header included to only affect the DEFINE_GUID()
78 // occurrences below but not any GUIDs declared in the standard files included
79 // above.
80 #include <initguid.h>
81 
82 // Generic error message for a failed direct2d operation
83 #define wxFAILED_HRESULT_MSG(result) \
84     wxString::Format("Direct2D failed with HRESULT %x", (result))
85 
86 // Checks a HRESULT value for success, otherwise displays an error message and
87 // returns from the enclosing function.
88 #define wxCHECK_HRESULT_RET(result) \
89     wxCHECK_RET(SUCCEEDED(result), wxFAILED_HRESULT_MSG(result))
90 
91 #define wxCHECK2_HRESULT_RET(result, returnValue)                             \
92     wxCHECK2_MSG(SUCCEEDED(result), return returnValue,                       \
93         wxFAILED_HRESULT_MSG(result))
94 
95 // Variation of wxCHECK_HRESULT_RET for functions which must return a pointer
96 #define wxCHECK_HRESULT_RET_PTR(result) wxCHECK2_HRESULT_RET(result, NULL)
97 
98 // Checks the precondition of wxManagedResourceHolder::AcquireResource, namely
99 // that it is bound to a manager.
100 #define wxCHECK_RESOURCE_HOLDER_PRE()                                         \
101     {                                                                         \
102     if (IsResourceAcquired()) return;                                         \
103     wxCHECK_RET(IsBound(),                                                    \
104         "Cannot acquire a native resource without being bound to a manager"); \
105     }
106 
107 // Checks the postcondition of wxManagedResourceHolder::AcquireResource, namely
108 // that it was successful in acquiring the native resource.
109 #define wxCHECK_RESOURCE_HOLDER_POST() \
110     wxCHECK_RET(m_nativeResource != NULL, "Could not acquire native resource");
111 
112 
113 // Helper class used to check for direct2d availability at runtime and to
114 // dynamically load the required symbols from d2d1.dll and dwrite.dll
115 class wxDirect2D
116 {
117 public:
118 
119     enum wxD2DVersion
120     {
121         wxD2D_VERSION_1_0,
122         wxD2D_VERSION_1_1,
123         wxD2D_VERSION_NONE
124     };
125 
Initialize()126     static bool Initialize()
127     {
128         if (!m_initialized)
129         {
130             m_hasDirect2DSupport = LoadLibraries();
131             m_initialized = true;
132         }
133 
134         return m_hasDirect2DSupport;
135     }
136 
HasDirect2DSupport()137     static bool HasDirect2DSupport()
138     {
139         Initialize();
140 
141         return m_hasDirect2DSupport;
142     }
143 
GetDirect2DVersion()144     static wxD2DVersion GetDirect2DVersion()
145     {
146         return m_D2DRuntimeVersion;
147     }
148 
149 private:
LoadLibraries()150     static bool LoadLibraries()
151     {
152         if ( !m_dllDirect2d.Load(wxT("d2d1.dll"), wxDL_VERBATIM | wxDL_QUIET) )
153             return false;
154 
155         if ( !m_dllDirectWrite.Load(wxT("dwrite.dll"), wxDL_VERBATIM | wxDL_QUIET) )
156             return false;
157 
158 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
159         if (!m_dllDirect3d.Load(wxT("d3d11.dll"), wxDL_VERBATIM | wxDL_QUIET))
160             return false;
161 #endif
162 
163         #define wxLOAD_FUNC(dll, name)                    \
164         name = (name##_t)dll.RawGetSymbol(#name);         \
165             if ( !name )                                  \
166             return false;
167 
168         wxLOAD_FUNC(m_dllDirect2d, D2D1CreateFactory);
169         wxLOAD_FUNC(m_dllDirect2d, D2D1MakeRotateMatrix);
170         wxLOAD_FUNC(m_dllDirect2d, D2D1MakeSkewMatrix);
171         wxLOAD_FUNC(m_dllDirect2d, D2D1IsMatrixInvertible);
172         wxLOAD_FUNC(m_dllDirect2d, D2D1InvertMatrix);
173         wxLOAD_FUNC(m_dllDirectWrite, DWriteCreateFactory);
174 
175 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
176         wxLOAD_FUNC(m_dllDirect3d, D3D11CreateDevice);
177         m_D2DRuntimeVersion = wxD2D_VERSION_1_1;
178 #else
179         m_D2DRuntimeVersion = wxD2D_VERSION_1_0;
180 #endif
181 
182         return true;
183     }
184 
185 public:
186     typedef HRESULT (WINAPI *D2D1CreateFactory_t)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS*, void**);
187     static D2D1CreateFactory_t D2D1CreateFactory;
188 
189     typedef void (WINAPI *D2D1MakeRotateMatrix_t)(FLOAT, D2D1_POINT_2F, D2D1_MATRIX_3X2_F*);
190     static D2D1MakeRotateMatrix_t D2D1MakeRotateMatrix;
191 
192     typedef void (WINAPI *D2D1MakeSkewMatrix_t)(FLOAT, FLOAT, D2D1_POINT_2F, D2D1_MATRIX_3X2_F*);
193     static D2D1MakeSkewMatrix_t D2D1MakeSkewMatrix;
194 
195     typedef BOOL (WINAPI *D2D1IsMatrixInvertible_t)(const D2D1_MATRIX_3X2_F*);
196     static D2D1IsMatrixInvertible_t D2D1IsMatrixInvertible;
197 
198     typedef BOOL (WINAPI *D2D1InvertMatrix_t)(D2D1_MATRIX_3X2_F*);
199     static D2D1InvertMatrix_t D2D1InvertMatrix;
200 
201     typedef HRESULT (WINAPI *DWriteCreateFactory_t)(DWRITE_FACTORY_TYPE, REFIID, IUnknown**);
202     static DWriteCreateFactory_t DWriteCreateFactory;
203 
204 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
205     typedef HRESULT (WINAPI *D3D11CreateDevice_t)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**);
206     static D3D11CreateDevice_t D3D11CreateDevice;
207 #endif
208 
209 private:
210     static bool m_initialized;
211     static bool m_hasDirect2DSupport;
212     static wxD2DVersion m_D2DRuntimeVersion;
213 
214     static wxDynamicLibrary m_dllDirect2d;
215     static wxDynamicLibrary m_dllDirectWrite;
216 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
217     static wxDynamicLibrary m_dllDirect3d;
218 #endif
219 };
220 
221 // define the members
222 bool wxDirect2D::m_initialized = false;
223 bool wxDirect2D::m_hasDirect2DSupport = false;
224 wxDirect2D::wxD2DVersion wxDirect2D::m_D2DRuntimeVersion = wxD2D_VERSION_NONE;
225 
226 wxDynamicLibrary wxDirect2D::m_dllDirect2d;
227 wxDynamicLibrary wxDirect2D::m_dllDirectWrite;
228 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
229 wxDynamicLibrary wxDirect2D::m_dllDirect3d;
230 #endif
231 
232 // define the (not yet imported) functions
233 wxDirect2D::D2D1CreateFactory_t wxDirect2D::D2D1CreateFactory = NULL;
234 wxDirect2D::D2D1MakeRotateMatrix_t wxDirect2D::D2D1MakeRotateMatrix = NULL;
235 wxDirect2D::D2D1MakeSkewMatrix_t wxDirect2D::D2D1MakeSkewMatrix = NULL;
236 wxDirect2D::D2D1IsMatrixInvertible_t wxDirect2D::D2D1IsMatrixInvertible = NULL;
237 wxDirect2D::D2D1InvertMatrix_t wxDirect2D::D2D1InvertMatrix = NULL;
238 wxDirect2D::DWriteCreateFactory_t wxDirect2D::DWriteCreateFactory = NULL;
239 
240 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
241 wxDirect2D::D3D11CreateDevice_t wxDirect2D::D3D11CreateDevice = NULL;
242 #endif
243 
244 // define the interface GUIDs
245 DEFINE_GUID(wxIID_IWICImagingFactory,
246             0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70);
247 
248 DEFINE_GUID(wxIID_ID2D1Factory,
249             0x06152247, 0x6f50, 0x465a, 0x92, 0x45, 0x11, 0x8b, 0xfd, 0x3b, 0x60, 0x07);
250 
251 DEFINE_GUID(wxIID_IDWriteFactory,
252             0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48);
253 
254 DEFINE_GUID(wxIID_IWICBitmapSource,
255             0x00000120, 0xa8f2, 0x4877, 0xba, 0x0a, 0xfd, 0x2b, 0x66, 0x45, 0xfb, 0x94);
256 
257 DEFINE_GUID(GUID_WICPixelFormat32bppPBGRA,
258             0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10);
259 
260 DEFINE_GUID(GUID_WICPixelFormat32bppBGR,
261             0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e);
262 
263 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
264 DEFINE_GUID(IID_IDXGIDevice,
265             0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c);
266 #endif
267 
268 #ifndef CLSID_WICImagingFactory
269 DEFINE_GUID(CLSID_WICImagingFactory,
270             0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa);
271 #endif
272 
273 #if wxUSE_PRIVATE_FONTS
274 DEFINE_GUID(wxIID_IDWriteFontFileEnumerator,
275             0x72755049, 0x5ff7, 0x435d, 0x83, 0x48, 0x4b, 0xe9, 0x7c, 0xfa, 0x6c, 0x7c);
276 
277 DEFINE_GUID(wxIID_IDWriteFontCollectionLoader,
278             0xcca920e4, 0x52f0, 0x492b, 0xbf, 0xa8, 0x29, 0xc7, 0x2e, 0xe0, 0xa4, 0x68);
279 #endif // wxUSE_PRIVATE_FONTS
280 
281 // Implementation of the Direct2D functions
wxD2D1CreateFactory(D2D1_FACTORY_TYPE factoryType,REFIID riid,CONST D2D1_FACTORY_OPTIONS * pFactoryOptions,void ** ppIFactory)282 HRESULT WINAPI wxD2D1CreateFactory(
283     D2D1_FACTORY_TYPE factoryType,
284     REFIID riid,
285     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
286     void **ppIFactory)
287 {
288     if (!wxDirect2D::Initialize())
289         return S_FALSE;
290 
291     return wxDirect2D::D2D1CreateFactory(
292         factoryType,
293         riid,
294         pFactoryOptions,
295         ppIFactory);
296 }
297 
wxD2D1MakeRotateMatrix(FLOAT angle,D2D1_POINT_2F center,D2D1_MATRIX_3X2_F * matrix)298 void WINAPI wxD2D1MakeRotateMatrix(
299     FLOAT angle,
300     D2D1_POINT_2F center,
301     D2D1_MATRIX_3X2_F *matrix)
302 {
303     if (!wxDirect2D::Initialize())
304         return;
305 
306     wxDirect2D::D2D1MakeRotateMatrix(angle, center, matrix);
307 }
308 
wxD2D1MakeSkewMatrix(FLOAT angleX,FLOAT angleY,D2D1_POINT_2F center,D2D1_MATRIX_3X2_F * matrix)309 void WINAPI wxD2D1MakeSkewMatrix(
310     FLOAT angleX,
311     FLOAT angleY,
312     D2D1_POINT_2F center,
313     D2D1_MATRIX_3X2_F *matrix)
314 {
315     if (!wxDirect2D::Initialize())
316         return;
317 
318     wxDirect2D::D2D1MakeSkewMatrix(angleX, angleY, center, matrix);
319 }
320 
wxD2D1IsMatrixInvertible(const D2D1_MATRIX_3X2_F * matrix)321 BOOL WINAPI wxD2D1IsMatrixInvertible(
322     const D2D1_MATRIX_3X2_F *matrix)
323 {
324     if (!wxDirect2D::Initialize())
325         return FALSE;
326 
327     return wxDirect2D::D2D1IsMatrixInvertible(matrix);
328 }
329 
wxD2D1InvertMatrix(D2D1_MATRIX_3X2_F * matrix)330 BOOL WINAPI wxD2D1InvertMatrix(
331     D2D1_MATRIX_3X2_F *matrix)
332 {
333     if (!wxDirect2D::Initialize())
334         return FALSE;
335 
336     return wxDirect2D::D2D1InvertMatrix(matrix);
337 }
338 
339 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
wxD3D11CreateDevice(IDXGIAdapter * pAdapter,D3D_DRIVER_TYPE DriverType,HMODULE Software,UINT Flags,CONST D3D_FEATURE_LEVEL * pFeatureLevels,UINT FeatureLevels,UINT SDKVersion,ID3D11Device ** ppDevice,D3D_FEATURE_LEVEL * pFeatureLevel,ID3D11DeviceContext ** ppImmediateContext)340 HRESULT WINAPI wxD3D11CreateDevice(
341     IDXGIAdapter* pAdapter,
342     D3D_DRIVER_TYPE DriverType,
343     HMODULE Software,
344     UINT Flags,
345     CONST D3D_FEATURE_LEVEL* pFeatureLevels,
346     UINT FeatureLevels,
347     UINT SDKVersion,
348     ID3D11Device** ppDevice,
349     D3D_FEATURE_LEVEL* pFeatureLevel,
350     ID3D11DeviceContext** ppImmediateContext)
351 {
352     if (!wxDirect2D::Initialize())
353         return S_FALSE;
354 
355     return wxDirect2D::D3D11CreateDevice(
356         pAdapter,
357         DriverType,
358         Software,
359         Flags,
360         pFeatureLevels,
361         FeatureLevels,
362         SDKVersion,
363         ppDevice,
364         pFeatureLevel,
365         ppImmediateContext);
366 }
367 #endif
368 
369 #if wxUSE_PRIVATE_FONTS
370 
371 // This function is defined in src/msw/font.cpp.
372 extern const wxArrayString& wxGetPrivateFontFileNames();
373 
374 namespace
375 {
376 wxCOMPtr<IDWriteFontCollection> gs_pPrivateFontCollection;
377 
378 typedef unsigned int wxDirect2DFontKey;
379 
380 class wxDirect2DFontFileEnumerator : public IDWriteFontFileEnumerator
381 {
382 public:
wxDirect2DFontFileEnumerator(IDWriteFactory * pFactory,const wxArrayString & fontCollection)383     wxDirect2DFontFileEnumerator(IDWriteFactory* pFactory, const wxArrayString& fontCollection)
384         : m_factory(pFactory)
385         , m_filePaths(fontCollection)
386         , m_nextIndex(0)
387     {
388     }
389 
~wxDirect2DFontFileEnumerator()390     virtual ~wxDirect2DFontFileEnumerator()
391     {
392     }
393 
394     // IDWriteFontFileEnumerator methods
MoveNext(BOOL * pHasCurrentFile)395     virtual wxSTDMETHODIMP MoveNext(BOOL* pHasCurrentFile) wxOVERRIDE
396     {
397         HRESULT hr = S_OK;
398 
399         *pHasCurrentFile = FALSE;
400         m_currentFile.reset();
401 
402         if ( m_nextIndex < m_filePaths.size() )
403         {
404             hr = m_factory->CreateFontFileReference(m_filePaths[m_nextIndex].wc_str(), NULL, &m_currentFile);
405             if ( SUCCEEDED(hr) )
406             {
407                 *pHasCurrentFile = TRUE;
408                 ++m_nextIndex;
409             }
410         }
411 
412         return hr;
413     }
414 
GetCurrentFontFile(IDWriteFontFile ** ppFontFile)415     virtual wxSTDMETHODIMP GetCurrentFontFile(IDWriteFontFile** ppFontFile) wxOVERRIDE
416     {
417         if ( m_currentFile )
418         {
419             m_currentFile.get()->AddRef();
420         }
421         *ppFontFile = m_currentFile;
422 
423         return m_currentFile ? S_OK : E_FAIL;
424     }
425 
426     // IUnknown methods
427     DECLARE_IUNKNOWN_METHODS;
428 
429 private:
430     wxCOMPtr<IDWriteFactory> m_factory;
431     wxCOMPtr<IDWriteFontFile> m_currentFile;
432     wxArrayString m_filePaths;
433     size_t m_nextIndex;
434 
435     wxDECLARE_NO_COPY_CLASS(wxDirect2DFontFileEnumerator);
436 };
437 
438 BEGIN_IID_TABLE(wxDirect2DFontFileEnumerator)
439 ADD_IID(Unknown)
440 ADD_RAW_IID(wxIID_IDWriteFontFileEnumerator)
441 END_IID_TABLE;
442 
443 IMPLEMENT_IUNKNOWN_METHODS(wxDirect2DFontFileEnumerator)
444 
445 class wxDirect2DFontCollectionLoader : public IDWriteFontCollectionLoader
446 {
447 public:
wxDirect2DFontCollectionLoader()448     wxDirect2DFontCollectionLoader()
449     {
450         ms_isInitialized = true;
451     }
452 
~wxDirect2DFontCollectionLoader()453     virtual ~wxDirect2DFontCollectionLoader()
454     {
455     }
456 
457     // IDWriteFontCollectionLoader methods
CreateEnumeratorFromKey(IDWriteFactory * pFactory,void const * pCollectionKey,UINT32 collectionKeySize,IDWriteFontFileEnumerator ** pFontFileEnumerator)458     virtual wxSTDMETHODIMP CreateEnumeratorFromKey(IDWriteFactory* pFactory,
459                                         void const* pCollectionKey, UINT32 collectionKeySize,
460                                         IDWriteFontFileEnumerator** pFontFileEnumerator) wxOVERRIDE
461     {
462         if ( !pFontFileEnumerator )
463             return E_INVALIDARG;
464 
465         *pFontFileEnumerator = NULL;
466 
467         if ( collectionKeySize != sizeof(wxDirect2DFontKey) )
468             return E_INVALIDARG;
469 
470         wxDirect2DFontKey key = *static_cast<wxDirect2DFontKey const*>(pCollectionKey);
471         if ( key != ms_key )
472             return E_INVALIDARG;
473 
474         if ( ms_fontList.empty() )
475             return E_INVALIDARG;
476 
477         wxDirect2DFontFileEnumerator* pEnumerator = new wxDirect2DFontFileEnumerator(pFactory, ms_fontList);
478         if ( !pEnumerator )
479             return E_OUTOFMEMORY;
480 
481         pEnumerator->AddRef();
482         *pFontFileEnumerator = pEnumerator;
483 
484         return S_OK;
485     }
486 
487     // Singleton loader instance
GetLoader()488     static IDWriteFontCollectionLoader* GetLoader()
489     {
490         static wxCOMPtr<wxDirect2DFontCollectionLoader> instance(new wxDirect2DFontCollectionLoader());
491 
492         return instance;
493     }
494 
IsInitialized()495     static bool IsInitialized()
496     {
497         return ms_isInitialized;
498     }
499 
SetFontList(const wxArrayString & list)500     static wxDirect2DFontKey SetFontList(const wxArrayString& list)
501     {
502         ms_fontList = list;
503         // Every time font collection is changed, generate unique key
504         return ++ms_key;
505     }
506 
GetFontList()507     static const wxArrayString& GetFontList()
508     {
509         return ms_fontList;
510     }
511 
512     // IUnknown methods
513     DECLARE_IUNKNOWN_METHODS;
514 
515 private:
516     static bool ms_isInitialized;
517     static wxArrayString ms_fontList;
518     static wxDirect2DFontKey ms_key;
519 
520     wxDECLARE_NO_COPY_CLASS(wxDirect2DFontCollectionLoader);
521 };
522 
523 BEGIN_IID_TABLE(wxDirect2DFontCollectionLoader)
524 ADD_IID(Unknown)
525 ADD_RAW_IID(wxIID_IDWriteFontCollectionLoader)
526 END_IID_TABLE;
527 
528 IMPLEMENT_IUNKNOWN_METHODS(wxDirect2DFontCollectionLoader)
529 
530 bool wxDirect2DFontCollectionLoader::ms_isInitialized(false);
531 wxArrayString wxDirect2DFontCollectionLoader::ms_fontList;
532 wxDirect2DFontKey wxDirect2DFontCollectionLoader::ms_key(0);
533 } // anonymous namespace
534 
535 #endif // wxUSE_PRIVATE_FONTS
536 
537 static IWICImagingFactory* gs_WICImagingFactory = NULL;
538 
wxWICImagingFactory()539 IWICImagingFactory* wxWICImagingFactory()
540 {
541     if (gs_WICImagingFactory == NULL) {
542         HRESULT hr = CoCreateInstance(
543             CLSID_WICImagingFactory,
544             NULL,
545             CLSCTX_INPROC_SERVER,
546             wxIID_IWICImagingFactory,
547             (LPVOID*)&gs_WICImagingFactory);
548         wxCHECK_HRESULT_RET_PTR(hr);
549     }
550     return gs_WICImagingFactory;
551 }
552 
553 static ID2D1Factory* gs_ID2D1Factory = NULL;
554 
wxD2D1Factory()555 ID2D1Factory* wxD2D1Factory()
556 {
557     if (!wxDirect2D::Initialize())
558         return NULL;
559 
560     if (gs_ID2D1Factory == NULL)
561     {
562         D2D1_FACTORY_OPTIONS factoryOptions = {D2D1_DEBUG_LEVEL_NONE};
563 
564         // According to
565         // https://msdn.microsoft.com/en-us/library/windows/desktop/ee794287(v=vs.85).aspx
566         // the Direct2D Debug Layer is only available starting with Windows 8
567         // and Visual Studio 2012.
568 #if defined(__WXDEBUG__) && defined(__VISUALC__) && wxCHECK_VISUALC_VERSION(11)
569         if ( wxGetWinVersion() >= wxWinVersion_8 )
570         {
571             factoryOptions.debugLevel = D2D1_DEBUG_LEVEL_WARNING;
572         }
573 #endif  //__WXDEBUG__
574 
575         HRESULT hr = wxDirect2D::D2D1CreateFactory(
576             D2D1_FACTORY_TYPE_SINGLE_THREADED,
577             wxIID_ID2D1Factory,
578             &factoryOptions,
579             reinterpret_cast<void**>(&gs_ID2D1Factory)
580             );
581         wxCHECK_HRESULT_RET_PTR(hr);
582     }
583     return gs_ID2D1Factory;
584 }
585 
586 static IDWriteFactory* gs_IDWriteFactory = NULL;
587 
wxDWriteFactory()588 IDWriteFactory* wxDWriteFactory()
589 {
590     if (!wxDirect2D::Initialize())
591         return NULL;
592 
593     if (gs_IDWriteFactory == NULL)
594     {
595         wxDirect2D::DWriteCreateFactory(
596             DWRITE_FACTORY_TYPE_SHARED,
597             wxIID_IDWriteFactory,
598             reinterpret_cast<IUnknown**>(&gs_IDWriteFactory)
599             );
600 #if wxUSE_PRIVATE_FONTS
601         // Register our custom font loader
602         HRESULT hr = gs_IDWriteFactory->RegisterFontCollectionLoader(wxDirect2DFontCollectionLoader::GetLoader());
603         if ( FAILED(hr) )
604         {
605             wxLogError(_("Could not register custom DirectWrite font loader."));
606         }
607 #endif // wxUSE_PRIVATE_FONTS
608     }
609     return gs_IDWriteFactory;
610 }
611 
612 extern WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen;
613 extern WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush;
614 
615 // We use the notion of a context supplier because the context
616 // needed to create Direct2D resources (namely the RenderTarget)
617 // is itself device-dependent and might change during the lifetime
618 // of the resources which were created from it.
619 template <typename C>
620 class wxContextSupplier
621 {
622 public:
623     typedef C ContextType;
624 
625     virtual C GetContext() = 0;
626 };
627 
628 typedef wxContextSupplier<ID2D1RenderTarget*> wxD2DContextSupplier;
629 
630 // A resource holder manages a generic resource by acquiring
631 // and releasing it on demand.
632 class wxResourceHolder
633 {
634 public:
635     // Acquires the managed resource if necessary (not already acquired)
636     virtual void AcquireResource() = 0;
637 
638     // Releases the managed resource
639     virtual void ReleaseResource() = 0;
640 
641     // Checks if the resources was previously acquired
642     virtual bool IsResourceAcquired() = 0;
643 
644     // Returns the managed resource or NULL if the resources
645     // was not previously acquired
646     virtual void* GetResource() = 0;
647 
~wxResourceHolder()648     virtual ~wxResourceHolder() {}
649 };
650 
651 class wxD2DResourceManager;
652 
653 class wxD2DManagedObject
654 {
655 public:
656     virtual void Bind(wxD2DResourceManager* manager) = 0;
657     virtual void UnBind() = 0;
658     virtual bool IsBound() = 0;
659     virtual wxD2DResourceManager* GetManager() = 0;
660 
~wxD2DManagedObject()661     virtual ~wxD2DManagedObject() {}
662 };
663 
664 class wxManagedResourceHolder : public wxResourceHolder, public wxD2DManagedObject
665 {
666 public:
~wxManagedResourceHolder()667     virtual ~wxManagedResourceHolder() {}
668 };
669 
670 // A Direct2D resource manager handles the device-dependent
671 // resource holders attached to it by requesting them to
672 // release their resources when the API invalidates.
673 // NOTE: We're using a list because we expect to have multiple
674 // insertions but very rarely a traversal (if ever).
675 WX_DECLARE_LIST(wxManagedResourceHolder, wxManagedResourceListType);
676 #include <wx/listimpl.cpp>
677 WX_DEFINE_LIST(wxManagedResourceListType);
678 
679 class wxD2DResourceManager: public wxD2DContextSupplier
680 {
681 public:
RegisterResourceHolder(wxManagedResourceHolder * resourceHolder)682     void RegisterResourceHolder(wxManagedResourceHolder* resourceHolder)
683     {
684         m_resources.push_back(resourceHolder);
685     }
686 
UnregisterResourceHolder(wxManagedResourceHolder * resourceHolder)687     void UnregisterResourceHolder(wxManagedResourceHolder* resourceHolder)
688     {
689         m_resources.remove(resourceHolder);
690     }
691 
ReleaseResources()692     void ReleaseResources()
693     {
694         wxManagedResourceListType::iterator it;
695         for (it = m_resources.begin(); it != m_resources.end(); ++it)
696         {
697             (*it)->ReleaseResource();
698         }
699 
700         // Check that all resources were released
701         for (it = m_resources.begin(); it != m_resources.end(); ++it)
702         {
703             wxCHECK_RET(!(*it)->IsResourceAcquired(), "One or more device-dependent resources failed to release");
704         }
705     }
706 
~wxD2DResourceManager()707     virtual ~wxD2DResourceManager()
708     {
709         while (!m_resources.empty())
710         {
711             m_resources.front()->ReleaseResource();
712             m_resources.front()->UnBind();
713         }
714     }
715 
716 private:
717     wxManagedResourceListType m_resources;
718 };
719 
720 // A Direct2D resource holder manages device dependent resources
721 // by storing any information necessary for acquiring the resource
722 // and releasing the resource when the API invalidates it.
723 template<typename T>
724 class wxD2DResourceHolder: public wxManagedResourceHolder
725 {
726 public:
wxD2DResourceHolder()727     wxD2DResourceHolder() : m_resourceManager(NULL)
728     {
729     }
730 
~wxD2DResourceHolder()731     virtual ~wxD2DResourceHolder()
732     {
733         UnBind();
734         ReleaseResource();
735     }
736 
IsResourceAcquired()737     bool IsResourceAcquired() wxOVERRIDE
738     {
739         return m_nativeResource != NULL;
740     }
741 
GetResource()742     void* GetResource() wxOVERRIDE
743     {
744         return GetD2DResource();
745     }
746 
GetD2DResource()747     wxCOMPtr<T>& GetD2DResource()
748     {
749         if (!IsResourceAcquired())
750         {
751             AcquireResource();
752         }
753 
754         return m_nativeResource;
755     }
756 
AcquireResource()757     void AcquireResource() wxOVERRIDE
758     {
759         wxCHECK_RESOURCE_HOLDER_PRE();
760 
761         DoAcquireResource();
762 
763         wxCHECK_RESOURCE_HOLDER_POST();
764     }
765 
ReleaseResource()766     void ReleaseResource() wxOVERRIDE
767     {
768         m_nativeResource.reset();
769     }
770 
GetContext()771     wxD2DContextSupplier::ContextType GetContext()
772     {
773         return m_resourceManager->GetContext();
774     }
775 
Bind(wxD2DResourceManager * manager)776     void Bind(wxD2DResourceManager* manager) wxOVERRIDE
777     {
778         if (IsBound())
779             return;
780 
781         m_resourceManager = manager;
782         m_resourceManager->RegisterResourceHolder(this);
783     }
784 
UnBind()785     void UnBind() wxOVERRIDE
786     {
787         if (!IsBound())
788             return;
789 
790         m_resourceManager->UnregisterResourceHolder(this);
791         m_resourceManager = NULL;
792     }
793 
IsBound()794     bool IsBound() wxOVERRIDE
795     {
796         return m_resourceManager != NULL;
797     }
798 
GetManager()799     wxD2DResourceManager* GetManager() wxOVERRIDE
800     {
801         return m_resourceManager;
802     }
803 
804 protected:
805     virtual void DoAcquireResource() = 0;
806 
807 private:
808     wxD2DResourceManager* m_resourceManager;
809 
810 protected:
811     wxCOMPtr<T> m_nativeResource;
812 };
813 
814 // Used as super class for graphics data objects
815 // to forward the bindings to their internal resource holder.
816 class wxD2DManagedGraphicsData : public wxD2DManagedObject
817 {
818 public:
Bind(wxD2DResourceManager * manager)819     void Bind(wxD2DResourceManager* manager) wxOVERRIDE
820     {
821         GetManagedObject()->Bind(manager);
822     }
823 
UnBind()824     void UnBind() wxOVERRIDE
825     {
826         GetManagedObject()->UnBind();
827     }
828 
IsBound()829     bool IsBound() wxOVERRIDE
830     {
831         return GetManagedObject()->IsBound();
832     }
833 
GetManager()834     wxD2DResourceManager* GetManager() wxOVERRIDE
835     {
836         return GetManagedObject()->GetManager();
837     }
838 
839     virtual wxD2DManagedObject* GetManagedObject() = 0;
840 
~wxD2DManagedGraphicsData()841     ~wxD2DManagedGraphicsData() {}
842 };
843 
wxD2DConvertPenCap(wxPenCap cap)844 D2D1_CAP_STYLE wxD2DConvertPenCap(wxPenCap cap)
845 {
846     switch (cap)
847     {
848     case wxCAP_ROUND:
849         return D2D1_CAP_STYLE_ROUND;
850     case wxCAP_PROJECTING:
851         return D2D1_CAP_STYLE_SQUARE;
852     case wxCAP_BUTT:
853         return D2D1_CAP_STYLE_FLAT;
854     case wxCAP_INVALID:
855         return D2D1_CAP_STYLE_FLAT;
856     }
857 
858     wxFAIL_MSG("unknown pen cap");
859     return D2D1_CAP_STYLE_FLAT;
860 }
861 
wxD2DConvertPenJoin(wxPenJoin join)862 D2D1_LINE_JOIN wxD2DConvertPenJoin(wxPenJoin join)
863 {
864     switch (join)
865     {
866     case wxJOIN_BEVEL:
867         return D2D1_LINE_JOIN_BEVEL;
868     case wxJOIN_MITER:
869         return D2D1_LINE_JOIN_MITER;
870     case wxJOIN_ROUND:
871         return D2D1_LINE_JOIN_ROUND;
872     case wxJOIN_INVALID:
873         return D2D1_LINE_JOIN_MITER;
874     }
875 
876     wxFAIL_MSG("unknown pen join");
877     return D2D1_LINE_JOIN_MITER;
878 }
879 
wxD2DConvertPenStyle(wxPenStyle dashStyle)880 D2D1_DASH_STYLE wxD2DConvertPenStyle(wxPenStyle dashStyle)
881 {
882     switch (dashStyle)
883     {
884     case wxPENSTYLE_SOLID:
885         return D2D1_DASH_STYLE_SOLID;
886     case wxPENSTYLE_DOT:
887         return D2D1_DASH_STYLE_DOT;
888     case wxPENSTYLE_LONG_DASH:
889         return D2D1_DASH_STYLE_DASH;
890     case wxPENSTYLE_SHORT_DASH:
891         return D2D1_DASH_STYLE_DASH;
892     case wxPENSTYLE_DOT_DASH:
893         return D2D1_DASH_STYLE_DASH_DOT;
894     case wxPENSTYLE_USER_DASH:
895         return D2D1_DASH_STYLE_CUSTOM;
896 
897     // NB: These styles cannot be converted to a D2D1_DASH_STYLE
898     // and must be handled separately.
899     case wxPENSTYLE_TRANSPARENT:
900         wxFALLTHROUGH;
901     case wxPENSTYLE_INVALID:
902         wxFALLTHROUGH;
903     case wxPENSTYLE_STIPPLE_MASK_OPAQUE:
904         wxFALLTHROUGH;
905     case wxPENSTYLE_STIPPLE_MASK:
906         wxFALLTHROUGH;
907     case wxPENSTYLE_STIPPLE:
908         wxFALLTHROUGH;
909     case wxPENSTYLE_BDIAGONAL_HATCH:
910         wxFALLTHROUGH;
911     case wxPENSTYLE_CROSSDIAG_HATCH:
912         wxFALLTHROUGH;
913     case wxPENSTYLE_FDIAGONAL_HATCH:
914         wxFALLTHROUGH;
915     case wxPENSTYLE_CROSS_HATCH:
916         wxFALLTHROUGH;
917     case wxPENSTYLE_HORIZONTAL_HATCH:
918         wxFALLTHROUGH;
919     case wxPENSTYLE_VERTICAL_HATCH:
920         return D2D1_DASH_STYLE_SOLID;
921     }
922 
923     wxFAIL_MSG("unknown pen style");
924     return D2D1_DASH_STYLE_SOLID;
925 }
926 
wxD2DConvertColour(wxColour colour)927 D2D1_COLOR_F wxD2DConvertColour(wxColour colour)
928 {
929     return D2D1::ColorF(
930         colour.Red() / 255.0f,
931         colour.Green() / 255.0f,
932         colour.Blue() / 255.0f,
933         colour.Alpha() / 255.0f);
934 }
935 
936 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
wxD2DCompositionModeSupported(wxCompositionMode compositionMode)937 bool wxD2DCompositionModeSupported(wxCompositionMode compositionMode)
938 {
939     if (compositionMode == wxCOMPOSITION_CLEAR || compositionMode == wxCOMPOSITION_INVALID)
940     {
941         return false;
942     }
943 
944     return true;
945 }
946 
wxD2DConvertCompositionMode(wxCompositionMode compositionMode)947 D2D1_COMPOSITE_MODE wxD2DConvertCompositionMode(wxCompositionMode compositionMode)
948 {
949     switch (compositionMode)
950     {
951     case wxCOMPOSITION_SOURCE:
952         return D2D1_COMPOSITE_MODE_SOURCE_COPY;
953     case wxCOMPOSITION_OVER:
954         return D2D1_COMPOSITE_MODE_SOURCE_OVER;
955     case wxCOMPOSITION_IN:
956         return D2D1_COMPOSITE_MODE_SOURCE_IN;
957     case wxCOMPOSITION_OUT:
958         return D2D1_COMPOSITE_MODE_SOURCE_OUT;
959     case wxCOMPOSITION_ATOP:
960         return D2D1_COMPOSITE_MODE_SOURCE_ATOP;
961     case wxCOMPOSITION_DEST_OVER:
962         return D2D1_COMPOSITE_MODE_DESTINATION_OVER;
963     case wxCOMPOSITION_DEST_IN:
964         return D2D1_COMPOSITE_MODE_DESTINATION_IN;
965     case wxCOMPOSITION_DEST_OUT:
966         return D2D1_COMPOSITE_MODE_DESTINATION_OUT;
967     case wxCOMPOSITION_DEST_ATOP:
968         return D2D1_COMPOSITE_MODE_DESTINATION_ATOP;
969     case wxCOMPOSITION_XOR:
970         return D2D1_COMPOSITE_MODE_XOR;
971     case wxCOMPOSITION_ADD:
972         return D2D1_COMPOSITE_MODE_PLUS;
973 
974     // unsupported composition modes
975     case wxCOMPOSITION_DEST:
976         wxFALLTHROUGH;
977     case wxCOMPOSITION_CLEAR:
978         wxFALLTHROUGH;
979     case wxCOMPOSITION_INVALID:
980         return D2D1_COMPOSITE_MODE_SOURCE_COPY;
981     }
982 
983     wxFAIL_MSG("unknown composition mode");
984     return D2D1_COMPOSITE_MODE_SOURCE_COPY;
985 }
986 #endif // wxD2D_DEVICE_CONTEXT_SUPPORTED
987 
988 // Direct2D 1.1 introduces a new enum for specifying the interpolation quality
989 // which is only used with the ID2D1DeviceContext::DrawImage method.
990 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
wxD2DConvertInterpolationMode(wxInterpolationQuality interpolationQuality)991 D2D1_INTERPOLATION_MODE wxD2DConvertInterpolationMode(wxInterpolationQuality interpolationQuality)
992 {
993     switch (interpolationQuality)
994     {
995     case wxINTERPOLATION_DEFAULT:
996         wxFALLTHROUGH;
997     case wxINTERPOLATION_NONE:
998         wxFALLTHROUGH;
999     case wxINTERPOLATION_FAST:
1000         return D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
1001     case wxINTERPOLATION_GOOD:
1002         return D2D1_INTERPOLATION_MODE_LINEAR;
1003     case wxINTERPOLATION_BEST:
1004         return D2D1_INTERPOLATION_MODE_CUBIC;
1005     }
1006 
1007     wxFAIL_MSG("unknown interpolation quality");
1008     return D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
1009 }
1010 #endif // wxD2D_DEVICE_CONTEXT_SUPPORTED
1011 
wxD2DConvertBitmapInterpolationMode(wxInterpolationQuality interpolationQuality)1012 D2D1_BITMAP_INTERPOLATION_MODE wxD2DConvertBitmapInterpolationMode(wxInterpolationQuality interpolationQuality)
1013 {
1014     switch (interpolationQuality)
1015     {
1016     case wxINTERPOLATION_DEFAULT:
1017         wxFALLTHROUGH;
1018     case wxINTERPOLATION_NONE:
1019         wxFALLTHROUGH;
1020     case wxINTERPOLATION_FAST:
1021         wxFALLTHROUGH;
1022     case wxINTERPOLATION_GOOD:
1023         return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
1024     case wxINTERPOLATION_BEST:
1025         return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR;
1026     }
1027 
1028     wxFAIL_MSG("unknown interpolation quality");
1029     return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR;
1030 }
1031 
wxD2DConvertRect(const wxRect & rect)1032 D2D1_RECT_F wxD2DConvertRect(const wxRect& rect)
1033 {
1034     return D2D1::RectF(rect.GetLeft(), rect.GetTop(), rect.GetRight(), rect.GetBottom());
1035 }
1036 
wxD2DConvertRegionToGeometry(ID2D1Factory * direct2dFactory,const wxRegion & region)1037 wxCOMPtr<ID2D1Geometry> wxD2DConvertRegionToGeometry(ID2D1Factory* direct2dFactory, const wxRegion& region)
1038 {
1039     // Build the array of geometries
1040     HRESULT hr;
1041     int i;
1042     ID2D1Geometry** geometries;
1043     int rectCount;
1044     if ( region.IsEmpty() )
1045     {
1046         // Empty region is skipped by iterator
1047         // so we have to create it in a special way.
1048         rectCount = 1;
1049         geometries = new ID2D1Geometry*[rectCount];
1050 
1051         geometries[0] = NULL;
1052         hr = direct2dFactory->CreateRectangleGeometry(
1053                         D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F),
1054                         (ID2D1RectangleGeometry**)(&geometries[0]));
1055         wxFAILED_HRESULT_MSG(hr);
1056     }
1057     else
1058     {
1059         // Count the number of rectangles which compose the region
1060         wxRegionIterator regionIterator(region);
1061         rectCount = 0;
1062         while(regionIterator++)
1063             rectCount++;
1064 
1065         geometries = new ID2D1Geometry*[rectCount];
1066         regionIterator.Reset(region);
1067 
1068         i = 0;
1069         while(regionIterator)
1070         {
1071             geometries[i] = NULL;
1072 
1073             wxRect rect = regionIterator.GetRect();
1074             rect.SetWidth(rect.GetWidth() + 1);
1075             rect.SetHeight(rect.GetHeight() + 1);
1076 
1077             hr = direct2dFactory->CreateRectangleGeometry(
1078                 wxD2DConvertRect(rect),
1079                 (ID2D1RectangleGeometry**)(&geometries[i]));
1080             wxFAILED_HRESULT_MSG(hr);
1081 
1082             i++;
1083             ++regionIterator;
1084         }
1085     }
1086 
1087     // Create a geometry group to hold all the rectangles
1088     wxCOMPtr<ID2D1GeometryGroup> resultGeometry;
1089     hr = direct2dFactory->CreateGeometryGroup(
1090         D2D1_FILL_MODE_WINDING,
1091         geometries,
1092         rectCount,
1093         &resultGeometry);
1094     wxFAILED_HRESULT_MSG(hr);
1095 
1096     // Cleanup temporaries
1097     for (i = 0; i < rectCount; ++i)
1098     {
1099         geometries[i]->Release();
1100     }
1101 
1102     delete[] geometries;
1103 
1104     return wxCOMPtr<ID2D1Geometry>(resultGeometry);
1105 }
1106 
1107 class wxD2DOffsetHelper
1108 {
1109 public:
wxD2DOffsetHelper(wxGraphicsContext * g)1110     explicit wxD2DOffsetHelper(wxGraphicsContext* g)
1111         : m_context(g)
1112     {
1113         m_offset = 0;
1114         if (m_context->ShouldOffset())
1115         {
1116             const wxGraphicsMatrix matrix(m_context->GetTransform());
1117             double x = m_context->GetContentScaleFactor(), y = x;
1118             matrix.TransformDistance(&x, &y);
1119             m_offset = 0.5 / wxMin(fabs(x), fabs(y));
1120             m_context->Translate(m_offset, m_offset);
1121         }
1122     }
1123 
~wxD2DOffsetHelper()1124     ~wxD2DOffsetHelper()
1125     {
1126         if (m_offset > 0)
1127         {
1128             m_context->Translate(-m_offset, -m_offset);
1129         }
1130     }
1131 
1132 private:
1133     wxGraphicsContext* m_context;
1134     double m_offset;
1135 };
1136 
operator ==(const D2D1::Matrix3x2F & lhs,const D2D1::Matrix3x2F & rhs)1137 bool operator==(const D2D1::Matrix3x2F& lhs, const D2D1::Matrix3x2F& rhs)
1138 {
1139     return
1140         lhs._11 == rhs._11 && lhs._12 == rhs._12 &&
1141         lhs._21 == rhs._21 && lhs._22 == rhs._22 &&
1142         lhs._31 == rhs._31 && lhs._32 == rhs._32;
1143 }
1144 
1145 //-----------------------------------------------------------------------------
1146 // wxD2DMatrixData declaration
1147 //-----------------------------------------------------------------------------
1148 
1149 class wxD2DMatrixData : public wxGraphicsMatrixData
1150 {
1151 public:
1152     wxD2DMatrixData(wxGraphicsRenderer* renderer);
1153     wxD2DMatrixData(wxGraphicsRenderer* renderer, const D2D1::Matrix3x2F& matrix);
1154 
1155     virtual wxGraphicsObjectRefData* Clone() const wxOVERRIDE;
1156 
1157     void Concat(const wxGraphicsMatrixData* t) wxOVERRIDE;
1158 
1159     void Set(wxDouble a = 1.0, wxDouble b = 0.0, wxDouble c = 0.0, wxDouble d = 1.0,
1160         wxDouble tx = 0.0, wxDouble ty = 0.0) wxOVERRIDE;
1161 
1162     void Get(wxDouble* a = NULL, wxDouble* b = NULL,  wxDouble* c = NULL,
1163         wxDouble* d = NULL, wxDouble* tx = NULL, wxDouble* ty = NULL) const wxOVERRIDE;
1164 
1165     void Invert() wxOVERRIDE;
1166 
1167     bool IsEqual(const wxGraphicsMatrixData* t) const wxOVERRIDE;
1168 
1169     bool IsIdentity() const wxOVERRIDE;
1170 
1171     void Translate(wxDouble dx, wxDouble dy) wxOVERRIDE;
1172 
1173     void Scale(wxDouble xScale, wxDouble yScale) wxOVERRIDE;
1174 
1175     void Rotate(wxDouble angle) wxOVERRIDE;
1176 
1177     void TransformPoint(wxDouble* x, wxDouble* y) const wxOVERRIDE;
1178 
1179     void TransformDistance(wxDouble* dx, wxDouble* dy) const wxOVERRIDE;
1180 
1181     void* GetNativeMatrix() const wxOVERRIDE;
1182 
1183     D2D1::Matrix3x2F GetMatrix3x2F() const;
1184 
1185 private:
1186     D2D1::Matrix3x2F m_matrix;
1187 };
1188 
1189 //-----------------------------------------------------------------------------
1190 // wxD2DMatrixData implementation
1191 //-----------------------------------------------------------------------------
1192 
wxD2DMatrixData(wxGraphicsRenderer * renderer)1193 wxD2DMatrixData::wxD2DMatrixData(wxGraphicsRenderer* renderer) : wxGraphicsMatrixData(renderer)
1194 {
1195     m_matrix = D2D1::Matrix3x2F::Identity();
1196 }
1197 
wxD2DMatrixData(wxGraphicsRenderer * renderer,const D2D1::Matrix3x2F & matrix)1198 wxD2DMatrixData::wxD2DMatrixData(wxGraphicsRenderer* renderer, const D2D1::Matrix3x2F& matrix) :
1199     wxGraphicsMatrixData(renderer), m_matrix(matrix)
1200 {
1201 }
1202 
Clone() const1203 wxGraphicsObjectRefData* wxD2DMatrixData::Clone() const
1204 {
1205     return new wxD2DMatrixData(GetRenderer(), m_matrix);
1206 }
1207 
Concat(const wxGraphicsMatrixData * t)1208 void wxD2DMatrixData::Concat(const wxGraphicsMatrixData* t)
1209 {
1210     // Elements of resulting matrix are modified in-place in SetProduct()
1211     // so multiplied matrices cannot be the instances of the resulting matrix.
1212     // Note that parameter matrix (t) is the multiplicand.
1213     const D2D1::Matrix3x2F m1(static_cast<const wxD2DMatrixData*>(t)->m_matrix);
1214     const D2D1::Matrix3x2F m2(m_matrix);
1215     m_matrix.SetProduct(m1, m2);
1216 }
1217 
Set(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty)1218 void wxD2DMatrixData::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, wxDouble tx, wxDouble ty)
1219 {
1220     m_matrix._11 = a;
1221     m_matrix._12 = b;
1222     m_matrix._21 = c;
1223     m_matrix._22 = d;
1224     m_matrix._31 = tx;
1225     m_matrix._32 = ty;
1226 }
1227 
Get(wxDouble * a,wxDouble * b,wxDouble * c,wxDouble * d,wxDouble * tx,wxDouble * ty) const1228 void wxD2DMatrixData::Get(wxDouble* a, wxDouble* b,  wxDouble* c, wxDouble* d, wxDouble* tx, wxDouble* ty) const
1229 {
1230     *a = m_matrix._11;
1231     *b = m_matrix._12;
1232     *c = m_matrix._21;
1233     *d = m_matrix._22;
1234     *tx = m_matrix._31;
1235     *ty = m_matrix._32;
1236 }
1237 
Invert()1238 void wxD2DMatrixData::Invert()
1239 {
1240     m_matrix.Invert();
1241 }
1242 
IsEqual(const wxGraphicsMatrixData * t) const1243 bool wxD2DMatrixData::IsEqual(const wxGraphicsMatrixData* t) const
1244 {
1245     return m_matrix == static_cast<const wxD2DMatrixData*>(t)->m_matrix;
1246 }
1247 
IsIdentity() const1248 bool wxD2DMatrixData::IsIdentity() const
1249 {
1250     return m_matrix.IsIdentity();
1251 }
1252 
Translate(wxDouble dx,wxDouble dy)1253 void wxD2DMatrixData::Translate(wxDouble dx, wxDouble dy)
1254 {
1255     m_matrix = D2D1::Matrix3x2F::Translation(dx, dy) * m_matrix;
1256 }
1257 
Scale(wxDouble xScale,wxDouble yScale)1258 void wxD2DMatrixData::Scale(wxDouble xScale, wxDouble yScale)
1259 {
1260     m_matrix = D2D1::Matrix3x2F::Scale(xScale, yScale) * m_matrix;
1261 }
1262 
Rotate(wxDouble angle)1263 void wxD2DMatrixData::Rotate(wxDouble angle)
1264 {
1265     m_matrix = D2D1::Matrix3x2F::Rotation(wxRadToDeg(angle)) * m_matrix;
1266 }
1267 
TransformPoint(wxDouble * x,wxDouble * y) const1268 void wxD2DMatrixData::TransformPoint(wxDouble* x, wxDouble* y) const
1269 {
1270     D2D1_POINT_2F result = m_matrix.TransformPoint(D2D1::Point2F(*x, *y));
1271     *x = result.x;
1272     *y = result.y;
1273 }
1274 
TransformDistance(wxDouble * dx,wxDouble * dy) const1275 void wxD2DMatrixData::TransformDistance(wxDouble* dx, wxDouble* dy) const
1276 {
1277     D2D1::Matrix3x2F noTranslationMatrix = m_matrix;
1278     noTranslationMatrix._31 = 0;
1279     noTranslationMatrix._32 = 0;
1280     D2D1_POINT_2F result = noTranslationMatrix.TransformPoint(D2D1::Point2F(*dx, *dy));
1281     *dx = result.x;
1282     *dy = result.y;
1283 }
1284 
GetNativeMatrix() const1285 void* wxD2DMatrixData::GetNativeMatrix() const
1286 {
1287     return const_cast<void*>(static_cast<const void*>(&m_matrix));
1288 }
1289 
GetMatrix3x2F() const1290 D2D1::Matrix3x2F wxD2DMatrixData::GetMatrix3x2F() const
1291 {
1292     return m_matrix;
1293 }
1294 
wxGetD2DMatrixData(const wxGraphicsMatrix & matrix)1295 const wxD2DMatrixData* wxGetD2DMatrixData(const wxGraphicsMatrix& matrix)
1296 {
1297     return static_cast<const wxD2DMatrixData*>(matrix.GetMatrixData());
1298 }
1299 
1300 //-----------------------------------------------------------------------------
1301 // wxD2DPathData declaration
1302 //-----------------------------------------------------------------------------
1303 
operator ==(const D2D1_POINT_2F & lhs,const D2D1_POINT_2F & rhs)1304 bool operator==(const D2D1_POINT_2F& lhs, const D2D1_POINT_2F& rhs)
1305 {
1306     return lhs.x == rhs.x && lhs.y == rhs.y;
1307 }
1308 
1309 class wxD2DPathData : public wxGraphicsPathData
1310 {
1311 public :
1312 
1313     // ID2D1PathGeometry objects are device-independent resources created
1314     // from a ID2D1Factory. This means we can safely create the resource outside
1315     // (the wxD2DRenderer handles this) and store it here since it never gets
1316     // thrown away by the GPU.
1317     wxD2DPathData(wxGraphicsRenderer* renderer, ID2D1Factory* d2dFactory);
1318 
1319     ~wxD2DPathData();
1320 
SetFillMode(D2D1_FILL_MODE fillMode)1321     void SetFillMode(D2D1_FILL_MODE fillMode)
1322     {
1323         m_fillMode = fillMode;
1324     }
1325 
GetFillMode() const1326     D2D1_FILL_MODE GetFillMode() const
1327     {
1328         return m_fillMode;
1329     }
1330 
1331     ID2D1PathGeometry* GetPathGeometry();
1332 
1333     // This closes the geometry sink, ensuring all the figures are stored inside
1334     // the ID2D1PathGeometry. Calling this method is required before any draw operation
1335     // involving a path.
1336     void Flush();
1337 
1338     wxGraphicsObjectRefData* Clone() const wxOVERRIDE;
1339 
1340     // begins a new subpath at (x,y)
1341     void MoveToPoint(wxDouble x, wxDouble y) wxOVERRIDE;
1342 
1343     // adds a straight line from the current point to (x,y)
1344     void AddLineToPoint(wxDouble x, wxDouble y) wxOVERRIDE;
1345 
1346     // adds a cubic Bezier curve from the current point, using two control points and an end point
1347     void AddCurveToPoint(wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y) wxOVERRIDE;
1348 
1349     // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
1350     void AddArc(wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) wxOVERRIDE;
1351 
1352     // gets the last point of the current path, (0,0) if not yet set
1353     void GetCurrentPoint(wxDouble* x, wxDouble* y) const wxOVERRIDE;
1354 
1355     // adds another path
1356     void AddPath(const wxGraphicsPathData* path) wxOVERRIDE;
1357 
1358     // closes the current sub-path
1359     void CloseSubpath() wxOVERRIDE;
1360 
1361     // returns the native path
1362     void* GetNativePath() const wxOVERRIDE;
1363 
1364     // give the native path returned by GetNativePath() back (there might be some deallocations necessary)
UnGetNativePath(void * WXUNUSED (p)) const1365     void UnGetNativePath(void* WXUNUSED(p)) const wxOVERRIDE {}
1366 
1367     // transforms each point of this path by the matrix
1368     void Transform(const wxGraphicsMatrixData* matrix) wxOVERRIDE;
1369 
1370     // gets the bounding box enclosing all points (possibly including control points)
1371     void GetBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble *h) const wxOVERRIDE;
1372 
1373     bool Contains(wxDouble x, wxDouble y, wxPolygonFillMode fillStyle = wxODDEVEN_RULE) const wxOVERRIDE;
1374 
1375     // appends an ellipsis as a new closed subpath fitting the passed rectangle
1376     void AddCircle(wxDouble x, wxDouble y, wxDouble r) wxOVERRIDE;
1377 
1378     // appends an ellipse
1379     void AddEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
1380 
1381 private:
1382     void EnsureGeometryOpen();
1383 
1384     void EnsureSinkOpen();
1385 
1386     void EnsureFigureOpen(const D2D1_POINT_2F& pos);
1387 
1388     void EndFigure(D2D1_FIGURE_END figureEnd);
1389 
1390     ID2D1Geometry* GetFullGeometry(D2D1_FILL_MODE fillMode) const;
1391 
1392     bool IsEmpty() const;
1393     bool IsStateSafeForFlush() const;
1394 
1395     struct GeometryStateData
1396     {
1397         bool m_isCurrentPointSet;
1398         D2D1_POINT_2F m_currentPoint;
1399         bool m_isFigureOpen;
1400         D2D1_POINT_2F m_figureStart;
1401         bool m_isFigureLogStartSet;
1402         D2D1_POINT_2F m_figureLogStart;
1403     };
1404     void SaveGeometryState(GeometryStateData& data) const;
1405     void RestoreGeometryState(const GeometryStateData& data);
1406 
1407 private :
1408     wxCOMPtr<ID2D1PathGeometry> m_pathGeometry;
1409 
1410     wxCOMPtr<ID2D1GeometrySink> m_geometrySink;
1411 
1412     wxCOMPtr<ID2D1Factory> m_direct2dfactory;
1413 
1414     mutable wxCOMPtr<ID2D1GeometryGroup> m_combinedGeometry;
1415     wxVector<ID2D1Geometry*> m_pTransformedGeometries;
1416 
1417     bool m_currentPointSet;
1418     D2D1_POINT_2F m_currentPoint;
1419 
1420     bool m_figureOpened;
1421     D2D1_POINT_2F m_figureStart;
1422     bool m_figureLogStartSet;
1423     D2D1_POINT_2F m_figureLogStart;
1424 
1425     bool m_geometryWritable;
1426 
1427     D2D1_FILL_MODE m_fillMode;
1428 };
1429 
1430 //-----------------------------------------------------------------------------
1431 // wxD2DPathData implementation
1432 //-----------------------------------------------------------------------------
1433 
wxD2DPathData(wxGraphicsRenderer * renderer,ID2D1Factory * d2dFactory)1434 wxD2DPathData::wxD2DPathData(wxGraphicsRenderer* renderer, ID2D1Factory* d2dFactory) :
1435     wxGraphicsPathData(renderer),
1436     m_direct2dfactory(d2dFactory),
1437     m_currentPointSet(false),
1438     m_currentPoint(D2D1::Point2F(0.0f, 0.0f)),
1439     m_figureOpened(false),
1440     m_figureStart(D2D1::Point2F(0.0f, 0.0f)),
1441     m_figureLogStartSet(false),
1442     m_figureLogStart(D2D1::Point2F(0.0f, 0.0f)),
1443     m_geometryWritable(true),
1444     m_fillMode(D2D1_FILL_MODE_ALTERNATE)
1445 {
1446     m_direct2dfactory->CreatePathGeometry(&m_pathGeometry);
1447     // To properly initialize path geometry there is also
1448     // necessary to open at least once its geometry sink.
1449     m_pathGeometry->Open(&m_geometrySink);
1450 }
1451 
~wxD2DPathData()1452 wxD2DPathData::~wxD2DPathData()
1453 {
1454     Flush();
1455     for( size_t i = 0; i < m_pTransformedGeometries.size(); i++ )
1456     {
1457         m_pTransformedGeometries[i]->Release();
1458     }
1459 }
1460 
GetPathGeometry()1461 ID2D1PathGeometry* wxD2DPathData::GetPathGeometry()
1462 {
1463     return m_pathGeometry;
1464 }
1465 
Clone() const1466 wxD2DPathData::wxGraphicsObjectRefData* wxD2DPathData::Clone() const
1467 {
1468     wxD2DPathData* newPathData = new wxD2DPathData(GetRenderer(), m_direct2dfactory);
1469 
1470     newPathData->EnsureGeometryOpen();
1471 
1472     // Only geometry with closed sink can be
1473     // transferred to another geometry object with
1474     // ID2D1PathGeometry::Stream() so we have to check
1475     // if actual transfer succeeded.
1476 
1477     // Transfer geometry to the new geometry sink.
1478     HRESULT hr = m_pathGeometry->Stream(newPathData->m_geometrySink);
1479     wxASSERT_MSG( SUCCEEDED(hr), wxS("Current geometry is in invalid state") );
1480     if ( FAILED(hr) )
1481     {
1482         delete newPathData;
1483         return NULL;
1484     }
1485 
1486     // Copy the collection of transformed geometries.
1487     ID2D1TransformedGeometry* pTransformedGeometry;
1488     for ( size_t i = 0; i < m_pTransformedGeometries.size(); i++ )
1489     {
1490         pTransformedGeometry = NULL;
1491         hr = m_direct2dfactory->CreateTransformedGeometry(
1492                     m_pTransformedGeometries[i],
1493                     D2D1::Matrix3x2F::Identity(), &pTransformedGeometry);
1494         wxASSERT_MSG( SUCCEEDED(hr), wxFAILED_HRESULT_MSG(hr) );
1495         newPathData->m_pTransformedGeometries.push_back(pTransformedGeometry);
1496     }
1497 
1498     // Copy positional data.
1499     GeometryStateData curState;
1500     SaveGeometryState(curState);
1501     newPathData->RestoreGeometryState(curState);
1502 
1503     return newPathData;
1504 }
1505 
Flush()1506 void wxD2DPathData::Flush()
1507 {
1508     if (m_geometrySink != NULL)
1509     {
1510         if ( m_figureOpened )
1511         {
1512             m_geometrySink->EndFigure(D2D1_FIGURE_END_OPEN);
1513             m_figureOpened = false;
1514         }
1515 
1516         if( m_geometryWritable )
1517         {
1518             HRESULT hr = m_geometrySink->Close();
1519             wxCHECK_HRESULT_RET(hr);
1520             m_geometryWritable = false;
1521         }
1522     }
1523 }
1524 
EnsureGeometryOpen()1525 void wxD2DPathData::EnsureGeometryOpen()
1526 {
1527     if (!m_geometryWritable)
1528     {
1529         wxCOMPtr<ID2D1PathGeometry> newPathGeometry;
1530         HRESULT hr;
1531         hr = m_direct2dfactory->CreatePathGeometry(&newPathGeometry);
1532         wxCHECK_HRESULT_RET(hr);
1533 
1534         m_geometrySink.reset();
1535         hr = newPathGeometry->Open(&m_geometrySink);
1536         wxCHECK_HRESULT_RET(hr);
1537 
1538         if (m_pathGeometry != NULL)
1539         {
1540             hr = m_pathGeometry->Stream(m_geometrySink);
1541             wxCHECK_HRESULT_RET(hr);
1542         }
1543 
1544         m_pathGeometry = newPathGeometry;
1545         m_geometryWritable = true;
1546     }
1547 }
1548 
EnsureSinkOpen()1549 void wxD2DPathData::EnsureSinkOpen()
1550 {
1551     EnsureGeometryOpen();
1552 
1553     if (m_geometrySink == NULL)
1554     {
1555         HRESULT hr = m_pathGeometry->Open(&m_geometrySink);
1556         wxCHECK_HRESULT_RET(hr);
1557     }
1558 }
1559 
EnsureFigureOpen(const D2D1_POINT_2F & pos)1560 void wxD2DPathData::EnsureFigureOpen(const D2D1_POINT_2F& pos)
1561 {
1562     EnsureSinkOpen();
1563 
1564     if (!m_figureOpened)
1565     {
1566         m_figureStart = pos;
1567         m_geometrySink->BeginFigure(m_figureStart, D2D1_FIGURE_BEGIN_FILLED);
1568         m_figureOpened = true;
1569         m_currentPoint = m_figureStart;
1570     }
1571 }
1572 
EndFigure(D2D1_FIGURE_END figureEnd)1573 void wxD2DPathData::EndFigure(D2D1_FIGURE_END figureEnd)
1574 {
1575     if (m_figureOpened)
1576     {
1577         // Ensure that sub-path being closed contains at least one point.
1578         if( figureEnd == D2D1_FIGURE_END_CLOSED )
1579             m_geometrySink->AddLine(m_currentPoint);
1580 
1581         if( figureEnd == D2D1_FIGURE_END_OPEN ||
1582             !m_figureLogStartSet ||
1583             m_figureLogStart == m_figureStart )
1584         {
1585             // If figure will remain open or if its logical startpoint
1586             // is not used or if it is the same as the actual
1587             // startpoint then we can end the figure in a standard way.
1588             m_geometrySink->EndFigure(figureEnd);
1589         }
1590         else
1591         {
1592             // If we want to end and close the figure for which
1593             // logical startpoint is not the same as actual startpoint
1594             // we have to fill the gap between the actual and logical
1595             // endpoints on our own.
1596             m_geometrySink->AddLine(m_figureLogStart);
1597             m_geometrySink->EndFigure(D2D1_FIGURE_END_OPEN);
1598             m_figureStart = m_figureLogStart;
1599         }
1600         m_figureOpened = false;
1601         m_figureLogStartSet = false;
1602 
1603         // If the figure is closed then current point
1604         // should be moved to the beginning of the figure.
1605         if( figureEnd == D2D1_FIGURE_END_CLOSED )
1606             m_currentPoint = m_figureStart;
1607     }
1608 }
1609 
GetFullGeometry(D2D1_FILL_MODE fillMode) const1610 ID2D1Geometry* wxD2DPathData::GetFullGeometry(D2D1_FILL_MODE fillMode) const
1611 {
1612     // Our final path geometry is represented by geometry group
1613     // which contains all transformed geometries plus current geometry.
1614 
1615     // We have to store pointers to all transformed geometries
1616     // as well as pointer to the current geometry in the auxiliary array.
1617     const size_t numGeometries = m_pTransformedGeometries.size();
1618     ID2D1Geometry** pGeometries = new ID2D1Geometry*[numGeometries+1];
1619     for( size_t i = 0; i < numGeometries; i++ )
1620         pGeometries[i] = m_pTransformedGeometries[i];
1621 
1622     pGeometries[numGeometries] = m_pathGeometry;
1623 
1624     // And use this array as a source to create geometry group.
1625     m_combinedGeometry.reset();
1626     HRESULT hr = m_direct2dfactory->CreateGeometryGroup(fillMode,
1627                                   pGeometries, numGeometries+1, &m_combinedGeometry);
1628     wxFAILED_HRESULT_MSG(hr);
1629     delete []pGeometries;
1630 
1631     return m_combinedGeometry;
1632 }
1633 
IsEmpty() const1634 bool wxD2DPathData::IsEmpty() const
1635 {
1636     return !m_currentPointSet && !m_figureOpened &&
1637             m_pTransformedGeometries.size() == 0;
1638 }
1639 
IsStateSafeForFlush() const1640 bool wxD2DPathData::IsStateSafeForFlush() const
1641 {
1642     // Only geometry with not yet started figure
1643     // or with started but empty figure can be fully
1644     // restored to its initial state after invoking Flush().
1645     if( !m_figureOpened )
1646         return true;
1647 
1648     D2D1_POINT_2F actFigureStart = m_figureLogStartSet ?
1649                         m_figureLogStart : m_figureStart;
1650     return m_currentPoint == actFigureStart;
1651 }
1652 
SaveGeometryState(GeometryStateData & data) const1653 void wxD2DPathData::SaveGeometryState(GeometryStateData& data) const
1654 {
1655     data.m_isFigureOpen = m_figureOpened;
1656     data.m_isFigureLogStartSet = m_figureLogStartSet;
1657     data.m_isCurrentPointSet = m_currentPointSet;
1658     data.m_currentPoint = m_currentPoint;
1659     data.m_figureStart = m_figureStart;
1660     data.m_figureLogStart = m_figureLogStart;
1661 }
1662 
RestoreGeometryState(const GeometryStateData & data)1663 void wxD2DPathData::RestoreGeometryState(const GeometryStateData& data)
1664 {
1665     if( data.m_isFigureOpen )
1666     {
1667         // If the figure has to be re-started at the startpoint
1668         // which is not the current point then we have to start it
1669         // physically at the current point but with storing also its
1670         // logical startpoint to use it later on to close the figure,
1671         // if necessary.
1672         // Ending and closing the figure using this proxy startpoint
1673         // is only a simulation of regular closure and figure can behave
1674         // in a slightly different way than figure closed with physical
1675         // startpoint so this action should be avoided if only possible.
1676         D2D1_POINT_2F actFigureStart = data.m_isFigureLogStartSet ?
1677                          data.m_figureLogStart : data.m_figureStart;
1678         if ( !(data.m_currentPoint == actFigureStart) )
1679         {
1680             m_figureLogStart = actFigureStart;
1681             m_figureLogStartSet = true;
1682             EnsureFigureOpen(data.m_currentPoint);
1683         }
1684         else
1685         {
1686             EnsureFigureOpen(actFigureStart);
1687         }
1688     }
1689     else
1690     {
1691         m_figureOpened = false;
1692     }
1693 
1694     m_currentPointSet = data.m_isCurrentPointSet;
1695     m_currentPoint = data.m_isCurrentPointSet ?
1696                 data.m_currentPoint : D2D1::Point2F(0.0F, 0.0F);
1697 }
1698 
MoveToPoint(wxDouble x,wxDouble y)1699 void wxD2DPathData::MoveToPoint(wxDouble x, wxDouble y)
1700 {
1701     // Close current sub-path (leaving the figure as is).
1702     EndFigure(D2D1_FIGURE_END_OPEN);
1703     // Store new current point
1704     m_currentPoint = D2D1::Point2F(x, y);
1705     m_currentPointSet = true;
1706 }
1707 
1708 // adds a straight line from the current point to (x,y)
AddLineToPoint(wxDouble x,wxDouble y)1709 void wxD2DPathData::AddLineToPoint(wxDouble x, wxDouble y)
1710 {
1711     // If current point is not yet set then
1712     // this function should behave as MoveToPoint.
1713     if( !m_currentPointSet )
1714     {
1715         MoveToPoint(x, y);
1716         return;
1717     }
1718 
1719     EnsureFigureOpen(m_currentPoint);
1720     m_geometrySink->AddLine(D2D1::Point2F(x, y));
1721 
1722     m_currentPoint = D2D1::Point2F(x, y);
1723 }
1724 
1725 // adds a cubic Bezier curve from the current point, using two control points and an end point
AddCurveToPoint(wxDouble cx1,wxDouble cy1,wxDouble cx2,wxDouble cy2,wxDouble x,wxDouble y)1726 void wxD2DPathData::AddCurveToPoint(wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y)
1727 {
1728     // If no current point is set then this function should behave
1729     // as if preceded by a call to MoveToPoint(cx1, cy1).
1730     if( !m_currentPointSet )
1731         MoveToPoint(cx1, cy1);
1732 
1733     EnsureFigureOpen(m_currentPoint);
1734 
1735     D2D1_BEZIER_SEGMENT bezierSegment = {
1736         { (FLOAT)cx1, (FLOAT)cy1 },
1737         { (FLOAT)cx2, (FLOAT)cy2 },
1738         { (FLOAT)x, (FLOAT)y } };
1739     m_geometrySink->AddBezier(bezierSegment);
1740 
1741     m_currentPoint = D2D1::Point2F(x, y);
1742 }
1743 
1744 // adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle
AddArc(wxDouble x,wxDouble y,wxDouble r,wxDouble startAngle,wxDouble endAngle,bool clockwise)1745 void wxD2DPathData::AddArc(wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise)
1746 {
1747     double angle;
1748 
1749     // For the sake of compatibility normalize angles the same way
1750     // as it is done in Cairo.
1751     if ( clockwise )
1752     {
1753         // If endAngle < startAngle it needs to be progressively
1754         // increased by 2*M_PI until endAngle > startAngle.
1755         if ( endAngle < startAngle )
1756         {
1757             while ( endAngle <= startAngle )
1758             {
1759                 endAngle += 2.0*M_PI;
1760             }
1761         }
1762 
1763         angle = endAngle - startAngle;
1764     }
1765     else
1766     {
1767         // If endAngle > startAngle it needs to be progressively
1768         // decreased by 2*M_PI until endAngle < startAngle.
1769         if ( endAngle > startAngle )
1770         {
1771             while ( endAngle >= startAngle )
1772             {
1773                 endAngle -= 2.0*M_PI;
1774             }
1775         }
1776 
1777         angle = startAngle - endAngle;
1778     }
1779 
1780     wxPoint2DDouble start = wxPoint2DDouble(cos(startAngle) * r, sin(startAngle) * r);
1781     wxPoint2DDouble end = wxPoint2DDouble(cos(endAngle) * r, sin(endAngle) * r);
1782 
1783     // To ensure compatibility with Cairo an initial
1784     // line segment to the beginning of the arc needs
1785     // to be added to the path.
1786     if ( m_figureOpened )
1787     {
1788         AddLineToPoint(start.m_x + x, start.m_y + y);
1789     }
1790     else if ( m_currentPointSet )
1791     {
1792         EnsureFigureOpen(m_currentPoint);
1793         AddLineToPoint(start.m_x + x, start.m_y + y);
1794     }
1795     else
1796     {
1797         MoveToPoint(start.m_x + x, start.m_y + y);
1798         EnsureFigureOpen(m_currentPoint);
1799     }
1800 
1801     D2D1_SWEEP_DIRECTION sweepDirection = clockwise ?
1802        D2D1_SWEEP_DIRECTION_CLOCKWISE : D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE;
1803     D2D1_SIZE_F size = D2D1::SizeF((FLOAT)r, (FLOAT)r);
1804 
1805     if ( angle >= 2.0*M_PI )
1806     {
1807         // In addition to arc we need to draw full circle(s).
1808         // Remarks:
1809         // 1. Parity of the number of the circles has to be
1810         // preserved because this matters when path would be
1811         // filled with wxODDEVEN_RULE flag set (using
1812         // D2D1_FILL_MODE_ALTERNATE mode) when number of the
1813         // edges is counted.
1814         // 2. ID2D1GeometrySink::AddArc() doesn't work
1815         // with 360-degree arcs so we need to construct
1816         // the circle from two halves.
1817         D2D1_ARC_SEGMENT circleSegment1 =
1818         {
1819             D2D1::Point2((FLOAT)(x - start.m_x), (FLOAT)(y - start.m_y)),  // end point
1820             size,                     // size
1821             0.0f,                     // rotation
1822             sweepDirection,           // sweep direction
1823             D2D1_ARC_SIZE_SMALL       // arc size
1824         };
1825         D2D1_ARC_SEGMENT circleSegment2 =
1826         {
1827             D2D1::Point2((FLOAT)(x + start.m_x), (FLOAT)(y + start.m_y)),  // end point
1828             size,                     // size
1829             0.0f,                     // rotation
1830             sweepDirection,           // sweep direction
1831             D2D1_ARC_SIZE_SMALL       // arc size
1832         };
1833 
1834         int numCircles = (int)(angle / (2.0*M_PI));
1835         numCircles = (numCircles - 1) % 2 + 1;
1836         for( int i = 0; i < numCircles; i++ )
1837         {
1838             m_geometrySink->AddArc(circleSegment1);
1839             m_geometrySink->AddArc(circleSegment2);
1840         }
1841 
1842         // Reduce the angle to [0..2*M_PI) range.
1843         angle = fmod(angle, 2.0*M_PI);
1844     }
1845 
1846     D2D1_ARC_SIZE arcSize = angle > M_PI ?
1847        D2D1_ARC_SIZE_LARGE : D2D1_ARC_SIZE_SMALL;
1848     D2D1_POINT_2F endPoint =
1849        D2D1::Point2((FLOAT)(end.m_x + x), (FLOAT)(end.m_y + y));
1850 
1851     D2D1_ARC_SEGMENT arcSegment =
1852     {
1853         endPoint,                     // end point
1854         size,                         // size
1855         0.0f,                         // rotation
1856         sweepDirection,               // sweep direction
1857         arcSize                       // arc size
1858     };
1859 
1860     m_geometrySink->AddArc(arcSegment);
1861 
1862     m_currentPoint = endPoint;
1863 }
1864 
1865 // appends an ellipsis as a new closed subpath fitting the passed rectangle
AddCircle(wxDouble x,wxDouble y,wxDouble r)1866 void wxD2DPathData::AddCircle(wxDouble x, wxDouble y, wxDouble r)
1867 {
1868     AddEllipse(x - r, y - r, r * 2, r * 2);
1869 }
1870 
1871 // appends an ellipse
AddEllipse(wxDouble x,wxDouble y,wxDouble w,wxDouble h)1872 void wxD2DPathData::AddEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
1873 {
1874     if ( w <= 0.0 || h <= 0.0 )
1875       return;
1876 
1877     // Calculate radii
1878     const wxDouble rx = w / 2.0;
1879     const wxDouble ry = h / 2.0;
1880 
1881     MoveToPoint(x + w, y + ry);
1882     // Open new subpath
1883     EnsureFigureOpen(m_currentPoint);
1884 
1885     D2D1_ARC_SEGMENT arcSegmentLower =
1886     {
1887         D2D1::Point2((FLOAT)(x), (FLOAT)(y + ry)),     // end point
1888         D2D1::SizeF((FLOAT)(rx), (FLOAT)(ry)),         // size
1889         0.0f,
1890         D2D1_SWEEP_DIRECTION_CLOCKWISE,
1891         D2D1_ARC_SIZE_SMALL
1892     };
1893     m_geometrySink->AddArc(arcSegmentLower);
1894 
1895     D2D1_ARC_SEGMENT arcSegmentUpper =
1896     {
1897         D2D1::Point2((FLOAT)(x + w), (FLOAT)(y + ry)), // end point
1898         D2D1::SizeF((FLOAT)(rx), (FLOAT)(ry)),         // size
1899         0.0f,
1900         D2D1_SWEEP_DIRECTION_CLOCKWISE,
1901         D2D1_ARC_SIZE_SMALL
1902     };
1903     m_geometrySink->AddArc(arcSegmentUpper);
1904 
1905     CloseSubpath();
1906 }
1907 
1908 // gets the last point of the current path, (0,0) if not yet set
GetCurrentPoint(wxDouble * x,wxDouble * y) const1909 void wxD2DPathData::GetCurrentPoint(wxDouble* x, wxDouble* y) const
1910 {
1911     if (x != NULL) *x = m_currentPoint.x;
1912     if (y != NULL) *y = m_currentPoint.y;
1913 }
1914 
1915 // adds another path
AddPath(const wxGraphicsPathData * path)1916 void wxD2DPathData::AddPath(const wxGraphicsPathData* path)
1917 {
1918     wxD2DPathData* pathSrc =
1919          const_cast<wxD2DPathData*>(static_cast<const wxD2DPathData*>(path));
1920 
1921     // Nothing to do if geometry of appended path is not initialized.
1922     if ( pathSrc->m_pathGeometry == NULL || pathSrc->m_geometrySink == NULL )
1923         return;
1924 
1925     // Because only closed geometry (with closed sink)
1926     // can be transferred to another geometry object with
1927     // ID2D1PathGeometry::Stream() so we have to close it
1928     // before any operation and to re-open afterwards.
1929     // Unfortunately, to close the sink it is also necessary
1930     // to end the figure it contains, if it was open.
1931     // After re-opening the geometry we should also re-start
1932     // the figure (if it was open) and restore its state but
1933     // it seems there is no straightforward way to do so
1934     // if the figure is not empty.
1935     //
1936     // So, only if appended path has a sub-path closed or
1937     // has an empty sub-path open there is possible to restore
1938     // its state after appending it to the current path and only
1939     // in this case the operation doesn't introduce side effects.
1940 
1941     // Nothing to do if appended path is empty.
1942     if ( pathSrc->IsEmpty() )
1943         return;
1944 
1945     // Save positional and auxiliary data
1946     // of the appended path and its geometry.
1947     GeometryStateData curStateSrc;
1948     pathSrc->SaveGeometryState(curStateSrc);
1949 
1950     // Close appended geometry.
1951     pathSrc->Flush();
1952 
1953     // Close current geometry (leaving the figure as is).
1954     Flush();
1955 
1956     HRESULT hr;
1957     ID2D1TransformedGeometry* pTransformedGeometry = NULL;
1958     // Add current geometry to the collection transformed geometries.
1959     hr = m_direct2dfactory->CreateTransformedGeometry(m_pathGeometry,
1960                         D2D1::Matrix3x2F::Identity(), &pTransformedGeometry);
1961     wxCHECK_HRESULT_RET(hr);
1962     m_pTransformedGeometries.push_back(pTransformedGeometry);
1963 
1964     // Add to the collection transformed geometries from the appended path.
1965     for ( size_t i = 0; i < pathSrc->m_pTransformedGeometries.size(); i++ )
1966     {
1967         pTransformedGeometry = NULL;
1968         hr = m_direct2dfactory->CreateTransformedGeometry(
1969                     pathSrc->m_pTransformedGeometries[i],
1970                     D2D1::Matrix3x2F::Identity(), &pTransformedGeometry);
1971         wxCHECK_HRESULT_RET(hr);
1972         m_pTransformedGeometries.push_back(pTransformedGeometry);
1973     }
1974 
1975     // Clear and reopen current geometry.
1976     m_pathGeometry.reset();
1977     EnsureGeometryOpen();
1978 
1979     // Transfer appended geometry to the current geometry sink.
1980     hr = pathSrc->m_pathGeometry->Stream(m_geometrySink);
1981     wxCHECK_HRESULT_RET(hr);
1982 
1983     // Apply to the current path positional data from the appended path.
1984     // This operation fully sets geometry to the required state
1985     // only if it represents geometry without started figure
1986     // or with started but empty figure.
1987     RestoreGeometryState(curStateSrc);
1988 
1989     // Reopen appended geometry.
1990     pathSrc->EnsureGeometryOpen();
1991     // Restore its positional data.
1992     // This operation fully restores geometry to the required state
1993     // only if it represents geometry without started figure
1994     // or with started but empty figure.
1995     pathSrc->RestoreGeometryState(curStateSrc);
1996 }
1997 
1998 // closes the current sub-path
CloseSubpath()1999 void wxD2DPathData::CloseSubpath()
2000 {
2001     // If we have a sub-path open by call to MoveToPoint(),
2002     // which doesn't open a new figure by itself,
2003     // we have to open a new figure now to get a required 1-point path.
2004     if ( !m_figureOpened && m_currentPointSet )
2005     {
2006         EnsureFigureOpen(m_currentPoint);
2007     }
2008     // Close sub-path and close the figure.
2009     if ( m_figureOpened )
2010     {
2011         EndFigure(D2D1_FIGURE_END_CLOSED);
2012         MoveToPoint(m_figureStart.x, m_figureStart.y);
2013     }
2014 }
2015 
GetNativePath() const2016 void* wxD2DPathData::GetNativePath() const
2017 {
2018     return GetFullGeometry(GetFillMode());
2019 }
2020 
Transform(const wxGraphicsMatrixData * matrix)2021 void wxD2DPathData::Transform(const wxGraphicsMatrixData* matrix)
2022 {
2023     // Unfortunately, it looks there is no straightforward way to apply
2024     // transformation to the current underlying path geometry
2025     // (ID2D1PathGeometry object) "in-place" (ie. transform it and use
2026     // for further graphics operations, including next transformations too).
2027     // Some simple methods offered by D2D are not useful for these purposes:
2028     // 1. ID2D1Factory::CreateTransformedGeometry() converts ID2D1PathGeometry
2029     // object to ID2D1TransformedGeometry object but ID2D1TransformedGeometry
2030     // inherits from ID2D1Geometry (not from ID2D1PathGeometry)
2031     // and hence cannot be used for further path operations.
2032     // 2. ID2D1Geometry::CombineWithGeometry() which could be used to get final
2033     // path geometry by combining empty geometry with transformed geometry
2034     // doesn't offer any combine mode which would produce a "sum" of geometries
2035     // (D2D1_COMBINE_MODE_UNION produces kind of outline). Moreover the result
2036     // is stored in ID2D1SimplifiedGeometrySink not in ID2DGeometrySink.
2037 
2038     // So, it seems that ability to transform the wxGraphicsPath
2039     // (several times) and still use it after this operation(s)
2040     // can be achieved (only?) by using a geometry group object
2041     // (ID2D1GeometryGroup) this way:
2042     // 1. After applying transformation to the current path geometry with
2043     // ID2D1Factory::CreateTransformedGeometry() the result is stored
2044     // in the collection of transformed geometries (an auxiliary array)
2045     // and after that a new (empty) geometry is open (in the same state
2046     // as just closed one) and this geometry is used as a current one
2047     // for further graphics operations.
2048     // 2. Since above steps are done at every transformation so our effective
2049     // geometry will be a superposition of all previously transformed
2050     // geometries stored in the collection (array) and the current
2051     // operational geometry.
2052     // 3. If there is necessary to use this combined effective geometry
2053     // in any operation then ID2D1GeometryGroup created with
2054     // ID2D1Factory::CreateGeometryGroup() from the collection
2055     // of stored geometries will act as a proxy geometry.
2056 
2057     const D2D1::Matrix3x2F* m = static_cast<D2D1::Matrix3x2F*>(matrix->GetNativeMatrix());
2058 
2059     // Save current positional data.
2060     GeometryStateData curState;
2061     SaveGeometryState(curState);
2062     // We need to close the geometry what requires also to end a figure
2063     // (if started). This ended figure should be re-started in its initial
2064     // state when all path processing is done but due to the Direct2D
2065     // constraints this can be fully done only if open figure was empty.
2066     // So, Transform() can be safely called if path doesn't contain the open
2067     // sub-path or if open sub-path is empty.
2068 
2069     // Close current geometry.
2070     Flush();
2071 
2072     HRESULT hr;
2073     ID2D1TransformedGeometry* pTransformedGeometry;
2074     // Apply given transformation to all previously stored geometries too.
2075     for( size_t i = 0; i < m_pTransformedGeometries.size(); i++ )
2076     {
2077         pTransformedGeometry = NULL;
2078         hr = m_direct2dfactory->CreateTransformedGeometry(m_pTransformedGeometries[i], m, &pTransformedGeometry);
2079         wxCHECK_HRESULT_RET(hr);
2080 
2081         m_pTransformedGeometries[i]->Release();
2082         m_pTransformedGeometries[i] = pTransformedGeometry;
2083     }
2084 
2085     // Transform current geometry and add the result
2086     // to the collection of transformed geometries.
2087     pTransformedGeometry = NULL;
2088     hr = m_direct2dfactory->CreateTransformedGeometry(m_pathGeometry, m, &pTransformedGeometry);
2089     wxCHECK_HRESULT_RET(hr);
2090     m_pTransformedGeometries.push_back(pTransformedGeometry);
2091 
2092     // Clear and reopen current geometry.
2093     m_pathGeometry.reset();
2094     EnsureGeometryOpen();
2095     // Restore the figure with transformed positional data.
2096     // This operation fully restores geometry to the required state
2097     // only if IsStateSafeForFlush() returns true.
2098     curState.m_currentPoint = m->TransformPoint(curState.m_currentPoint);
2099     curState.m_figureLogStart = m->TransformPoint(curState.m_figureLogStart);
2100     curState.m_figureStart = m->TransformPoint(curState.m_figureStart);
2101     RestoreGeometryState(curState);
2102 }
2103 
GetBox(wxDouble * x,wxDouble * y,wxDouble * w,wxDouble * h) const2104 void wxD2DPathData::GetBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble *h) const
2105 {
2106     D2D1_RECT_F bounds;
2107     ID2D1Geometry *curGeometry = GetFullGeometry(GetFillMode());
2108     HRESULT hr = curGeometry->GetBounds(D2D1::Matrix3x2F::Identity(), &bounds);
2109     wxCHECK_HRESULT_RET(hr);
2110     // Check if bounds are empty
2111     if ( bounds.left > bounds.right )
2112     {
2113         bounds.left = bounds.top = bounds.right = bounds.bottom = 0.0F;
2114     }
2115     if (x) *x = bounds.left;
2116     if (y) *y = bounds.top;
2117     if (w) *w = bounds.right - bounds.left;
2118     if (h) *h = bounds.bottom - bounds.top;
2119 }
2120 
Contains(wxDouble x,wxDouble y,wxPolygonFillMode fillStyle) const2121 bool wxD2DPathData::Contains(wxDouble x, wxDouble y, wxPolygonFillMode fillStyle) const
2122 {
2123     BOOL result;
2124     D2D1_FILL_MODE fillMode = (fillStyle == wxODDEVEN_RULE) ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING;
2125     ID2D1Geometry *curGeometry = GetFullGeometry(fillMode);
2126     curGeometry->FillContainsPoint(D2D1::Point2F(x, y), D2D1::Matrix3x2F::Identity(), &result);
2127     return result != FALSE;
2128 }
2129 
wxGetD2DPathData(const wxGraphicsPath & path)2130 wxD2DPathData* wxGetD2DPathData(const wxGraphicsPath& path)
2131 {
2132     return static_cast<wxD2DPathData*>(path.GetGraphicsData());
2133 }
2134 
2135 // This utility class is used to read a color value with the format
2136 // PBGRA from a byte stream and to write a color back to the stream.
2137 // It's used in conjunction with the IWICBitmapSource or IWICBitmap
2138 // pixel data to easily read and write color values.
2139 struct wxPBGRAColor
2140 {
wxPBGRAColorwxPBGRAColor2141     wxPBGRAColor(BYTE* stream) :
2142         b(*stream), g(*(stream + 1)), r(*(stream + 2)), a(*(stream + 3))
2143     {}
2144 
wxPBGRAColorwxPBGRAColor2145     wxPBGRAColor(const wxColor& color) :
2146         b(color.Blue()), g(color.Green()), r(color.Red()), a(color.Alpha())
2147     {}
2148 
IsBlackwxPBGRAColor2149     bool IsBlack() const { return r == 0 && g == 0 && b == 0; }
2150 
WritewxPBGRAColor2151     void Write(BYTE* stream) const
2152     {
2153         *(stream + 0) = b;
2154         *(stream + 1) = g;
2155         *(stream + 2) = r;
2156         *(stream + 3) = a;
2157     }
2158 
2159     BYTE b, g, r, a;
2160 };
2161 
2162 namespace
2163 {
wxCreateWICBitmap(const WXHBITMAP sourceBitmap,bool hasAlpha,bool forceAlpha)2164 wxCOMPtr<IWICBitmapSource> wxCreateWICBitmap(const WXHBITMAP sourceBitmap, bool hasAlpha, bool forceAlpha)
2165 {
2166     HRESULT hr;
2167 
2168     wxCOMPtr<IWICBitmap> wicBitmap;
2169     hr = wxWICImagingFactory()->CreateBitmapFromHBITMAP(sourceBitmap, NULL, hasAlpha ? WICBitmapUsePremultipliedAlpha : WICBitmapIgnoreAlpha, &wicBitmap);
2170     wxCHECK2_HRESULT_RET(hr, wxCOMPtr<IWICBitmapSource>(NULL));
2171 
2172     wxCOMPtr<IWICFormatConverter> converter;
2173     hr = wxWICImagingFactory()->CreateFormatConverter(&converter);
2174     wxCHECK2_HRESULT_RET(hr, wxCOMPtr<IWICBitmapSource>(NULL));
2175 
2176     WICPixelFormatGUID pixelFormat = hasAlpha || forceAlpha ? GUID_WICPixelFormat32bppPBGRA : GUID_WICPixelFormat32bppBGR;
2177 
2178     hr = converter->Initialize(
2179         wicBitmap,
2180         pixelFormat,
2181         WICBitmapDitherTypeNone, NULL, 0.f,
2182         WICBitmapPaletteTypeMedianCut);
2183     wxCHECK2_HRESULT_RET(hr, wxCOMPtr<IWICBitmapSource>(NULL));
2184 
2185     return wxCOMPtr<IWICBitmapSource>(converter);
2186 }
2187 
wxCreateWICBitmap(const wxBitmap & sourceBitmap,bool forceAlpha)2188 inline wxCOMPtr<IWICBitmapSource> wxCreateWICBitmap(const wxBitmap& sourceBitmap, bool forceAlpha)
2189 {
2190     return wxCreateWICBitmap(sourceBitmap.GetHBITMAP(), sourceBitmap.HasAlpha(), forceAlpha);
2191 }
2192 
2193 #if wxUSE_IMAGE
CreateWICBitmapFromImage(const wxImage & img,bool forceAlpha,IWICBitmap ** ppBmp)2194 void CreateWICBitmapFromImage(const wxImage& img, bool forceAlpha, IWICBitmap** ppBmp)
2195 {
2196     const int width = img.GetWidth();
2197     const int height = img.GetHeight();
2198     // Create a compatible WIC Bitmap
2199     WICPixelFormatGUID fmt = img.HasAlpha() || img.HasMask() || forceAlpha ? GUID_WICPixelFormat32bppPBGRA : GUID_WICPixelFormat32bppBGR;
2200     HRESULT hr = wxWICImagingFactory()->CreateBitmap(width, height, fmt, WICBitmapCacheOnLoad, ppBmp);
2201     wxCHECK_HRESULT_RET(hr);
2202 
2203     // Copy contents of source image to the WIC bitmap.
2204     WICRect rcLock = { 0, 0, width, height };
2205     wxCOMPtr<IWICBitmapLock> pLock;
2206     hr = (*ppBmp)->Lock(&rcLock, WICBitmapLockWrite, &pLock);
2207     wxCHECK_HRESULT_RET(hr);
2208 
2209     UINT rowStride = 0;
2210     hr = pLock->GetStride(&rowStride);
2211     wxCHECK_HRESULT_RET(hr);
2212 
2213     UINT bufferSize = 0;
2214     BYTE* pBuffer = NULL;
2215     hr = pLock->GetDataPointer(&bufferSize, &pBuffer);
2216     wxCHECK_HRESULT_RET(hr);
2217 
2218     const unsigned char* imgRGB = img.GetData();    // source RGB buffer
2219     const unsigned char* imgAlpha = img.GetAlpha(); // source alpha buffer
2220     BYTE* pBmpBuffer = pBuffer;
2221     for ( int y = 0; y < height; y++ )
2222     {
2223         BYTE* pPixByte = pBmpBuffer;
2224         for ( int x = 0; x < width; x++ )
2225         {
2226             unsigned char r = *imgRGB++;
2227             unsigned char g = *imgRGB++;
2228             unsigned char b = *imgRGB++;
2229             if ( imgAlpha )
2230             {
2231                 unsigned char a = *imgAlpha++;
2232                 // Premultiply RGB values
2233                 *pPixByte++ = (b * a + 127) / 255;
2234                 *pPixByte++ = (g * a + 127) / 255;
2235                 *pPixByte++ = (r * a + 127) / 255;
2236                 *pPixByte++ = a;
2237             }
2238             else
2239             {
2240                 *pPixByte++ = b;
2241                 *pPixByte++ = g;
2242                 *pPixByte++ = r;
2243                 *pPixByte++ = 255;
2244             }
2245         }
2246 
2247         pBmpBuffer += rowStride;
2248     }
2249 
2250     // If there is a mask, set the alpha bytes in the target buffer to
2251     // fully transparent or retain original value
2252     if ( img.HasMask() )
2253     {
2254         unsigned char mr = img.GetMaskRed();
2255         unsigned char mg = img.GetMaskGreen();
2256         unsigned char mb = img.GetMaskBlue();
2257 
2258         imgRGB = img.GetData();
2259         pBmpBuffer = pBuffer;
2260         for ( int y = 0; y < height; y++ )
2261         {
2262             BYTE* pPixByte = pBmpBuffer;
2263             for ( int x = 0; x < width; x++ )
2264             {
2265                 if ( imgRGB[0] == mr && imgRGB[1] == mg && imgRGB[2] == mb )
2266                     pPixByte[0] = pPixByte[1] = pPixByte[2] = pPixByte[3] = 0;
2267 
2268                 imgRGB += 3;
2269                 pPixByte += 4;
2270             }
2271 
2272             pBmpBuffer += rowStride;
2273         }
2274     }
2275 }
2276 
CreateImageFromWICBitmap(IWICBitmap * pBmp,wxImage * pImg)2277 void CreateImageFromWICBitmap(IWICBitmap* pBmp, wxImage* pImg)
2278 {
2279     UINT width, height;
2280     HRESULT hr = pBmp->GetSize(&width, &height);
2281     wxCHECK_HRESULT_RET(hr);
2282 
2283     WICRect rcLock = { 0, 0, (INT)width, (INT)height };
2284     wxCOMPtr<IWICBitmapLock> pLock;
2285     hr = pBmp->Lock(&rcLock, WICBitmapLockRead, &pLock);
2286     wxCHECK_HRESULT_RET(hr);
2287 
2288     UINT rowStride = 0;
2289     hr = pLock->GetStride(&rowStride);
2290     wxCHECK_HRESULT_RET(hr);
2291 
2292     UINT bufferSize = 0;
2293     BYTE* pBmpBuffer = NULL;
2294     hr = pLock->GetDataPointer(&bufferSize, &pBmpBuffer);
2295     wxCHECK_HRESULT_RET(hr);
2296 
2297     WICPixelFormatGUID pixelFormat;
2298     hr = pLock->GetPixelFormat(&pixelFormat);
2299     wxCHECK_HRESULT_RET(hr);
2300     wxASSERT_MSG(pixelFormat == GUID_WICPixelFormat32bppPBGRA || pixelFormat == GUID_WICPixelFormat32bppBGR,
2301                  "Unsupported pixel format");
2302 
2303     // Only premultiplied ARGB bitmaps are supported.
2304     const bool hasAlpha = pixelFormat == GUID_WICPixelFormat32bppPBGRA;
2305 
2306     if ( pImg->IsOk() )
2307     {
2308         if ( pImg->GetWidth() != (int)width || pImg->GetHeight() != (int)height )
2309         {
2310             pImg->Resize(wxSize(width, height), wxPoint(0, 0));
2311         }
2312     }
2313     else
2314     {
2315         pImg->Create(width, height);
2316     }
2317     if ( hasAlpha && !pImg->HasAlpha() )
2318     {
2319         pImg->SetAlpha();
2320     }
2321     pImg->SetMask(false);
2322 
2323     unsigned char* destRGB = pImg->GetData();
2324     unsigned char* destAlpha = pImg->GetAlpha();
2325     for ( UINT y = 0; y < height; y++ )
2326     {
2327         BYTE* pPixByte = pBmpBuffer;
2328         for ( UINT x = 0; x < width; x++ )
2329         {
2330             wxPBGRAColor color = wxPBGRAColor(pPixByte);
2331             unsigned char a = hasAlpha ? color.a : wxIMAGE_ALPHA_OPAQUE;
2332             // Undo premultiplication for ARGB bitmap
2333             *destRGB++ = (a > 0 && a < 255)?(color.r * 255) / a : color.r;
2334             *destRGB++ = (a > 0 && a < 255)?(color.g * 255) / a : color.g;
2335             *destRGB++ = (a > 0 && a < 255)?(color.b * 255) / a : color.b;
2336             if ( destAlpha )
2337                 *destAlpha++ = a;
2338 
2339             pPixByte += 4;
2340         }
2341 
2342         pBmpBuffer += rowStride;
2343     }
2344 }
2345 #endif // wxUSE_IMAGE
2346 };
2347 
2348 // WIC Bitmap Source for creating hatch patterned bitmaps
2349 class wxHatchBitmapSource : public IWICBitmapSource
2350 {
2351 public:
wxHatchBitmapSource(wxBrushStyle brushStyle,const wxColor & color)2352     wxHatchBitmapSource(wxBrushStyle brushStyle, const wxColor& color) :
2353         m_brushStyle(brushStyle), m_color(color), m_refCount(0l)
2354     {
2355     }
2356 
~wxHatchBitmapSource()2357     virtual ~wxHatchBitmapSource() {}
2358 
GetSize(__RPC__out UINT * width,__RPC__out UINT * height)2359     HRESULT STDMETHODCALLTYPE GetSize(__RPC__out UINT *width, __RPC__out UINT *height) wxOVERRIDE
2360     {
2361         if (width != NULL) *width = 8;
2362         if (height != NULL) *height = 8;
2363         return S_OK;
2364     }
2365 
GetPixelFormat(__RPC__out WICPixelFormatGUID * pixelFormat)2366     HRESULT STDMETHODCALLTYPE GetPixelFormat(__RPC__out WICPixelFormatGUID *pixelFormat) wxOVERRIDE
2367     {
2368         if (pixelFormat != NULL) *pixelFormat = GUID_WICPixelFormat32bppPBGRA;
2369         return S_OK;
2370     }
2371 
GetResolution(__RPC__out double * dpiX,__RPC__out double * dpiY)2372     HRESULT STDMETHODCALLTYPE GetResolution(__RPC__out double *dpiX, __RPC__out double *dpiY) wxOVERRIDE
2373     {
2374         if (dpiX != NULL) *dpiX = 96.0;
2375         if (dpiY != NULL) *dpiY = 96.0;
2376         return S_OK;
2377     }
2378 
CopyPalette(__RPC__in_opt IWICPalette * WXUNUSED (palette))2379     HRESULT STDMETHODCALLTYPE CopyPalette(__RPC__in_opt IWICPalette*  WXUNUSED(palette)) wxOVERRIDE
2380     {
2381         return WINCODEC_ERR_PALETTEUNAVAILABLE;
2382     }
2383 
CopyPixels(const WICRect * WXUNUSED (prc),UINT WXUNUSED (stride),UINT WXUNUSED (bufferSize),BYTE * buffer)2384     HRESULT STDMETHODCALLTYPE CopyPixels(
2385         const WICRect* WXUNUSED(prc),
2386         UINT WXUNUSED(stride),
2387         UINT WXUNUSED(bufferSize),
2388         BYTE *buffer) wxOVERRIDE
2389     {
2390         // patterns are encoded in a bit map of size 8 x 8
2391         static const unsigned char BDIAGONAL_PATTERN[8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
2392         static const unsigned char FDIAGONAL_PATTERN[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
2393         static const unsigned char CROSSDIAG_PATTERN[8] = { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 };
2394         static const unsigned char CROSS_PATTERN[8] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFF };
2395         static const unsigned char HORIZONTAL_PATTERN[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF };
2396         static const unsigned char VERTICAL_PATTERN[8] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
2397 
2398         switch (m_brushStyle)
2399         {
2400             case wxBRUSHSTYLE_BDIAGONAL_HATCH:
2401                 CopyPattern(buffer, BDIAGONAL_PATTERN);
2402                 break;
2403             case wxBRUSHSTYLE_CROSSDIAG_HATCH:
2404                 CopyPattern(buffer, CROSSDIAG_PATTERN);
2405                 break;
2406             case wxBRUSHSTYLE_FDIAGONAL_HATCH:
2407                 CopyPattern(buffer, FDIAGONAL_PATTERN);
2408                 break;
2409             case wxBRUSHSTYLE_CROSS_HATCH:
2410                 CopyPattern(buffer, CROSS_PATTERN);
2411                 break;
2412             case wxBRUSHSTYLE_HORIZONTAL_HATCH:
2413                 CopyPattern(buffer, HORIZONTAL_PATTERN);
2414                 break;
2415             case wxBRUSHSTYLE_VERTICAL_HATCH:
2416                 CopyPattern(buffer, VERTICAL_PATTERN);
2417                 break;
2418             default:
2419                 break;
2420         }
2421 
2422         return S_OK;
2423     }
2424 
2425     // Implementations adapted from: "Implementing IUnknown in C++"
2426     // http://msdn.microsoft.com/en-us/library/office/cc839627%28v=office.15%29.aspx
2427 
QueryInterface(REFIID referenceId,void ** object)2428     HRESULT STDMETHODCALLTYPE QueryInterface(REFIID referenceId, void** object) wxOVERRIDE
2429     {
2430         if (!object)
2431         {
2432             return E_INVALIDARG;
2433         }
2434 
2435         *object = NULL;
2436 
2437         if (referenceId == IID_IUnknown || referenceId == wxIID_IWICBitmapSource)
2438         {
2439             *object = (LPVOID)this;
2440             AddRef();
2441             return NOERROR;
2442         }
2443 
2444         return E_NOINTERFACE;
2445     }
2446 
AddRef(void)2447     ULONG STDMETHODCALLTYPE AddRef(void) wxOVERRIDE
2448     {
2449         InterlockedIncrement(&m_refCount);
2450         return m_refCount;
2451     }
2452 
Release(void)2453     ULONG STDMETHODCALLTYPE Release(void) wxOVERRIDE
2454     {
2455         wxCHECK_MSG(m_refCount > 0, 0, "Unbalanced number of calls to Release");
2456 
2457         ULONG refCount = InterlockedDecrement(&m_refCount);
2458         if (m_refCount == 0)
2459         {
2460             delete this;
2461         }
2462         return refCount;
2463     }
2464 
2465 private:
2466 
2467     // Copies an 8x8 bit pattern to a PBGRA byte buffer
CopyPattern(BYTE * buffer,const unsigned char * pattern) const2468     void CopyPattern(BYTE* buffer, const unsigned char* pattern) const
2469     {
2470         static const wxPBGRAColor transparent(wxTransparentColour);
2471 
2472         int k = 0;
2473 
2474         for (int i = 0; i < 8; ++i)
2475         {
2476             for (int j = 7; j >= 0; --j)
2477             {
2478                 bool isColorBit = (pattern[i] & (1 << j)) > 0;
2479                 (isColorBit ? m_color : transparent).Write(buffer + k);
2480                 k += 4;
2481             }
2482         }
2483     }
2484 
2485 private:
2486     // The hatch style produced by this bitmap source
2487     const wxBrushStyle m_brushStyle;
2488 
2489     // The colour of the hatch
2490     const wxPBGRAColor m_color;
2491 
2492     // Internally used to implement IUnknown's reference counting
2493     ULONG m_refCount;
2494 };
2495 
2496 // RAII class hosting a WIC bitmap lock used for writing
2497 // pixel data to a WICBitmap
2498 class wxBitmapPixelWriteLock
2499 {
2500 public:
wxBitmapPixelWriteLock(IWICBitmap * bitmap)2501     wxBitmapPixelWriteLock(IWICBitmap* bitmap)
2502     {
2503         // Retrieve the size of the bitmap
2504         UINT w, h;
2505         bitmap->GetSize(&w, &h);
2506         WICRect lockSize = {0, 0, (INT)w, (INT)h};
2507 
2508         // Obtain a bitmap lock for exclusive write
2509         bitmap->Lock(&lockSize, WICBitmapLockWrite, &m_pixelLock);
2510     }
2511 
GetLock()2512     IWICBitmapLock* GetLock() { return m_pixelLock; }
2513 
2514 private:
2515     wxCOMPtr<IWICBitmapLock> m_pixelLock;
2516 };
2517 
2518 class wxD2DBitmapResourceHolder : public wxD2DResourceHolder<ID2D1Bitmap>
2519 {
2520 public:
wxD2DBitmapResourceHolder(const wxBitmap & sourceBitmap)2521     wxD2DBitmapResourceHolder(const wxBitmap& sourceBitmap)
2522     {
2523         HRESULT hr;
2524         if ( sourceBitmap.GetMask() )
2525         {
2526             int w = sourceBitmap.GetWidth();
2527             int h = sourceBitmap.GetHeight();
2528 
2529             wxCOMPtr<IWICBitmapSource> colorBitmap = wxCreateWICBitmap(sourceBitmap, true);
2530             wxCOMPtr<IWICBitmapSource> maskBitmap = wxCreateWICBitmap(sourceBitmap.GetMask()->GetBitmap(), false);
2531 
2532             hr = wxWICImagingFactory()->CreateBitmap(w, h, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnLoad, &m_srcBitmap);
2533             wxCHECK_HRESULT_RET(hr);
2534 
2535             BYTE* colorBuffer = new BYTE[4 * w * h];
2536             BYTE* maskBuffer = new BYTE[4 * w * h];
2537             BYTE* resultBuffer;
2538 
2539             hr = colorBitmap->CopyPixels(NULL, w * 4, 4 * w * h, colorBuffer);
2540             wxCHECK_HRESULT_RET(hr);
2541             hr = maskBitmap->CopyPixels(NULL, w * 4, 4 * w * h, maskBuffer);
2542             wxCHECK_HRESULT_RET(hr);
2543 
2544             {
2545                 wxBitmapPixelWriteLock lock(m_srcBitmap);
2546 
2547                 UINT bufferSize = 0;
2548                 hr = lock.GetLock()->GetDataPointer(&bufferSize, &resultBuffer);
2549 
2550                 static const wxPBGRAColor transparentColor(wxTransparentColour);
2551 
2552                 // Create the result bitmap
2553                 for ( int i = 0; i < w * h * 4; i += 4 )
2554                 {
2555                     wxPBGRAColor color(colorBuffer + i);
2556                     wxPBGRAColor mask(maskBuffer + i);
2557 
2558                     if ( mask.IsBlack() )
2559                     {
2560                         transparentColor.Write(resultBuffer + i);
2561                     }
2562                     else
2563                     {
2564                         color.Write(resultBuffer + i);
2565                     }
2566                 }
2567             }
2568 
2569             delete[] colorBuffer;
2570             delete[] maskBuffer;
2571         }
2572         else
2573         {
2574             wxCOMPtr<IWICBitmapSource> srcBmp = wxCreateWICBitmap(sourceBitmap, false);
2575             hr = wxWICImagingFactory()->CreateBitmapFromSource(srcBmp, WICBitmapNoCache, &m_srcBitmap);
2576             wxCHECK_HRESULT_RET(hr);
2577         }
2578     }
2579 
wxD2DBitmapResourceHolder(IWICBitmap * pSrcBmp)2580     wxD2DBitmapResourceHolder(IWICBitmap* pSrcBmp) :
2581         m_srcBitmap(pSrcBmp)
2582     {
2583     }
2584 
GetSize() const2585     wxSize GetSize() const
2586     {
2587         UINT w, h;
2588         HRESULT hr = m_srcBitmap->GetSize(&w, &h);
2589         wxCHECK2_HRESULT_RET(hr, wxSize());
2590 
2591         return wxSize((int)w, (int)h);
2592     }
2593 
2594 #if wxUSE_IMAGE
wxD2DBitmapResourceHolder(const wxImage & img)2595     wxD2DBitmapResourceHolder(const wxImage& img)
2596     {
2597         CreateWICBitmapFromImage(img, false, &m_srcBitmap);
2598     }
2599 
ConvertToImage() const2600     wxImage ConvertToImage() const
2601     {
2602         wxImage img;
2603         CreateImageFromWICBitmap(m_srcBitmap, &img);
2604 
2605         return img;
2606     }
2607 #endif // wxUSE_IMAGE
2608 
GetSubBitmap(wxDouble x,wxDouble y,wxDouble w,wxDouble h) const2609     wxD2DBitmapResourceHolder* GetSubBitmap(wxDouble x, wxDouble y, wxDouble w, wxDouble h) const
2610     {
2611         wxCOMPtr<IWICBitmapClipper> clipper;
2612         HRESULT hr = wxWICImagingFactory()->CreateBitmapClipper(&clipper);
2613         wxCHECK2_HRESULT_RET(hr, NULL);
2614 
2615         WICRect r = { (INT)x, (INT)y, (INT)w, (INT)h };
2616         hr = clipper->Initialize(m_srcBitmap, &r);
2617         wxCHECK2_HRESULT_RET(hr, NULL);
2618 
2619         wxCOMPtr<IWICBitmap> subBmp;
2620         hr = wxWICImagingFactory()->CreateBitmapFromSource(clipper, WICBitmapNoCache, &subBmp);
2621         wxCHECK2_HRESULT_RET(hr, NULL);
2622 
2623         return new wxD2DBitmapResourceHolder(subBmp);
2624     }
2625 
2626 protected:
DoAcquireResource()2627     void DoAcquireResource() wxOVERRIDE
2628     {
2629         HRESULT hr = GetContext()->CreateBitmapFromWicBitmap(m_srcBitmap, 0, &m_nativeResource);
2630         wxCHECK_HRESULT_RET(hr);
2631     }
2632 
2633 private:
2634     wxCOMPtr<IWICBitmap> m_srcBitmap;
2635 };
2636 
2637 //-----------------------------------------------------------------------------
2638 // wxD2DBitmapData declaration
2639 //-----------------------------------------------------------------------------
2640 
2641 class wxD2DBitmapData : public wxGraphicsBitmapData, public wxD2DManagedGraphicsData
2642 {
2643 public:
2644     typedef wxD2DBitmapResourceHolder NativeType;
2645 
wxD2DBitmapData(wxGraphicsRenderer * renderer,const wxBitmap & bitmap)2646     wxD2DBitmapData(wxGraphicsRenderer* renderer, const wxBitmap& bitmap) :
2647         wxGraphicsBitmapData(renderer)
2648     {
2649         m_bitmapHolder = new NativeType(bitmap);
2650     }
2651 
wxD2DBitmapData(wxGraphicsRenderer * renderer,const wxImage & image)2652     wxD2DBitmapData(wxGraphicsRenderer* renderer, const wxImage& image) :
2653         wxGraphicsBitmapData(renderer)
2654     {
2655         m_bitmapHolder = new NativeType(image);
2656     }
2657 
wxD2DBitmapData(wxGraphicsRenderer * renderer,NativeType * pseudoNativeBitmap)2658     wxD2DBitmapData(wxGraphicsRenderer* renderer, NativeType* pseudoNativeBitmap) :
2659         wxGraphicsBitmapData(renderer), m_bitmapHolder(pseudoNativeBitmap) {}
2660 
2661     ~wxD2DBitmapData();
2662 
2663     // returns the native representation
2664     void* GetNativeBitmap() const wxOVERRIDE;
2665 
2666     wxCOMPtr<ID2D1Bitmap> GetD2DBitmap();
2667 
GetManagedObject()2668     wxD2DManagedObject* GetManagedObject() wxOVERRIDE
2669     {
2670         return m_bitmapHolder;
2671     }
2672 
2673 private:
2674     NativeType* m_bitmapHolder;
2675 };
2676 
2677 //-----------------------------------------------------------------------------
2678 // wxD2DBitmapData implementation
2679 //-----------------------------------------------------------------------------
2680 
~wxD2DBitmapData()2681 wxD2DBitmapData::~wxD2DBitmapData()
2682 {
2683     delete m_bitmapHolder;
2684 }
2685 
GetNativeBitmap() const2686 void* wxD2DBitmapData::GetNativeBitmap() const
2687 {
2688     return static_cast<void*>(m_bitmapHolder);
2689 }
2690 
GetD2DBitmap()2691 wxCOMPtr<ID2D1Bitmap> wxD2DBitmapData::GetD2DBitmap()
2692 {
2693     return m_bitmapHolder->GetD2DResource();
2694 }
2695 
wxGetD2DBitmapData(const wxGraphicsBitmap & bitmap)2696 wxD2DBitmapData* wxGetD2DBitmapData(const wxGraphicsBitmap& bitmap)
2697 {
2698     return static_cast<wxD2DBitmapData*>(bitmap.GetRefData());
2699 }
2700 
2701 // Helper class used to create and safely release a ID2D1GradientStopCollection from wxGraphicsGradientStops
2702 class wxD2DGradientStopsHelper : public wxD2DResourceHolder<ID2D1GradientStopCollection>
2703 {
2704 public:
wxD2DGradientStopsHelper(const wxGraphicsGradientStops & gradientStops)2705     wxD2DGradientStopsHelper(const wxGraphicsGradientStops& gradientStops)
2706     {
2707         const int stopCount = gradientStops.GetCount();
2708         m_gradientStops.reserve(stopCount);
2709         for ( int i = 0; i < stopCount; ++i )
2710         {
2711             D2D1_GRADIENT_STOP stop;
2712             stop.position = gradientStops.Item(i).GetPosition();
2713             stop.color = wxD2DConvertColour(gradientStops.Item(i).GetColour());
2714             m_gradientStops.push_back(stop);
2715         }
2716     }
2717 
2718 protected:
DoAcquireResource()2719     void DoAcquireResource() wxOVERRIDE
2720     {
2721         wxCHECK_RET(!m_gradientStops.empty(), "No gradient stops provided");
2722 
2723         HRESULT hr = GetContext()->CreateGradientStopCollection(&m_gradientStops[0],
2724             m_gradientStops.size(), D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &m_nativeResource);
2725         wxCHECK_HRESULT_RET(hr);
2726     }
2727 
2728 private:
2729     wxVector<D2D1_GRADIENT_STOP> m_gradientStops;
2730 };
2731 
2732 template <typename B>
2733 class wxD2DBrushResourceHolder : public wxD2DResourceHolder<B>
2734 {
2735 public:
wxD2DBrushResourceHolder(const wxBrush & brush)2736     wxD2DBrushResourceHolder(const wxBrush& brush) : m_sourceBrush(brush) {}
~wxD2DBrushResourceHolder()2737     virtual ~wxD2DBrushResourceHolder() {}
2738 protected:
2739     const wxBrush m_sourceBrush;
2740 };
2741 
2742 class wxD2DSolidBrushResourceHolder : public wxD2DBrushResourceHolder<ID2D1SolidColorBrush>
2743 {
2744 public:
wxD2DSolidBrushResourceHolder(const wxBrush & brush)2745     wxD2DSolidBrushResourceHolder(const wxBrush& brush) : wxD2DBrushResourceHolder(brush) {}
2746 
2747 protected:
DoAcquireResource()2748     void DoAcquireResource() wxOVERRIDE
2749     {
2750         wxColour colour = m_sourceBrush.GetColour();
2751         HRESULT hr = GetContext()->CreateSolidColorBrush(wxD2DConvertColour(colour), &m_nativeResource);
2752         wxCHECK_HRESULT_RET(hr);
2753     }
2754 };
2755 
2756 class wxD2DBitmapBrushResourceHolder : public wxD2DBrushResourceHolder<ID2D1BitmapBrush>
2757 {
2758 public:
wxD2DBitmapBrushResourceHolder(const wxBrush & brush)2759     wxD2DBitmapBrushResourceHolder(const wxBrush& brush) : wxD2DBrushResourceHolder(brush) {}
2760 
2761 protected:
DoAcquireResource()2762     void DoAcquireResource() wxOVERRIDE
2763     {
2764         // TODO: cache this bitmap
2765         wxD2DBitmapResourceHolder bitmap(*(m_sourceBrush.GetStipple()));
2766         bitmap.Bind(GetManager());
2767 
2768         HRESULT result = GetContext()->CreateBitmapBrush(
2769             bitmap.GetD2DResource(),
2770             D2D1::BitmapBrushProperties(
2771             D2D1_EXTEND_MODE_WRAP,
2772             D2D1_EXTEND_MODE_WRAP,
2773             D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR),
2774             &m_nativeResource);
2775 
2776         wxCHECK_HRESULT_RET(result);
2777     }
2778 };
2779 
2780 class wxD2DHatchBrushResourceHolder : public wxD2DBrushResourceHolder<ID2D1BitmapBrush>
2781 {
2782 public:
wxD2DHatchBrushResourceHolder(const wxBrush & brush)2783     wxD2DHatchBrushResourceHolder(const wxBrush& brush) : wxD2DBrushResourceHolder(brush) {}
2784 
2785 protected:
DoAcquireResource()2786     void DoAcquireResource() wxOVERRIDE
2787     {
2788         wxCOMPtr<wxHatchBitmapSource> hatchBitmapSource(new wxHatchBitmapSource(m_sourceBrush.GetStyle(), m_sourceBrush.GetColour()));
2789 
2790         wxCOMPtr<ID2D1Bitmap> bitmap;
2791 
2792         HRESULT hr = GetContext()->CreateBitmapFromWicBitmap(hatchBitmapSource, &bitmap);
2793         wxCHECK_HRESULT_RET(hr);
2794 
2795         hr = GetContext()->CreateBitmapBrush(
2796             bitmap,
2797             D2D1::BitmapBrushProperties(
2798             D2D1_EXTEND_MODE_WRAP,
2799             D2D1_EXTEND_MODE_WRAP,
2800             D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR),
2801             &m_nativeResource);
2802         wxCHECK_HRESULT_RET(hr);
2803     }
2804 };
2805 
2806 class wxD2DLinearGradientBrushResourceHolder : public wxD2DResourceHolder<ID2D1LinearGradientBrush>
2807 {
2808 public:
2809     struct LinearGradientInfo {
2810         const wxDouble x1;
2811         const wxDouble y1;
2812         const wxDouble x2;
2813         const wxDouble y2;
2814         const wxGraphicsGradientStops stops;
2815         const wxGraphicsMatrix matrix;
LinearGradientInfowxD2DLinearGradientBrushResourceHolder::LinearGradientInfo2816         LinearGradientInfo(wxDouble& x1_, wxDouble& y1_,
2817                            wxDouble& x2_, wxDouble& y2_,
2818                            const wxGraphicsGradientStops& stops_,
2819                            const wxGraphicsMatrix& matrix_)
2820             : x1(x1_), y1(y1_), x2(x2_), y2(y2_), stops(stops_), matrix(matrix_) {}
2821     };
2822 
wxD2DLinearGradientBrushResourceHolder(wxDouble & x1,wxDouble & y1,wxDouble & x2,wxDouble & y2,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)2823     wxD2DLinearGradientBrushResourceHolder(wxDouble& x1, wxDouble& y1,
2824                                            wxDouble& x2, wxDouble& y2,
2825                                            const wxGraphicsGradientStops& stops,
2826                                            const wxGraphicsMatrix& matrix)
2827         : m_linearGradientInfo(x1, y1, x2, y2, stops, matrix) {}
2828 
2829 protected:
DoAcquireResource()2830     void DoAcquireResource() wxOVERRIDE
2831     {
2832         wxD2DGradientStopsHelper helper(m_linearGradientInfo.stops);
2833         helper.Bind(GetManager());
2834 
2835         HRESULT hr = GetContext()->CreateLinearGradientBrush(
2836             D2D1::LinearGradientBrushProperties(
2837                 D2D1::Point2F(m_linearGradientInfo.x1, m_linearGradientInfo.y1),
2838                 D2D1::Point2F(m_linearGradientInfo.x2, m_linearGradientInfo.y2)),
2839             helper.GetD2DResource(),
2840             &m_nativeResource);
2841         wxCHECK_HRESULT_RET(hr);
2842 
2843         if (! m_linearGradientInfo.matrix.IsNull())
2844         {
2845             D2D1::Matrix3x2F matrix = wxGetD2DMatrixData(m_linearGradientInfo.matrix)->GetMatrix3x2F();
2846             matrix.Invert();
2847             m_nativeResource->SetTransform(matrix);
2848         }
2849     }
2850 private:
2851     const LinearGradientInfo m_linearGradientInfo;
2852 };
2853 
2854 class wxD2DRadialGradientBrushResourceHolder : public wxD2DResourceHolder<ID2D1RadialGradientBrush>
2855 {
2856 public:
2857     struct RadialGradientInfo {
2858         const wxDouble x1;
2859         const wxDouble y1;
2860         const wxDouble x2;
2861         const wxDouble y2;
2862         const wxDouble radius;
2863         const wxGraphicsGradientStops stops;
2864         const wxGraphicsMatrix matrix;
2865 
RadialGradientInfowxD2DRadialGradientBrushResourceHolder::RadialGradientInfo2866         RadialGradientInfo(wxDouble x1_, wxDouble y1_,
2867                            wxDouble x2_, wxDouble y2_,
2868                            wxDouble r,
2869                            const wxGraphicsGradientStops& stops_,
2870                            const wxGraphicsMatrix& matrix_)
2871             : x1(x1_), y1(y1_), x2(x2_), y2(y2_), radius(r), stops(stops_), matrix(matrix_) {}
2872     };
2873 
wxD2DRadialGradientBrushResourceHolder(wxDouble & x1,wxDouble & y1,wxDouble & x2,wxDouble & y2,wxDouble & r,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)2874     wxD2DRadialGradientBrushResourceHolder(wxDouble& x1, wxDouble& y1,
2875                                            wxDouble& x2, wxDouble& y2,
2876                                            wxDouble& r,
2877                                            const wxGraphicsGradientStops& stops,
2878                                            const wxGraphicsMatrix& matrix)
2879         : m_radialGradientInfo(x1, y1, x2, y2, r, stops, matrix) {}
2880 
2881 protected:
DoAcquireResource()2882     void DoAcquireResource() wxOVERRIDE
2883     {
2884         wxD2DGradientStopsHelper helper(m_radialGradientInfo.stops);
2885         helper.Bind(GetManager());
2886 
2887         wxDouble xo = m_radialGradientInfo.x1 - m_radialGradientInfo.x2;
2888         wxDouble yo = m_radialGradientInfo.y1 - m_radialGradientInfo.y2;
2889 
2890         HRESULT hr = GetContext()->CreateRadialGradientBrush(
2891             D2D1::RadialGradientBrushProperties(
2892                 D2D1::Point2F(m_radialGradientInfo.x1, m_radialGradientInfo.y1),
2893                 D2D1::Point2F(xo, yo),
2894                 m_radialGradientInfo.radius, m_radialGradientInfo.radius),
2895             helper.GetD2DResource(),
2896             &m_nativeResource);
2897         wxCHECK_HRESULT_RET(hr);
2898 
2899         if (! m_radialGradientInfo.matrix.IsNull())
2900         {
2901             D2D1::Matrix3x2F matrix = wxGetD2DMatrixData(m_radialGradientInfo.matrix)->GetMatrix3x2F();
2902             matrix.Invert();
2903             m_nativeResource->SetTransform(matrix);
2904         }
2905     }
2906 
2907 private:
2908     const RadialGradientInfo m_radialGradientInfo;
2909 };
2910 
2911 //-----------------------------------------------------------------------------
2912 // wxD2DBrushData declaration
2913 //-----------------------------------------------------------------------------
2914 
2915 class wxD2DBrushData : public wxGraphicsObjectRefData, public wxD2DManagedGraphicsData
2916 {
2917 public:
2918     wxD2DBrushData(wxGraphicsRenderer* renderer, const wxBrush brush);
2919 
2920     wxD2DBrushData(wxGraphicsRenderer* renderer);
2921 
2922     void CreateLinearGradientBrush(wxDouble x1, wxDouble y1,
2923                                    wxDouble x2, wxDouble y2,
2924                                    const wxGraphicsGradientStops& stops,
2925                                    const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix);
2926 
2927     void CreateRadialGradientBrush(wxDouble startX, wxDouble startY,
2928                                    wxDouble endX, wxDouble endY,
2929                                    wxDouble radius,
2930                                    const wxGraphicsGradientStops& stops,
2931                                    const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix);
2932 
GetBrush() const2933     ID2D1Brush* GetBrush() const
2934     {
2935         return (ID2D1Brush*)(m_brushResourceHolder->GetResource());
2936     }
2937 
GetManagedObject()2938     wxD2DManagedObject* GetManagedObject() wxOVERRIDE
2939     {
2940         return m_brushResourceHolder.get();
2941     }
2942 
2943 private:
2944     wxSharedPtr<wxManagedResourceHolder> m_brushResourceHolder;
2945 };
2946 
2947 //-----------------------------------------------------------------------------
2948 // wxD2DBrushData implementation
2949 //-----------------------------------------------------------------------------
2950 
wxD2DBrushData(wxGraphicsRenderer * renderer,const wxBrush brush)2951 wxD2DBrushData::wxD2DBrushData(wxGraphicsRenderer* renderer, const wxBrush brush)
2952     : wxGraphicsObjectRefData(renderer), m_brushResourceHolder(NULL)
2953 {
2954     if (brush.GetStyle() == wxBRUSHSTYLE_SOLID)
2955     {
2956         m_brushResourceHolder = new wxD2DSolidBrushResourceHolder(brush);
2957     }
2958     else if (brush.IsHatch())
2959     {
2960         m_brushResourceHolder = new wxD2DHatchBrushResourceHolder(brush);
2961     }
2962     else
2963     {
2964         m_brushResourceHolder = new wxD2DBitmapBrushResourceHolder(brush);
2965     }
2966 }
2967 
wxD2DBrushData(wxGraphicsRenderer * renderer)2968 wxD2DBrushData::wxD2DBrushData(wxGraphicsRenderer* renderer)
2969     : wxGraphicsObjectRefData(renderer), m_brushResourceHolder(NULL)
2970 {
2971 }
2972 
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)2973 void wxD2DBrushData::CreateLinearGradientBrush(
2974     wxDouble x1, wxDouble y1,
2975     wxDouble x2, wxDouble y2,
2976     const wxGraphicsGradientStops& stops,
2977     const wxGraphicsMatrix& matrix)
2978 {
2979     m_brushResourceHolder = new wxD2DLinearGradientBrushResourceHolder(
2980         x1, y1, x2, y2, stops, matrix);
2981 }
2982 
CreateRadialGradientBrush(wxDouble startX,wxDouble startY,wxDouble endX,wxDouble endY,wxDouble radius,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)2983 void wxD2DBrushData::CreateRadialGradientBrush(
2984     wxDouble startX, wxDouble startY,
2985     wxDouble endX, wxDouble endY,
2986     wxDouble radius,
2987     const wxGraphicsGradientStops& stops,
2988     const wxGraphicsMatrix& matrix)
2989 {
2990     m_brushResourceHolder = new wxD2DRadialGradientBrushResourceHolder(
2991         startX, startY, endX, endY, radius, stops, matrix);
2992 }
2993 
wxGetD2DBrushData(const wxGraphicsBrush & brush)2994 wxD2DBrushData* wxGetD2DBrushData(const wxGraphicsBrush& brush)
2995 {
2996     return static_cast<wxD2DBrushData*>(brush.GetGraphicsData());
2997 }
2998 
wxIsHatchPenStyle(wxPenStyle penStyle)2999 bool wxIsHatchPenStyle(wxPenStyle penStyle)
3000 {
3001     return penStyle >= wxPENSTYLE_FIRST_HATCH && penStyle <= wxPENSTYLE_LAST_HATCH;
3002 }
3003 
wxConvertPenStyleToBrushStyle(wxPenStyle penStyle)3004 wxBrushStyle wxConvertPenStyleToBrushStyle(wxPenStyle penStyle)
3005 {
3006     switch(penStyle)
3007     {
3008     case wxPENSTYLE_BDIAGONAL_HATCH:
3009         return wxBRUSHSTYLE_BDIAGONAL_HATCH;
3010     case wxPENSTYLE_CROSSDIAG_HATCH:
3011         return wxBRUSHSTYLE_CROSSDIAG_HATCH;
3012     case wxPENSTYLE_FDIAGONAL_HATCH:
3013         return wxBRUSHSTYLE_FDIAGONAL_HATCH;
3014     case wxPENSTYLE_CROSS_HATCH:
3015         return wxBRUSHSTYLE_CROSS_HATCH;
3016     case wxPENSTYLE_HORIZONTAL_HATCH:
3017         return wxBRUSHSTYLE_HORIZONTAL_HATCH;
3018     case wxPENSTYLE_VERTICAL_HATCH:
3019         return wxBRUSHSTYLE_VERTICAL_HATCH;
3020     default:
3021         break;
3022     }
3023 
3024     return wxBRUSHSTYLE_SOLID;
3025 }
3026 
3027 //-----------------------------------------------------------------------------
3028 // wxD2DPenData declaration
3029 //-----------------------------------------------------------------------------
3030 
3031 class wxD2DPenData : public wxGraphicsObjectRefData, public wxD2DManagedGraphicsData
3032 {
3033 public:
3034     wxD2DPenData(wxGraphicsRenderer* renderer,
3035                  ID2D1Factory* direct2dFactory,
3036                  const wxGraphicsPenInfo& info);
3037 
3038     void CreateStrokeStyle(ID2D1Factory* const direct2dfactory);
3039 
3040     ID2D1Brush* GetBrush();
3041 
3042     FLOAT GetWidth();
3043     bool IsZeroWidth() const;
3044     void SetWidth(const wxGraphicsContext* context);
3045 
3046     ID2D1StrokeStyle* GetStrokeStyle();
3047 
GetManagedObject()3048     wxD2DManagedObject* GetManagedObject() wxOVERRIDE
3049     {
3050         return m_stippleBrush->GetManagedObject();
3051     }
3052 
3053 private:
3054     // We store the original pen description for later when we need to recreate
3055     // the device-dependent resources.
3056     const wxGraphicsPenInfo m_penInfo;
3057 
3058     // A stroke style is a device-independent resource.
3059     // Describes the caps, miter limit, line join, and dash information.
3060     wxCOMPtr<ID2D1StrokeStyle> m_strokeStyle;
3061 
3062     // Drawing outlines with Direct2D requires a brush for the color or stipple.
3063     wxSharedPtr<wxD2DBrushData> m_stippleBrush;
3064 
3065     // The width of the stroke
3066     FLOAT m_width;
3067 };
3068 
3069 //-----------------------------------------------------------------------------
3070 // wxD2DPenData implementation
3071 //-----------------------------------------------------------------------------
3072 
wxD2DPenData(wxGraphicsRenderer * renderer,ID2D1Factory * direct2dFactory,const wxGraphicsPenInfo & info)3073 wxD2DPenData::wxD2DPenData(
3074     wxGraphicsRenderer* renderer,
3075     ID2D1Factory* direct2dFactory,
3076     const wxGraphicsPenInfo& info)
3077     : wxGraphicsObjectRefData(renderer),
3078       m_penInfo(info),
3079       m_width(info.GetWidth())
3080 {
3081     CreateStrokeStyle(direct2dFactory);
3082 
3083     wxBrush strokeBrush;
3084 
3085     if (m_penInfo.GetStyle() == wxPENSTYLE_STIPPLE)
3086     {
3087         strokeBrush.SetStipple(m_penInfo.GetStipple());
3088         strokeBrush.SetStyle(wxBRUSHSTYLE_STIPPLE);
3089     }
3090     else if(wxIsHatchPenStyle(m_penInfo.GetStyle()))
3091     {
3092         strokeBrush.SetStyle(wxConvertPenStyleToBrushStyle(m_penInfo.GetStyle()));
3093         strokeBrush.SetColour(m_penInfo.GetColour());
3094     }
3095     else
3096     {
3097         strokeBrush.SetColour(m_penInfo.GetColour());
3098         strokeBrush.SetStyle(wxBRUSHSTYLE_SOLID);
3099     }
3100 
3101     switch ( m_penInfo.GetGradientType() )
3102     {
3103     case wxGRADIENT_NONE:
3104         m_stippleBrush = new wxD2DBrushData(renderer, strokeBrush);
3105         break;
3106 
3107     case wxGRADIENT_LINEAR:
3108         m_stippleBrush = new wxD2DBrushData(renderer);
3109         m_stippleBrush->CreateLinearGradientBrush(
3110                                 m_penInfo.GetX1(), m_penInfo.GetY1(),
3111                                 m_penInfo.GetX2(), m_penInfo.GetY2(),
3112                                 m_penInfo.GetStops(),
3113                                 m_penInfo.GetMatrix());
3114         break;
3115 
3116     case wxGRADIENT_RADIAL:
3117         m_stippleBrush = new wxD2DBrushData(renderer);
3118         m_stippleBrush->CreateRadialGradientBrush(
3119                                 m_penInfo.GetStartX(), m_penInfo.GetStartY(),
3120                                 m_penInfo.GetEndX(), m_penInfo.GetEndY(),
3121                                 m_penInfo.GetRadius(),
3122                                 m_penInfo.GetStops(),
3123                                 m_penInfo.GetMatrix());
3124         break;
3125     }
3126 }
3127 
3128 
CreateStrokeStyle(ID2D1Factory * const direct2dfactory)3129 void wxD2DPenData::CreateStrokeStyle(ID2D1Factory* const direct2dfactory)
3130 {
3131     D2D1_CAP_STYLE capStyle = wxD2DConvertPenCap(m_penInfo.GetCap());
3132     D2D1_LINE_JOIN lineJoin = wxD2DConvertPenJoin(m_penInfo.GetJoin());
3133     D2D1_DASH_STYLE dashStyle = wxD2DConvertPenStyle(m_penInfo.GetStyle());
3134 
3135     int dashCount = 0;
3136     FLOAT* dashes = NULL;
3137 
3138     if (dashStyle == D2D1_DASH_STYLE_CUSTOM)
3139     {
3140         dashCount = m_penInfo.GetDashCount();
3141         dashes = new FLOAT[dashCount];
3142 
3143         for (int i = 0; i < dashCount; ++i)
3144         {
3145             dashes[i] = m_penInfo.GetDash()[i];
3146         }
3147 
3148     }
3149 
3150     direct2dfactory->CreateStrokeStyle(
3151         D2D1::StrokeStyleProperties(capStyle, capStyle, capStyle, lineJoin, 0, dashStyle, 0.0f),
3152         dashes, dashCount,
3153         &m_strokeStyle);
3154 
3155     delete[] dashes;
3156 }
3157 
SetWidth(const wxGraphicsContext * context)3158 void wxD2DPenData::SetWidth(const wxGraphicsContext* context)
3159 {
3160     if (m_penInfo.GetWidth() <= 0)
3161     {
3162         const wxGraphicsMatrix matrix(context->GetTransform());
3163         double x = context->GetContentScaleFactor(), y = x;
3164         matrix.TransformDistance(&x, &y);
3165         m_width = 1 / wxMin(fabs(x), fabs(y));
3166     }
3167 }
3168 
GetBrush()3169 ID2D1Brush* wxD2DPenData::GetBrush()
3170 {
3171     return m_stippleBrush->GetBrush();
3172 }
3173 
GetWidth()3174 FLOAT wxD2DPenData::GetWidth()
3175 {
3176     return m_width;
3177 }
3178 
IsZeroWidth() const3179 bool wxD2DPenData::IsZeroWidth() const
3180 {
3181     return m_penInfo.GetWidth() <= 0;
3182 }
3183 
GetStrokeStyle()3184 ID2D1StrokeStyle* wxD2DPenData::GetStrokeStyle()
3185 {
3186     return m_strokeStyle;
3187 }
3188 
wxGetD2DPenData(const wxGraphicsPen & pen)3189 wxD2DPenData* wxGetD2DPenData(const wxGraphicsPen& pen)
3190 {
3191     return static_cast<wxD2DPenData*>(pen.GetGraphicsData());
3192 }
3193 
3194 class wxD2DFontData : public wxGraphicsObjectRefData
3195 {
3196 public:
3197     wxD2DFontData(wxGraphicsRenderer* renderer, const wxFont& font, const wxRealPoint& dpi, const wxColor& color);
3198 
3199     wxCOMPtr<IDWriteTextLayout> CreateTextLayout(const wxString& text) const;
3200 
GetBrushData()3201     wxD2DBrushData& GetBrushData() { return m_brushData; }
3202 
GetTextFormat() const3203     wxCOMPtr<IDWriteTextFormat> GetTextFormat() const { return m_textFormat; }
3204 
GetFont()3205     wxCOMPtr<IDWriteFont> GetFont() { return m_font; }
3206 
3207 private:
3208     // The native, device-independent font object
3209     wxCOMPtr<IDWriteFont> m_font;
3210 
3211     // The native, device-independent font object
3212     wxCOMPtr<IDWriteTextFormat> m_textFormat;
3213 
3214     // We use a color brush to render the font
3215     wxD2DBrushData m_brushData;
3216 
3217     bool m_underlined;
3218 
3219     bool m_strikethrough;
3220 };
3221 
wxD2DFontData(wxGraphicsRenderer * renderer,const wxFont & font,const wxRealPoint & dpi,const wxColor & color)3222 wxD2DFontData::wxD2DFontData(wxGraphicsRenderer* renderer, const wxFont& font, const wxRealPoint& dpi, const wxColor& color) :
3223     wxGraphicsObjectRefData(renderer), m_brushData(renderer, wxBrush(color)),
3224     m_underlined(font.GetUnderlined()), m_strikethrough(font.GetStrikethrough())
3225 {
3226     HRESULT hr;
3227 
3228     wxCOMPtr<IDWriteGdiInterop> gdiInterop;
3229     hr = wxDWriteFactory()->GetGdiInterop(&gdiInterop);
3230     wxCHECK_HRESULT_RET(hr);
3231 
3232     LOGFONTW logfont;
3233     int n = GetObjectW(font.GetHFONT(), sizeof(logfont), &logfont);
3234     wxCHECK_RET( n > 0, wxS("Failed to obtain font info") );
3235 
3236     // Ensure the LOGFONT object contains the correct font face name
3237     if (logfont.lfFaceName[0] == L'\0')
3238     {
3239         // The length of the font name must not exceed LF_FACESIZE TCHARs,
3240         // including the terminating NULL.
3241         wxString name = font.GetFaceName().Mid(0, WXSIZEOF(logfont.lfFaceName)-1);
3242         for (unsigned int i = 0; i < name.Length(); ++i)
3243         {
3244             logfont.lfFaceName[i] = name.GetChar(i);
3245         }
3246         logfont.lfFaceName[name.Length()] = L'\0';
3247     }
3248 
3249     wxCOMPtr<IDWriteFontFamily> fontFamily;
3250     wxCOMPtr<IDWriteFontCollection> fontCollection; // NULL if font is taken from the system collection
3251 
3252     hr = gdiInterop->CreateFontFromLOGFONT(&logfont, &m_font);
3253     if ( hr == DWRITE_E_NOFONT )
3254     {
3255         // It was attempted to create DirectWrite font from non-TrueType GDI font
3256         // or from private GDI font.
3257 #if wxUSE_PRIVATE_FONTS
3258         // Make private fonts available to D2D.
3259         const wxArrayString& privateFonts = wxGetPrivateFontFileNames();
3260         if ( privateFonts.empty() )
3261         {
3262             wxLogApiError(wxString::Format("IDWriteGdiInterop::CreateFontFromLOGFONT() for '%s'", logfont.lfFaceName), hr);
3263             return;
3264         }
3265         // Update font collection if the list of private fonts has changed.
3266         if ( privateFonts != wxDirect2DFontCollectionLoader::GetFontList() )
3267         {
3268             wxDirect2DFontKey collectionKey = wxDirect2DFontCollectionLoader::SetFontList(privateFonts);
3269 
3270             gs_pPrivateFontCollection.reset();
3271             hr = wxDWriteFactory()->CreateCustomFontCollection(
3272                                         wxDirect2DFontCollectionLoader::GetLoader(),
3273                                         &collectionKey, sizeof(collectionKey),
3274                                         &gs_pPrivateFontCollection);
3275             wxCHECK_HRESULT_RET(hr);
3276         }
3277         wxCHECK_RET(gs_pPrivateFontCollection != NULL, "No custom font collection created");
3278 
3279         UINT32 fontIdx = ~0U;
3280         BOOL fontFound = FALSE;
3281         hr = gs_pPrivateFontCollection->FindFamilyName(logfont.lfFaceName, &fontIdx, &fontFound);
3282         wxCHECK_HRESULT_RET(hr);
3283         if ( !fontFound )
3284         {
3285             wxFAIL_MSG(wxString::Format("Couldn't find custom font family '%s'", logfont.lfFaceName));
3286             return;
3287         }
3288         hr = gs_pPrivateFontCollection->GetFontFamily(fontIdx, &fontFamily);
3289         wxCHECK_HRESULT_RET(hr);
3290 
3291         // Even though DWRITE_FONT_WEIGHT is an enum, it's values are within the same range
3292         // as font width values in LOGFONT (0-1000) so we can cast LONG to this enum.
3293         DWRITE_FONT_WEIGHT fWeight = static_cast<DWRITE_FONT_WEIGHT>(logfont.lfWeight);
3294 
3295         DWRITE_FONT_STYLE fStyle;
3296         if ( logfont.lfItalic == TRUE )
3297             fStyle = DWRITE_FONT_STYLE_ITALIC;
3298         else
3299             fStyle = DWRITE_FONT_STYLE_NORMAL;
3300 
3301         DWRITE_FONT_STRETCH fStretch = DWRITE_FONT_STRETCH_NORMAL;
3302 
3303         hr = fontFamily->GetFirstMatchingFont(fWeight, fStretch, fStyle, &m_font);
3304         wxCHECK_RET(SUCCEEDED(hr),
3305             wxString::Format("Failed to find custom font '%s' (HRESULT = %x)", logfont.lfFaceName, hr));
3306 
3307         fontCollection = gs_pPrivateFontCollection;
3308 #else
3309         return;
3310 #endif // wxUSE_PRIVATE_FONTS
3311     }
3312     else
3313     {
3314         wxCHECK_RET(SUCCEEDED(hr),
3315             wxString::Format("Failed to create font '%s' (HRESULT = %x)", logfont.lfFaceName, hr));
3316 
3317         hr = m_font->GetFontFamily(&fontFamily);
3318         wxCHECK_HRESULT_RET(hr);
3319     }
3320 
3321     wxCOMPtr<IDWriteLocalizedStrings> familyNames;
3322     hr = fontFamily->GetFamilyNames(&familyNames);
3323     wxCHECK_HRESULT_RET(hr);
3324 
3325     UINT32 length;
3326     hr = familyNames->GetStringLength(0, &length);
3327     wxCHECK_HRESULT_RET(hr);
3328 
3329     wchar_t* name = new wchar_t[length+1];
3330     hr = familyNames->GetString(0, name, length+1);
3331     wxCHECK_HRESULT_RET(hr);
3332 
3333     FLOAT fontSize = !dpi.y
3334         ? FLOAT(font.GetPixelSize().GetHeight())
3335         : FLOAT(font.GetFractionalPointSize() * dpi.y / 72);
3336 
3337     hr = wxDWriteFactory()->CreateTextFormat(
3338         name,
3339         fontCollection,
3340         m_font->GetWeight(),
3341         m_font->GetStyle(),
3342         m_font->GetStretch(),
3343         fontSize,
3344         L"en-us",
3345         &m_textFormat);
3346 
3347     delete[] name;
3348 
3349     wxCHECK_HRESULT_RET(hr);
3350 }
3351 
CreateTextLayout(const wxString & text) const3352 wxCOMPtr<IDWriteTextLayout> wxD2DFontData::CreateTextLayout(const wxString& text) const
3353 {
3354     static const FLOAT MAX_WIDTH = FLT_MAX;
3355     static const FLOAT MAX_HEIGHT = FLT_MAX;
3356 
3357     HRESULT hr;
3358 
3359     wxCOMPtr<IDWriteTextLayout> textLayout;
3360 
3361     hr = wxDWriteFactory()->CreateTextLayout(
3362         text.c_str(),
3363         text.length(),
3364         m_textFormat,
3365         MAX_WIDTH,
3366         MAX_HEIGHT,
3367         &textLayout);
3368     wxCHECK2_HRESULT_RET(hr, wxCOMPtr<IDWriteTextLayout>(NULL));
3369 
3370     DWRITE_TEXT_RANGE textRange = { 0, (UINT32) text.length() };
3371 
3372     if (m_underlined)
3373     {
3374         textLayout->SetUnderline(true, textRange);
3375     }
3376 
3377     if (m_strikethrough)
3378     {
3379         textLayout->SetStrikethrough(true, textRange);
3380     }
3381 
3382     return textLayout;
3383 }
3384 
wxGetD2DFontData(const wxGraphicsFont & font)3385 wxD2DFontData* wxGetD2DFontData(const wxGraphicsFont& font)
3386 {
3387     return static_cast<wxD2DFontData*>(font.GetGraphicsData());
3388 }
3389 
3390 // A render target resource holder exposes methods relevant
3391 // for native render targets such as resize
3392 class wxD2DRenderTargetResourceHolder : public wxD2DResourceHolder<ID2D1RenderTarget>
3393 {
3394 public:
3395     // This method is called when an external event signals the underlying DC
3396     // is resized (e.g. the resizing of a window). Some implementations can leave
3397     // this method empty, while others must adjust the render target size to match
3398     // the underlying DC.
Resize()3399     virtual void Resize()
3400     {
3401     }
3402 
3403     // We use this method instead of the one provided by the native render target
3404     // because Direct2D 1.0 render targets do not accept a composition mode
3405     // parameter, while the device context in Direct2D 1.1 does. This way, we make
3406     // best use of the capabilities of each render target.
3407     //
3408     // The default implementation works for all render targets, but the D2D 1.0
3409     // render target holders shouldn't need to override it, since none of the
3410     // 1.0 render targets offer a better version of this method.
DrawBitmap(ID2D1Bitmap * bitmap,const D2D1_RECT_F & srcRect,const D2D1_RECT_F & destRect,wxInterpolationQuality interpolationQuality,wxCompositionMode WXUNUSED (compositionMode))3411     virtual void DrawBitmap(ID2D1Bitmap* bitmap,
3412         const D2D1_RECT_F& srcRect, const D2D1_RECT_F& destRect,
3413         wxInterpolationQuality interpolationQuality,
3414         wxCompositionMode WXUNUSED(compositionMode))
3415     {
3416         m_nativeResource->DrawBitmap(
3417             bitmap,
3418             destRect,
3419             1.0f,
3420             wxD2DConvertBitmapInterpolationMode(interpolationQuality),
3421             srcRect);
3422     }
3423 
3424     // We use this method instead of the one provided by the native render target
3425     // because some contexts might require writing to a buffer (e.g. an image
3426     // context), and some render targets might require additional operations to
3427     // be executed (e.g. the device context must present the swap chain)
Flush()3428     virtual HRESULT Flush()
3429     {
3430         return m_nativeResource->Flush();
3431     }
3432 
3433     // Composition is not supported at in D2D 1.0, and we only allow for:
3434     // wxCOMPOSITION_DEST - which is essentially a no-op and is handled
3435     //                      externally by preventing any draw calls.
3436     // wxCOMPOSITION_OVER - which copies the source over the destination using
3437     //                      alpha blending. This is the default way D2D 1.0
3438     //                      draws images.
SetCompositionMode(wxCompositionMode compositionMode)3439     virtual bool SetCompositionMode(wxCompositionMode compositionMode)
3440     {
3441         if (compositionMode == wxCOMPOSITION_DEST ||
3442             compositionMode == wxCOMPOSITION_OVER)
3443         {
3444             // There's nothing we can do but notify the caller the composition
3445             // mode is supported
3446             return true;
3447         }
3448 
3449         return false;
3450     }
3451 };
3452 
3453 #if wxUSE_IMAGE
3454 class wxD2DImageRenderTargetResourceHolder : public wxD2DRenderTargetResourceHolder
3455 {
3456 public:
wxD2DImageRenderTargetResourceHolder(wxImage * image,ID2D1Factory * factory)3457     wxD2DImageRenderTargetResourceHolder(wxImage* image, ID2D1Factory* factory) :
3458         m_resultImage(image), m_factory(factory)
3459     {
3460     }
3461 
Flush()3462     HRESULT Flush() wxOVERRIDE
3463     {
3464         HRESULT hr = m_nativeResource->Flush();
3465         FlushRenderTargetToImage();
3466         return hr;
3467     }
3468 
~wxD2DImageRenderTargetResourceHolder()3469     ~wxD2DImageRenderTargetResourceHolder()
3470     {
3471         FlushRenderTargetToImage();
3472     }
3473 
3474 protected:
DoAcquireResource()3475     void DoAcquireResource() wxOVERRIDE
3476     {
3477         CreateWICBitmapFromImage(*m_resultImage, true, &m_wicBitmap);
3478 
3479         // Create the render target
3480         HRESULT hr = m_factory->CreateWicBitmapRenderTarget(
3481             m_wicBitmap,
3482             D2D1::RenderTargetProperties(
3483                 D2D1_RENDER_TARGET_TYPE_SOFTWARE,
3484                 D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
3485             &m_nativeResource);
3486         wxCHECK_HRESULT_RET(hr);
3487     }
3488 
3489 private:
FlushRenderTargetToImage()3490     void FlushRenderTargetToImage()
3491     {
3492         CreateImageFromWICBitmap(m_wicBitmap, m_resultImage);
3493    }
3494 
3495 private:
3496     wxImage* m_resultImage;
3497     wxCOMPtr<IWICBitmap> m_wicBitmap;
3498 
3499     ID2D1Factory* m_factory;
3500 };
3501 #endif // wxUSE_IMAGE
3502 
3503 class wxD2DHwndRenderTargetResourceHolder : public wxD2DRenderTargetResourceHolder
3504 {
3505 public:
3506     typedef ID2D1HwndRenderTarget* ImplementationType;
3507 
wxD2DHwndRenderTargetResourceHolder(HWND hwnd,ID2D1Factory * factory)3508     wxD2DHwndRenderTargetResourceHolder(HWND hwnd, ID2D1Factory* factory) :
3509         m_hwnd(hwnd), m_factory(factory)
3510     {
3511     }
3512 
Resize()3513     void Resize() wxOVERRIDE
3514     {
3515         RECT clientRect = wxGetClientRect(m_hwnd);
3516 
3517         D2D1_SIZE_U hwndSize = D2D1::SizeU(
3518             clientRect.right - clientRect.left,
3519             clientRect.bottom - clientRect.top);
3520 
3521         D2D1_SIZE_U renderTargetSize = GetRenderTarget()->GetPixelSize();
3522 
3523         if (hwndSize.width != renderTargetSize.width || hwndSize.height != renderTargetSize.height)
3524         {
3525             GetRenderTarget()->Resize(hwndSize);
3526         }
3527     }
3528 
3529 protected:
DoAcquireResource()3530     void DoAcquireResource() wxOVERRIDE
3531     {
3532         wxCOMPtr<ID2D1HwndRenderTarget> renderTarget;
3533 
3534         HRESULT result;
3535 
3536         RECT clientRect = wxGetClientRect(m_hwnd);
3537 
3538         D2D1_SIZE_U size = D2D1::SizeU(
3539             clientRect.right - clientRect.left,
3540             clientRect.bottom - clientRect.top);
3541 
3542         result = m_factory->CreateHwndRenderTarget(
3543             D2D1::RenderTargetProperties(),
3544             D2D1::HwndRenderTargetProperties(m_hwnd, size),
3545             &renderTarget);
3546 
3547         if (FAILED(result))
3548         {
3549             wxFAIL_MSG("Could not create Direct2D render target");
3550         }
3551 
3552         renderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
3553 
3554         m_nativeResource = renderTarget;
3555     }
3556 
3557 private:
3558     // Converts the underlying resource pointer of type
3559     // ID2D1RenderTarget* to the actual implementation type
GetRenderTarget()3560     ImplementationType GetRenderTarget()
3561     {
3562         return static_cast<ImplementationType>(GetD2DResource().get());
3563     }
3564 
3565 private:
3566     HWND m_hwnd;
3567     ID2D1Factory* m_factory;
3568 };
3569 
3570 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
3571 class wxD2DDeviceContextResourceHolder : public wxD2DRenderTargetResourceHolder
3572 {
3573 public:
wxD2DDeviceContextResourceHolder(ID2D1Factory * factory,HWND hwnd)3574     wxD2DDeviceContextResourceHolder(ID2D1Factory* factory, HWND hwnd) :
3575         m_hwnd(hwnd)
3576     {
3577         HRESULT hr = factory->QueryInterface(IID_ID2D1Factory1, reinterpret_cast<void**>(&m_factory));
3578         wxCHECK_HRESULT_RET(hr);
3579     }
3580 
DrawBitmap(ID2D1Bitmap * bitmap,const D2D1_RECT_F & srcRect,const D2D1_RECT_F & destRect,wxInterpolationQuality interpolationQuality,wxCompositionMode compositionMode)3581     void DrawBitmap(ID2D1Bitmap* bitmap,
3582         const D2D1_RECT_F& srcRect, const D2D1_RECT_F& destRect,
3583         wxInterpolationQuality interpolationQuality,
3584         wxCompositionMode compositionMode) wxOVERRIDE
3585     {
3586         D2D1_POINT_2F offset = D2D1::Point2(destRect.left, destRect.top);
3587         m_context->DrawImage(bitmap,
3588             offset,
3589             srcRect,
3590             wxD2DConvertInterpolationMode(interpolationQuality),
3591             wxD2DConvertCompositionMode(compositionMode));
3592     }
3593 
Flush()3594     HRESULT Flush() wxOVERRIDE
3595     {
3596         HRESULT hr = m_nativeResource->Flush();
3597         DXGI_PRESENT_PARAMETERS params = { 0 };
3598         m_swapChain->Present1(1, 0, &params);
3599         return hr;
3600     }
3601 
3602 protected:
3603 
3604     // Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/hh780339%28v=vs.85%29.aspx
DoAcquireResource()3605     void DoAcquireResource() wxOVERRIDE
3606     {
3607         HRESULT hr;
3608 
3609         // This flag adds support for surfaces with a different color channel ordering than the API default.
3610         // You need it for compatibility with Direct2D.
3611         UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
3612 
3613         // This array defines the set of DirectX hardware feature levels this app  supports.
3614         // The ordering is important and you should  preserve it.
3615         // Don't forget to declare your app's minimum required feature level in its
3616         // description.  All apps are assumed to support 9.1 unless otherwise stated.
3617         D3D_FEATURE_LEVEL featureLevels[] =
3618         {
3619             D3D_FEATURE_LEVEL_11_1,
3620             D3D_FEATURE_LEVEL_11_0,
3621             D3D_FEATURE_LEVEL_10_1,
3622             D3D_FEATURE_LEVEL_10_0,
3623             D3D_FEATURE_LEVEL_9_3,
3624             D3D_FEATURE_LEVEL_9_2,
3625             D3D_FEATURE_LEVEL_9_1
3626         };
3627 
3628         // Create the DX11 API device object, and get a corresponding context.
3629         wxCOMPtr<ID3D11Device> device;
3630         wxCOMPtr<ID3D11DeviceContext> context;
3631 
3632         hr = D3D11CreateDevice(
3633             NULL,                    // specify null to use the default adapter
3634             D3D_DRIVER_TYPE_HARDWARE,
3635             0,
3636             creationFlags,              // optionally set debug and Direct2D compatibility flags
3637             featureLevels,              // list of feature levels this app can support
3638             ARRAYSIZE(featureLevels),   // number of possible feature levels
3639             D3D11_SDK_VERSION,
3640             &device,                    // returns the Direct3D device created
3641             &m_featureLevel,            // returns feature level of device created
3642             &context);                  // returns the device immediate context
3643         wxCHECK_HRESULT_RET(hr);
3644 
3645         // Obtain the underlying DXGI device of the Direct3D11 device.
3646         hr = device->QueryInterface(IID_IDXGIDevice, (void**)&m_dxgiDevice);
3647         wxCHECK_HRESULT_RET(hr);
3648 
3649         // Obtain the Direct2D device for 2-D rendering.
3650         hr = m_factory->CreateDevice(m_dxgiDevice, &m_device);
3651         wxCHECK_HRESULT_RET(hr);
3652 
3653         // Get Direct2D device's corresponding device context object.
3654         hr = m_device->CreateDeviceContext(
3655             D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
3656             &m_context);
3657         wxCHECK_HRESULT_RET(hr);
3658 
3659         m_nativeResource = m_context;
3660 
3661         AttachSurface();
3662     }
3663 
3664 private:
AttachSurface()3665     void AttachSurface()
3666     {
3667         HRESULT hr;
3668 
3669         // Allocate a descriptor.
3670         DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
3671         swapChainDesc.Width = 0;
3672         swapChainDesc.Height = 0;
3673         swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
3674         swapChainDesc.Stereo = false;
3675         swapChainDesc.SampleDesc.Count = 1;
3676         swapChainDesc.SampleDesc.Quality = 0;
3677         swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
3678         swapChainDesc.BufferCount = 2;
3679         swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
3680         swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
3681         swapChainDesc.Flags = 0;
3682 
3683         // Identify the physical adapter (GPU or card) this device is runs on.
3684         wxCOMPtr<IDXGIAdapter> dxgiAdapter;
3685         hr = m_dxgiDevice->GetAdapter(&dxgiAdapter);
3686         wxCHECK_HRESULT_RET(hr);
3687 
3688         // Get the factory object that created the DXGI device.
3689         wxCOMPtr<IDXGIFactory2> dxgiFactory;
3690         hr = dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
3691         wxCHECK_HRESULT_RET(hr);
3692 
3693         // Get the final swap chain for this window from the DXGI factory.
3694         hr = dxgiFactory->CreateSwapChainForHwnd(
3695             m_dxgiDevice,
3696             m_hwnd,
3697             &swapChainDesc,
3698             NULL,    // allow on all displays
3699             NULL,
3700             &m_swapChain);
3701         wxCHECK_HRESULT_RET(hr);
3702 
3703         // Ensure that DXGI doesn't queue more than one frame at a time.
3704         hr = m_dxgiDevice->SetMaximumFrameLatency(1);
3705         wxCHECK_HRESULT_RET(hr);
3706 
3707         // Get the backbuffer for this window which is be the final 3D render target.
3708         wxCOMPtr<ID3D11Texture2D> backBuffer;
3709         hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
3710         wxCHECK_HRESULT_RET(hr);
3711 
3712         FLOAT dpiX, dpiY;
3713         dpiX = dpiY = (FLOAT)::GetDpiForWindow(m_hwnd);
3714 
3715         // Now we set up the Direct2D render target bitmap linked to the swapchain.
3716         // Whenever we render to this bitmap, it is directly rendered to the
3717         // swap chain associated with the window.
3718         D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
3719             D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
3720             D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
3721             dpiX, dpiY);
3722 
3723         // Direct2D needs the dxgi version of the backbuffer surface pointer.
3724         wxCOMPtr<IDXGISurface> dxgiBackBuffer;
3725         hr = m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer));
3726         wxCHECK_HRESULT_RET(hr);
3727 
3728         // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
3729         hr = m_context->CreateBitmapFromDxgiSurface(
3730             dxgiBackBuffer.get(),
3731             &bitmapProperties,
3732             &m_targetBitmap);
3733         wxCHECK_HRESULT_RET(hr);
3734 
3735         // Now we can set the Direct2D render target.
3736         m_context->SetTarget(m_targetBitmap);
3737     }
3738 
~wxD2DDeviceContextResourceHolder()3739     ~wxD2DDeviceContextResourceHolder()
3740     {
3741         DXGI_PRESENT_PARAMETERS params = { 0 };
3742         m_swapChain->Present1(1, 0, &params);
3743     }
3744 
3745 private:
3746     wxCOMPtr<ID2D1Factory1> m_factory;
3747 
3748     HWND m_hwnd;
3749 
3750     D3D_FEATURE_LEVEL m_featureLevel;
3751     wxCOMPtr<IDXGIDevice1> m_dxgiDevice;
3752     wxCOMPtr<ID2D1Device> m_device;
3753     wxCOMPtr<ID2D1DeviceContext> m_context;
3754     wxCOMPtr<ID2D1Bitmap1> m_targetBitmap;
3755     wxCOMPtr<IDXGISwapChain1> m_swapChain;
3756 };
3757 #endif
3758 
3759 class wxD2DDCRenderTargetResourceHolder : public wxD2DRenderTargetResourceHolder
3760 {
3761 public:
wxD2DDCRenderTargetResourceHolder(ID2D1Factory * factory,HDC hdc,D2D1_ALPHA_MODE alphaMode)3762     wxD2DDCRenderTargetResourceHolder(ID2D1Factory* factory, HDC hdc, D2D1_ALPHA_MODE alphaMode) :
3763         m_factory(factory), m_hdc(hdc), m_alphaMode(alphaMode)
3764     {
3765     }
3766 
3767 protected:
DoAcquireResource()3768     void DoAcquireResource() wxOVERRIDE
3769     {
3770         wxCOMPtr<ID2D1DCRenderTarget> renderTarget;
3771         D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties = D2D1::RenderTargetProperties(
3772             D2D1_RENDER_TARGET_TYPE_DEFAULT,
3773             D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, m_alphaMode));
3774 
3775         HRESULT hr = m_factory->CreateDCRenderTarget(
3776             &renderTargetProperties,
3777             &renderTarget);
3778         wxCHECK_HRESULT_RET(hr);
3779 
3780         // We want draw on the entire device area.
3781         // GetClipBox() retrieves logical size of DC
3782         // what is what we need to pass to BindDC.
3783         RECT r;
3784         int status = ::GetClipBox(m_hdc, &r);
3785         wxCHECK_RET( status != ERROR, wxS("Error retrieving DC dimensions") );
3786 
3787         hr = renderTarget->BindDC(m_hdc, &r);
3788         wxCHECK_HRESULT_RET(hr);
3789         renderTarget->SetTransform(
3790                        D2D1::Matrix3x2F::Translation(-r.left, -r.top));
3791 
3792         m_nativeResource = renderTarget;
3793     }
3794 
3795 private:
3796     ID2D1Factory* m_factory;
3797     HDC m_hdc;
3798     D2D1_ALPHA_MODE m_alphaMode;
3799 };
3800 
3801 // The null context has no state of its own and does nothing.
3802 // It is only used as a base class for the lightweight
3803 // measuring context. The measuring context cannot inherit from
3804 // the default implementation wxD2DContext, because some methods
3805 // from wxD2DContext require the presence of a "context"
3806 // (render target) in order to acquire various device-dependent
3807 // resources. Without a proper context, those methods would fail.
3808 // The methods implemented in the null context are fundamentally no-ops.
3809 class wxNullContext : public wxGraphicsContext
3810 {
3811 public:
wxNullContext(wxGraphicsRenderer * renderer)3812     wxNullContext(wxGraphicsRenderer* renderer) : wxGraphicsContext(renderer) {}
GetTextExtent(const wxString &,wxDouble *,wxDouble *,wxDouble *,wxDouble *) const3813     void GetTextExtent(const wxString&, wxDouble*, wxDouble*, wxDouble*, wxDouble*) const wxOVERRIDE {}
GetPartialTextExtents(const wxString &,wxArrayDouble &) const3814     void GetPartialTextExtents(const wxString&, wxArrayDouble&) const wxOVERRIDE {}
Clip(const wxRegion &)3815     void Clip(const wxRegion&) wxOVERRIDE {}
Clip(wxDouble,wxDouble,wxDouble,wxDouble)3816     void Clip(wxDouble, wxDouble, wxDouble, wxDouble) wxOVERRIDE {}
ResetClip()3817     void ResetClip() wxOVERRIDE {}
GetClipBox(wxDouble *,wxDouble *,wxDouble *,wxDouble *)3818     void GetClipBox(wxDouble*, wxDouble*, wxDouble*, wxDouble*) wxOVERRIDE {}
GetNativeContext()3819     void* GetNativeContext() wxOVERRIDE { return NULL; }
SetAntialiasMode(wxAntialiasMode)3820     bool SetAntialiasMode(wxAntialiasMode) wxOVERRIDE { return false; }
SetInterpolationQuality(wxInterpolationQuality)3821     bool SetInterpolationQuality(wxInterpolationQuality) wxOVERRIDE { return false; }
SetCompositionMode(wxCompositionMode)3822     bool SetCompositionMode(wxCompositionMode) wxOVERRIDE { return false; }
BeginLayer(wxDouble)3823     void BeginLayer(wxDouble) wxOVERRIDE {}
EndLayer()3824     void EndLayer() wxOVERRIDE {}
Translate(wxDouble,wxDouble)3825     void Translate(wxDouble, wxDouble) wxOVERRIDE {}
Scale(wxDouble,wxDouble)3826     void Scale(wxDouble, wxDouble) wxOVERRIDE {}
Rotate(wxDouble)3827     void Rotate(wxDouble) wxOVERRIDE {}
ConcatTransform(const wxGraphicsMatrix &)3828     void ConcatTransform(const wxGraphicsMatrix&) wxOVERRIDE {}
SetTransform(const wxGraphicsMatrix &)3829     void SetTransform(const wxGraphicsMatrix&) wxOVERRIDE {}
GetTransform() const3830     wxGraphicsMatrix GetTransform() const wxOVERRIDE { return wxNullGraphicsMatrix; }
StrokePath(const wxGraphicsPath &)3831     void StrokePath(const wxGraphicsPath&) wxOVERRIDE {}
FillPath(const wxGraphicsPath &,wxPolygonFillMode)3832     void FillPath(const wxGraphicsPath&, wxPolygonFillMode) wxOVERRIDE {}
DrawBitmap(const wxGraphicsBitmap &,wxDouble,wxDouble,wxDouble,wxDouble)3833     void DrawBitmap(const wxGraphicsBitmap&, wxDouble, wxDouble, wxDouble, wxDouble) wxOVERRIDE {}
DrawBitmap(const wxBitmap &,wxDouble,wxDouble,wxDouble,wxDouble)3834     void DrawBitmap(const wxBitmap&, wxDouble, wxDouble, wxDouble, wxDouble) wxOVERRIDE {}
DrawIcon(const wxIcon &,wxDouble,wxDouble,wxDouble,wxDouble)3835     void DrawIcon(const wxIcon&, wxDouble, wxDouble, wxDouble, wxDouble) wxOVERRIDE {}
PushState()3836     void PushState() wxOVERRIDE {}
PopState()3837     void PopState() wxOVERRIDE {}
Flush()3838     void Flush() wxOVERRIDE {}
3839 
3840 protected:
DoDrawText(const wxString &,wxDouble,wxDouble)3841     void DoDrawText(const wxString&, wxDouble, wxDouble) wxOVERRIDE {}
3842 };
3843 
3844 class wxD2DMeasuringContext : public wxNullContext
3845 {
3846 public:
wxD2DMeasuringContext(wxGraphicsRenderer * renderer)3847     wxD2DMeasuringContext(wxGraphicsRenderer* renderer) : wxNullContext(renderer) {}
3848 
GetTextExtent(const wxString & str,wxDouble * width,wxDouble * height,wxDouble * descent,wxDouble * externalLeading) const3849     void GetTextExtent(const wxString& str, wxDouble* width, wxDouble* height, wxDouble* descent, wxDouble* externalLeading) const wxOVERRIDE
3850     {
3851         GetTextExtent(wxGetD2DFontData(m_font), str, width, height, descent, externalLeading);
3852     }
3853 
GetPartialTextExtents(const wxString & text,wxArrayDouble & widths) const3854     void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const wxOVERRIDE
3855     {
3856         GetPartialTextExtents(wxGetD2DFontData(m_font), text, widths);
3857     }
3858 
GetPartialTextExtents(wxD2DFontData * fontData,const wxString & text,wxArrayDouble & widths)3859     static void GetPartialTextExtents(wxD2DFontData* fontData, const wxString& text, wxArrayDouble& widths)
3860     {
3861         for (unsigned int i = 0; i < text.Length(); ++i)
3862         {
3863             wxDouble width;
3864             GetTextExtent(fontData, text.SubString(0, i), &width, NULL, NULL, NULL);
3865             widths.push_back(width);
3866         }
3867     }
3868 
GetTextExtent(wxD2DFontData * fontData,const wxString & str,wxDouble * width,wxDouble * height,wxDouble * descent,wxDouble * externalLeading)3869     static void GetTextExtent(wxD2DFontData* fontData, const wxString& str, wxDouble* width, wxDouble* height, wxDouble* descent, wxDouble* externalLeading)
3870     {
3871         wxCOMPtr<IDWriteTextLayout> textLayout = fontData->CreateTextLayout(str);
3872         wxCOMPtr<IDWriteFont> font = fontData->GetFont();
3873 
3874         DWRITE_TEXT_METRICS textMetrics;
3875         textLayout->GetMetrics(&textMetrics);
3876 
3877         DWRITE_FONT_METRICS fontMetrics;
3878         font->GetMetrics(&fontMetrics);
3879 
3880         FLOAT ratio = fontData->GetTextFormat()->GetFontSize() / (FLOAT)fontMetrics.designUnitsPerEm;
3881 
3882         if (width != NULL) *width = textMetrics.widthIncludingTrailingWhitespace;
3883         if (height != NULL) *height = textMetrics.height;
3884 
3885         if (descent != NULL) *descent = fontMetrics.descent * ratio;
3886         if (externalLeading != NULL) *externalLeading = wxMax(0.0f, (fontMetrics.ascent + fontMetrics.descent) * ratio - textMetrics.height);
3887     }
3888 };
3889 
3890 //-----------------------------------------------------------------------------
3891 // wxD2DContext declaration
3892 //-----------------------------------------------------------------------------
3893 
3894 class wxD2DContext : public wxGraphicsContext, wxD2DResourceManager
3895 {
3896 public:
3897     // Create the context for the given HWND, which may be associated (if it's
3898     // non-null) with the given wxWindow.
3899     wxD2DContext(wxGraphicsRenderer* renderer,
3900                  ID2D1Factory* direct2dFactory,
3901                  HWND hwnd,
3902                  wxWindow* window = NULL);
3903 
3904     // Create the context for the given HDC which may be associated (if it's
3905     // non-null) with the given wxDC.
3906     wxD2DContext(wxGraphicsRenderer* renderer,
3907                  ID2D1Factory* direct2dFactory,
3908                  HDC hdc,
3909                  const wxDC* dc = NULL,
3910                  D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_IGNORE);
3911 
3912 #if wxUSE_IMAGE
3913     wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, wxImage& image);
3914 #endif // wxUSE_IMAGE
3915 
3916     wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, void* nativeContext);
3917 
3918     ~wxD2DContext();
3919 
3920     void Clip(const wxRegion& region) wxOVERRIDE;
3921 
3922     void Clip(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3923 
3924     void ResetClip() wxOVERRIDE;
3925 
3926     void GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h) wxOVERRIDE;
3927 
3928     // The native context used by wxD2DContext is a Direct2D render target.
3929     void* GetNativeContext() wxOVERRIDE;
3930 
3931     bool SetAntialiasMode(wxAntialiasMode antialias) wxOVERRIDE;
3932 
3933     bool SetInterpolationQuality(wxInterpolationQuality interpolation) wxOVERRIDE;
3934 
3935     bool SetCompositionMode(wxCompositionMode op) wxOVERRIDE;
3936 
3937     void BeginLayer(wxDouble opacity) wxOVERRIDE;
3938 
3939     void EndLayer() wxOVERRIDE;
3940 
3941     void Translate(wxDouble dx, wxDouble dy) wxOVERRIDE;
3942 
3943     void Scale(wxDouble xScale, wxDouble yScale) wxOVERRIDE;
3944 
3945     void Rotate(wxDouble angle) wxOVERRIDE;
3946 
3947     void ConcatTransform(const wxGraphicsMatrix& matrix) wxOVERRIDE;
3948 
3949     void SetTransform(const wxGraphicsMatrix& matrix) wxOVERRIDE;
3950 
3951     wxGraphicsMatrix GetTransform() const wxOVERRIDE;
3952 
3953     void StrokePath(const wxGraphicsPath& p) wxOVERRIDE;
3954 
3955     void FillPath(const wxGraphicsPath& p , wxPolygonFillMode fillStyle = wxODDEVEN_RULE) wxOVERRIDE;
3956 
3957     void DrawRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3958 
3959     void DrawRoundedRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) wxOVERRIDE;
3960 
3961     void DrawEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3962 
3963     void DrawBitmap(const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3964 
3965     void DrawBitmap(const wxBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3966 
3967     void DrawIcon(const wxIcon& icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
3968 
3969     void PushState() wxOVERRIDE;
3970 
3971     void PopState() wxOVERRIDE;
3972 
3973     void GetTextExtent(
3974         const wxString& str,
3975         wxDouble* width,
3976         wxDouble* height,
3977         wxDouble* descent,
3978         wxDouble* externalLeading) const wxOVERRIDE;
3979 
3980     void GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const wxOVERRIDE;
3981 
3982     bool ShouldOffset() const wxOVERRIDE;
3983 
3984     void SetPen(const wxGraphicsPen& pen) wxOVERRIDE;
3985 
3986     void Flush() wxOVERRIDE;
3987 
3988     void GetDPI(wxDouble* dpiX, wxDouble* dpiY) const wxOVERRIDE;
3989 
GetContext()3990     wxD2DContextSupplier::ContextType GetContext() wxOVERRIDE
3991     {
3992         return GetRenderTarget();
3993     }
3994 
3995 private:
3996     void Init();
3997 
3998     void DoDrawText(const wxString& str, wxDouble x, wxDouble y) wxOVERRIDE;
3999 
4000     void EnsureInitialized();
4001 
4002     HRESULT CreateRenderTarget();
4003 
4004     void AdjustRenderTargetSize();
4005 
4006     void ReleaseDeviceDependentResources();
4007 
4008     ID2D1RenderTarget* GetRenderTarget() const;
4009 
4010     void SetClipLayer(ID2D1Geometry* clipGeometry);
4011 
4012 private:
4013     enum LayerType
4014     {
4015         CLIP_LAYER,
4016         OTHER_LAYER
4017     };
4018 
4019     struct LayerData
4020     {
4021         LayerType type;
4022         D2D1_LAYER_PARAMETERS params;
4023         wxCOMPtr<ID2D1Layer> layer;
4024         wxCOMPtr<ID2D1Geometry> geometry;
4025         D2D1_MATRIX_3X2_F transformMatrix;
4026     };
4027 
4028     struct StateData
4029     {
4030         // A ID2D1DrawingStateBlock represents the drawing state of a render target:
4031         // the anti aliasing mode, transform, tags, and text-rendering options.
4032         // The context owns these pointers and is responsible for releasing them.
4033         wxCOMPtr<ID2D1DrawingStateBlock> drawingState;
4034         // We need to store also current layers.
4035         wxStack<LayerData> layers;
4036     };
4037 
4038 private:
4039     ID2D1Factory* m_direct2dFactory;
4040     wxSharedPtr<wxD2DRenderTargetResourceHolder> m_renderTargetHolder;
4041     wxStack<StateData> m_stateStack;
4042     wxStack<LayerData> m_layers;
4043     ID2D1RenderTarget* m_cachedRenderTarget;
4044     D2D1::Matrix3x2F m_initTransform;
4045     // Clipping box
4046     bool m_isClipBoxValid;
4047     double m_clipX1, m_clipY1, m_clipX2, m_clipY2;
4048 
4049 private:
4050     wxDECLARE_NO_COPY_CLASS(wxD2DContext);
4051 };
4052 
4053 //-----------------------------------------------------------------------------
4054 // wxD2DContext implementation
4055 //-----------------------------------------------------------------------------
4056 
wxD2DContext(wxGraphicsRenderer * renderer,ID2D1Factory * direct2dFactory,HWND hwnd,wxWindow * window)4057 wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer,
4058                            ID2D1Factory* direct2dFactory,
4059                            HWND hwnd,
4060                            wxWindow* window) :
4061     wxGraphicsContext(renderer, window), m_direct2dFactory(direct2dFactory),
4062 #if wxD2D_DEVICE_CONTEXT_SUPPORTED
4063     m_renderTargetHolder(new wxD2DDeviceContextResourceHolder(direct2dFactory, hwnd))
4064 #else
4065     m_renderTargetHolder(new wxD2DHwndRenderTargetResourceHolder(hwnd, direct2dFactory))
4066 #endif
4067 {
4068     RECT r = wxGetWindowRect(hwnd);
4069     m_width = r.right - r.left;
4070     m_height = r.bottom - r.top;
4071     Init();
4072 }
4073 
wxD2DContext(wxGraphicsRenderer * renderer,ID2D1Factory * direct2dFactory,HDC hdc,const wxDC * dc,D2D1_ALPHA_MODE alphaMode)4074 wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer,
4075                            ID2D1Factory* direct2dFactory,
4076                            HDC hdc,
4077                            const wxDC* dc,
4078                            D2D1_ALPHA_MODE alphaMode) :
4079     wxGraphicsContext(renderer, dc->GetWindow()), m_direct2dFactory(direct2dFactory),
4080     m_renderTargetHolder(new wxD2DDCRenderTargetResourceHolder(direct2dFactory, hdc, alphaMode))
4081 {
4082     if ( dc )
4083     {
4084         const wxSize dcSize = dc->GetSize();
4085         m_width = dcSize.GetWidth();
4086         m_height = dcSize.GetHeight();
4087     }
4088 
4089     Init();
4090 }
4091 
4092 #if wxUSE_IMAGE
wxD2DContext(wxGraphicsRenderer * renderer,ID2D1Factory * direct2dFactory,wxImage & image)4093 wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, wxImage& image) :
4094     wxGraphicsContext(renderer), m_direct2dFactory(direct2dFactory),
4095     m_renderTargetHolder(new wxD2DImageRenderTargetResourceHolder(&image, direct2dFactory))
4096 {
4097     m_width = image.GetWidth();
4098     m_height = image.GetHeight();
4099     Init();
4100 }
4101 #endif // wxUSE_IMAGE
4102 
wxD2DContext(wxGraphicsRenderer * renderer,ID2D1Factory * direct2dFactory,void * nativeContext)4103 wxD2DContext::wxD2DContext(wxGraphicsRenderer* renderer, ID2D1Factory* direct2dFactory, void* nativeContext) :
4104     wxGraphicsContext(renderer), m_direct2dFactory(direct2dFactory)
4105 {
4106     m_renderTargetHolder = *((wxSharedPtr<wxD2DRenderTargetResourceHolder>*)nativeContext);
4107     m_width = 0;
4108     m_height = 0;
4109     Init();
4110 }
4111 
Init()4112 void wxD2DContext::Init()
4113 {
4114     m_cachedRenderTarget = NULL;
4115     m_composition = wxCOMPOSITION_OVER;
4116     m_renderTargetHolder->Bind(this);
4117     m_enableOffset = true;
4118     m_isClipBoxValid = false;
4119     m_clipX1 = m_clipY1 = m_clipX2 = m_clipY2 = 0.0;
4120     EnsureInitialized();
4121 }
4122 
~wxD2DContext()4123 wxD2DContext::~wxD2DContext()
4124 {
4125     // Remove all layers from the stack of layers.
4126     while ( !m_layers.empty() )
4127     {
4128         LayerData ld = m_layers.top();
4129         m_layers.pop();
4130 
4131         GetRenderTarget()->PopLayer();
4132         ld.layer.reset();
4133         ld.geometry.reset();
4134     }
4135 
4136     HRESULT result = GetRenderTarget()->EndDraw();
4137     wxCHECK_HRESULT_RET(result);
4138 
4139     ReleaseResources();
4140 }
4141 
GetRenderTarget() const4142 ID2D1RenderTarget* wxD2DContext::GetRenderTarget() const
4143 {
4144     return m_cachedRenderTarget;
4145 }
4146 
Clip(const wxRegion & region)4147 void wxD2DContext::Clip(const wxRegion& region)
4148 {
4149     wxCOMPtr<ID2D1Geometry> clipGeometry = wxD2DConvertRegionToGeometry(m_direct2dFactory, region);
4150 
4151     SetClipLayer(clipGeometry);
4152 }
4153 
Clip(wxDouble x,wxDouble y,wxDouble w,wxDouble h)4154 void wxD2DContext::Clip(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4155 {
4156     wxCOMPtr<ID2D1RectangleGeometry> clipGeometry;
4157     HRESULT hr = m_direct2dFactory->CreateRectangleGeometry(
4158                         D2D1::RectF(x, y, x + w, y + h), &clipGeometry);
4159     wxCHECK_HRESULT_RET(hr);
4160 
4161     SetClipLayer(clipGeometry);
4162 }
4163 
SetClipLayer(ID2D1Geometry * clipGeometry)4164 void wxD2DContext::SetClipLayer(ID2D1Geometry* clipGeometry)
4165 {
4166     EnsureInitialized();
4167 
4168     wxCOMPtr<ID2D1Layer> clipLayer;
4169     HRESULT hr = GetRenderTarget()->CreateLayer(&clipLayer);
4170     wxCHECK_HRESULT_RET(hr);
4171 
4172     LayerData ld;
4173     ld.type = CLIP_LAYER;
4174     ld.params = D2D1::LayerParameters(D2D1::InfiniteRect(), clipGeometry, GetRenderTarget()->GetAntialiasMode());
4175     ld.layer = clipLayer;
4176     ld.geometry = clipGeometry;
4177     // We need to store CTM to be able to re-apply
4178     // the layer at the original position later on.
4179     GetRenderTarget()->GetTransform(&ld.transformMatrix);
4180 
4181     GetRenderTarget()->PushLayer(ld.params, clipLayer);
4182     // Store layer parameters.
4183     m_layers.push(ld);
4184 
4185     m_isClipBoxValid = false;
4186 }
4187 
ResetClip()4188 void wxD2DContext::ResetClip()
4189 {
4190     wxStack<LayerData> layersToRestore;
4191     // Remove all clipping layers from the stack of layers.
4192     while ( !m_layers.empty() )
4193     {
4194         LayerData ld = m_layers.top();
4195         m_layers.pop();
4196 
4197         if ( ld.type == CLIP_LAYER )
4198         {
4199             GetRenderTarget()->PopLayer();
4200             ld.layer.reset();
4201             ld.geometry.reset();
4202             continue;
4203         }
4204 
4205         GetRenderTarget()->PopLayer();
4206         // Save non-clipping layer
4207         layersToRestore.push(ld);
4208     }
4209 
4210     HRESULT hr = GetRenderTarget()->Flush();
4211     wxCHECK_HRESULT_RET(hr);
4212 
4213     // Re-apply all remaining non-clipping layers.
4214     // First, save current transformation matrix.
4215     D2D1_MATRIX_3X2_F currTransform;
4216     GetRenderTarget()->GetTransform(&currTransform);
4217     while ( !layersToRestore.empty() )
4218     {
4219         LayerData ld = layersToRestore.top();
4220         layersToRestore.pop();
4221 
4222         // Restore layer at original position.
4223         GetRenderTarget()->SetTransform(&ld.transformMatrix);
4224         GetRenderTarget()->PushLayer(ld.params, ld.layer);
4225         // Store layer parameters.
4226         m_layers.push(ld);
4227     }
4228     // Restore current transformation matrix.
4229     GetRenderTarget()->SetTransform(&currTransform);
4230 
4231     m_isClipBoxValid = false;
4232 }
4233 
GetClipBox(wxDouble * x,wxDouble * y,wxDouble * w,wxDouble * h)4234 void wxD2DContext::GetClipBox(wxDouble* x, wxDouble* y, wxDouble* w, wxDouble* h)
4235 {
4236     if ( !m_isClipBoxValid )
4237     {
4238         // To obtain actual clipping box we have to start with rectangle
4239         // covering the entire render target and interesect with this rectangle
4240         // all clipping layers. Bounding box of the final geometry
4241         // (being intersection of all clipping layers) is a clipping box.
4242 
4243         HRESULT hr;
4244         wxCOMPtr<ID2D1RectangleGeometry> rectGeometry;
4245         hr = m_direct2dFactory->CreateRectangleGeometry(
4246                     D2D1::RectF(0.0F, 0.0F, (FLOAT)m_width, (FLOAT)m_height),
4247                     &rectGeometry);
4248         wxCHECK_HRESULT_RET(hr);
4249 
4250         wxCOMPtr<ID2D1Geometry> clipGeometry(rectGeometry);
4251 
4252         wxStack<LayerData> layers(m_layers);
4253         while( !layers.empty() )
4254         {
4255             LayerData ld = layers.top();
4256             layers.pop();
4257 
4258             if ( ld.type == CLIP_LAYER )
4259             {
4260                 // If current geometry is empty (null region)
4261                 // or there is no intersection between geometries
4262                 // then final result is "null" rectangle geometry.
4263                 FLOAT area;
4264                 hr = ld.geometry->ComputeArea(ld.transformMatrix, &area);
4265                 wxCHECK_HRESULT_RET(hr);
4266                 D2D1_GEOMETRY_RELATION geomRel;
4267                 hr = clipGeometry->CompareWithGeometry(ld.geometry, ld.transformMatrix, &geomRel);
4268                 wxCHECK_HRESULT_RET(hr);
4269                 if ( area <= FLT_MIN || geomRel == D2D1_GEOMETRY_RELATION_DISJOINT )
4270                 {
4271                     wxCOMPtr<ID2D1RectangleGeometry> nullGeometry;
4272                     hr = m_direct2dFactory->CreateRectangleGeometry(
4273                                 D2D1::RectF(0.0F, 0.0F, 0.0F, 0.0F), &nullGeometry);
4274                     wxCHECK_HRESULT_RET(hr);
4275 
4276                     clipGeometry.reset();
4277                     clipGeometry = nullGeometry;
4278                     break;
4279                 }
4280 
4281                 wxCOMPtr<ID2D1PathGeometry> pathGeometryClip;
4282                 hr = m_direct2dFactory->CreatePathGeometry(&pathGeometryClip);
4283                 wxCHECK_HRESULT_RET(hr);
4284                 wxCOMPtr<ID2D1GeometrySink> pGeometrySink;
4285                 hr = pathGeometryClip->Open(&pGeometrySink);
4286                 wxCHECK_HRESULT_RET(hr);
4287 
4288                 hr = clipGeometry->CombineWithGeometry(ld.geometry, D2D1_COMBINE_MODE_INTERSECT,
4289                                                        ld.transformMatrix, pGeometrySink);
4290                 wxCHECK_HRESULT_RET(hr);
4291                 hr = pGeometrySink->Close();
4292                 wxCHECK_HRESULT_RET(hr);
4293                 pGeometrySink.reset();
4294 
4295                 clipGeometry = pathGeometryClip;
4296                 pathGeometryClip.reset();
4297             }
4298         }
4299 
4300         // Final clipping geometry is given in device coordinates
4301         // so we need to transform its bounds to logical coordinates.
4302         D2D1::Matrix3x2F currTransform;
4303         GetRenderTarget()->GetTransform(&currTransform);
4304         currTransform.Invert();
4305 
4306         D2D1_RECT_F bounds;
4307         // First check if clip region is empty.
4308         FLOAT clipArea;
4309         hr = clipGeometry->ComputeArea(currTransform, &clipArea);
4310         wxCHECK_HRESULT_RET(hr);
4311         if ( clipArea <= FLT_MIN )
4312         {
4313             bounds.left = bounds.top = bounds.right = bounds.bottom = 0.0F;
4314         }
4315         else
4316         {
4317             // If it is not empty then get it bounds.
4318             hr = clipGeometry->GetBounds(currTransform, &bounds);
4319             wxCHECK_HRESULT_RET(hr);
4320         }
4321 
4322         m_clipX1 = bounds.left;
4323         m_clipY1 = bounds.top;
4324         m_clipX2 = bounds.right;
4325         m_clipY2 = bounds.bottom;
4326         m_isClipBoxValid = true;
4327     }
4328 
4329     if ( x )
4330         *x = m_clipX1;
4331     if ( y )
4332         *y = m_clipY1;
4333     if ( w )
4334         *w = m_clipX2 - m_clipX1;
4335     if ( h )
4336         *h = m_clipY2 - m_clipY1;
4337 }
4338 
GetNativeContext()4339 void* wxD2DContext::GetNativeContext()
4340 {
4341     return &m_renderTargetHolder;
4342 }
4343 
StrokePath(const wxGraphicsPath & p)4344 void wxD2DContext::StrokePath(const wxGraphicsPath& p)
4345 {
4346     if (m_composition == wxCOMPOSITION_DEST)
4347         return;
4348 
4349     wxD2DOffsetHelper helper(this);
4350 
4351     EnsureInitialized();
4352     AdjustRenderTargetSize();
4353 
4354     wxD2DPathData* pathData = wxGetD2DPathData(p);
4355     pathData->Flush();
4356 
4357     if (!m_pen.IsNull())
4358     {
4359         wxD2DPenData* penData = wxGetD2DPenData(m_pen);
4360         penData->SetWidth(this);
4361         penData->Bind(this);
4362         ID2D1Brush* nativeBrush = penData->GetBrush();
4363         GetRenderTarget()->DrawGeometry((ID2D1Geometry*)pathData->GetNativePath(), nativeBrush, penData->GetWidth(), penData->GetStrokeStyle());
4364     }
4365 }
4366 
FillPath(const wxGraphicsPath & p,wxPolygonFillMode fillStyle)4367 void wxD2DContext::FillPath(const wxGraphicsPath& p , wxPolygonFillMode fillStyle)
4368 {
4369     if (m_composition == wxCOMPOSITION_DEST)
4370         return;
4371 
4372     EnsureInitialized();
4373     AdjustRenderTargetSize();
4374 
4375     wxD2DPathData* pathData = wxGetD2DPathData(p);
4376     pathData->SetFillMode(fillStyle == wxODDEVEN_RULE ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING);
4377     pathData->Flush();
4378 
4379     if (!m_brush.IsNull())
4380     {
4381         wxD2DBrushData* brushData = wxGetD2DBrushData(m_brush);
4382         brushData->Bind(this);
4383         GetRenderTarget()->FillGeometry((ID2D1Geometry*)pathData->GetNativePath(), brushData->GetBrush());
4384     }
4385 }
4386 
SetAntialiasMode(wxAntialiasMode antialias)4387 bool wxD2DContext::SetAntialiasMode(wxAntialiasMode antialias)
4388 {
4389     if (m_antialias == antialias)
4390     {
4391         return true;
4392     }
4393 
4394     D2D1_ANTIALIAS_MODE antialiasMode;
4395     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode;
4396     switch ( antialias )
4397     {
4398     case wxANTIALIAS_DEFAULT:
4399         antialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE;
4400         textAntialiasMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
4401         break;
4402 
4403     case wxANTIALIAS_NONE:
4404         antialiasMode = D2D1_ANTIALIAS_MODE_ALIASED;
4405         textAntialiasMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
4406         break;
4407 
4408     default:
4409         wxFAIL_MSG("Unknown antialias mode");
4410         return false;
4411     }
4412 
4413     GetRenderTarget()->SetAntialiasMode(antialiasMode);
4414     GetRenderTarget()->SetTextAntialiasMode(textAntialiasMode);
4415 
4416     m_antialias = antialias;
4417     return true;
4418 }
4419 
SetInterpolationQuality(wxInterpolationQuality interpolation)4420 bool wxD2DContext::SetInterpolationQuality(wxInterpolationQuality interpolation)
4421 {
4422     // Since different versions of Direct2D have different enumerations for
4423     // interpolation quality, we deffer the conversion to the method which
4424     // does the actual drawing.
4425 
4426     m_interpolation = interpolation;
4427     return true;
4428 }
4429 
SetCompositionMode(wxCompositionMode compositionMode)4430 bool wxD2DContext::SetCompositionMode(wxCompositionMode compositionMode)
4431 {
4432     if (m_composition == compositionMode)
4433         return true;
4434 
4435     if (m_renderTargetHolder->SetCompositionMode(compositionMode))
4436     {
4437         // the composition mode is supported by the render target
4438         m_composition = compositionMode;
4439         return true;
4440     }
4441 
4442     return false;
4443 }
4444 
BeginLayer(wxDouble opacity)4445 void wxD2DContext::BeginLayer(wxDouble opacity)
4446 {
4447     EnsureInitialized();
4448 
4449     wxCOMPtr<ID2D1Layer> layer;
4450     HRESULT hr = GetRenderTarget()->CreateLayer(&layer);
4451     wxCHECK_HRESULT_RET(hr);
4452 
4453     LayerData ld;
4454     ld.type = OTHER_LAYER;
4455     ld.params = D2D1::LayerParameters(D2D1::InfiniteRect(),
4456                         NULL,
4457                         D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
4458                         D2D1::IdentityMatrix(), opacity);
4459     ld.layer = layer;
4460     // We need to store CTM to be able to re-apply
4461     // the layer at the original position later on.
4462     GetRenderTarget()->GetTransform(&ld.transformMatrix);
4463 
4464     GetRenderTarget()->PushLayer(ld.params, layer);
4465 
4466     // Store layer parameters.
4467     m_layers.push(ld);
4468 }
4469 
EndLayer()4470 void wxD2DContext::EndLayer()
4471 {
4472     wxStack<LayerData> layersToRestore;
4473     // Temporarily remove all clipping layers
4474     // above the first standard layer
4475     // and next permanently remove this layer.
4476     while ( !m_layers.empty() )
4477     {
4478         LayerData ld = m_layers.top();
4479         m_layers.pop();
4480 
4481         if ( ld.type == CLIP_LAYER )
4482         {
4483             GetRenderTarget()->PopLayer();
4484             layersToRestore.push(ld);
4485             continue;
4486         }
4487 
4488         // We found a non-clipping layer to remove.
4489         GetRenderTarget()->PopLayer();
4490         ld.layer.reset();
4491         break;
4492     }
4493 
4494     if ( m_layers.empty() )
4495     {
4496         HRESULT hr = GetRenderTarget()->Flush();
4497         wxCHECK_HRESULT_RET(hr);
4498     }
4499 
4500     // Re-apply all stored clipping layers.
4501     // First, save current transformation matrix.
4502     D2D1_MATRIX_3X2_F currTransform;
4503     GetRenderTarget()->GetTransform(&currTransform);
4504     while ( !layersToRestore.empty() )
4505     {
4506         LayerData ld = layersToRestore.top();
4507         layersToRestore.pop();
4508 
4509         if ( ld.type == CLIP_LAYER )
4510         {
4511             // Restore layer at original position.
4512             GetRenderTarget()->SetTransform(&ld.transformMatrix);
4513             GetRenderTarget()->PushLayer(ld.params, ld.layer);
4514         }
4515         else
4516         {
4517             wxFAIL_MSG( wxS("Invalid layer type") );
4518         }
4519         // Store layer parameters.
4520         m_layers.push(ld);
4521     }
4522     // Restore current transformation matrix.
4523     GetRenderTarget()->SetTransform(&currTransform);
4524 }
4525 
Translate(wxDouble dx,wxDouble dy)4526 void wxD2DContext::Translate(wxDouble dx, wxDouble dy)
4527 {
4528     wxGraphicsMatrix translationMatrix = CreateMatrix();
4529     translationMatrix.Translate(dx, dy);
4530     ConcatTransform(translationMatrix);
4531 }
4532 
Scale(wxDouble xScale,wxDouble yScale)4533 void wxD2DContext::Scale(wxDouble xScale, wxDouble yScale)
4534 {
4535     wxGraphicsMatrix scaleMatrix = CreateMatrix();
4536     scaleMatrix.Scale(xScale, yScale);
4537     ConcatTransform(scaleMatrix);
4538 }
4539 
Rotate(wxDouble angle)4540 void wxD2DContext::Rotate(wxDouble angle)
4541 {
4542     wxGraphicsMatrix rotationMatrix = CreateMatrix();
4543     rotationMatrix.Rotate(angle);
4544     ConcatTransform(rotationMatrix);
4545 }
4546 
ConcatTransform(const wxGraphicsMatrix & matrix)4547 void wxD2DContext::ConcatTransform(const wxGraphicsMatrix& matrix)
4548 {
4549     D2D1::Matrix3x2F localMatrix = wxGetD2DMatrixData(GetTransform())->GetMatrix3x2F();
4550     D2D1::Matrix3x2F concatMatrix = wxGetD2DMatrixData(matrix)->GetMatrix3x2F();
4551 
4552     D2D1::Matrix3x2F resultMatrix;
4553     resultMatrix.SetProduct(concatMatrix, localMatrix);
4554 
4555     wxGraphicsMatrix resultTransform;
4556     resultTransform.SetRefData(new wxD2DMatrixData(GetRenderer(), resultMatrix));
4557 
4558     SetTransform(resultTransform);
4559 }
4560 
SetTransform(const wxGraphicsMatrix & matrix)4561 void wxD2DContext::SetTransform(const wxGraphicsMatrix& matrix)
4562 {
4563     EnsureInitialized();
4564 
4565     D2D1::Matrix3x2F m;
4566     m.SetProduct(wxGetD2DMatrixData(matrix)->GetMatrix3x2F(), m_initTransform);
4567     GetRenderTarget()->SetTransform(&m);
4568 
4569     m_isClipBoxValid = false;
4570 }
4571 
GetTransform() const4572 wxGraphicsMatrix wxD2DContext::GetTransform() const
4573 {
4574     D2D1::Matrix3x2F transformMatrix;
4575 
4576     if (GetRenderTarget() != NULL)
4577     {
4578         GetRenderTarget()->GetTransform(&transformMatrix);
4579 
4580         if ( m_initTransform.IsInvertible() )
4581         {
4582             D2D1::Matrix3x2F invMatrix = m_initTransform;
4583             invMatrix.Invert();
4584 
4585             D2D1::Matrix3x2F m;
4586             m.SetProduct(transformMatrix, invMatrix);
4587             transformMatrix = m;
4588         }
4589     }
4590     else
4591     {
4592         transformMatrix = D2D1::Matrix3x2F::Identity();
4593     }
4594 
4595     wxD2DMatrixData* matrixData = new wxD2DMatrixData(GetRenderer(), transformMatrix);
4596 
4597     wxGraphicsMatrix matrix;
4598     matrix.SetRefData(matrixData);
4599 
4600     return matrix;
4601 }
4602 
DrawBitmap(const wxGraphicsBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h)4603 void wxD2DContext::DrawBitmap(const wxGraphicsBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4604 {
4605     if (m_composition == wxCOMPOSITION_DEST)
4606         return;
4607 
4608     wxD2DBitmapData* bitmapData = wxGetD2DBitmapData(bmp);
4609     bitmapData->Bind(this);
4610     wxSize bmpSize = static_cast<wxD2DBitmapData::NativeType*>(bitmapData->GetNativeBitmap())->GetSize();
4611 
4612     m_renderTargetHolder->DrawBitmap(
4613         bitmapData->GetD2DBitmap(),
4614         D2D1::RectF(0, 0, bmpSize.GetWidth(), bmpSize.GetHeight()),
4615         D2D1::RectF(x, y, x + w, y + h),
4616         GetInterpolationQuality(),
4617         GetCompositionMode());
4618 }
4619 
DrawBitmap(const wxBitmap & bmp,wxDouble x,wxDouble y,wxDouble w,wxDouble h)4620 void wxD2DContext::DrawBitmap(const wxBitmap& bmp, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4621 {
4622     wxGraphicsBitmap graphicsBitmap = CreateBitmap(bmp);
4623     DrawBitmap(graphicsBitmap, x, y, w, h);
4624 }
4625 
DrawIcon(const wxIcon & icon,wxDouble x,wxDouble y,wxDouble w,wxDouble h)4626 void wxD2DContext::DrawIcon(const wxIcon& icon, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4627 {
4628     DrawBitmap(wxBitmap(icon), x, y, w, h);
4629 }
4630 
PushState()4631 void wxD2DContext::PushState()
4632 {
4633     EnsureInitialized();
4634 
4635     StateData state;
4636     m_direct2dFactory->CreateDrawingStateBlock(&state.drawingState);
4637     GetRenderTarget()->SaveDrawingState(state.drawingState);
4638     state.layers = m_layers;
4639 
4640     m_stateStack.push(state);
4641 }
4642 
PopState()4643 void wxD2DContext::PopState()
4644 {
4645     wxCHECK_RET(!m_stateStack.empty(), wxS("No state to pop"));
4646 
4647     // Remove all layers from the stack of layers.
4648     while ( !m_layers.empty() )
4649     {
4650         LayerData ld = m_layers.top();
4651         m_layers.pop();
4652 
4653         GetRenderTarget()->PopLayer();
4654         ld.layer.reset();
4655         ld.geometry.reset();
4656     }
4657 
4658     // Retrieve state data.
4659     StateData state;
4660     state = m_stateStack.top();
4661     m_stateStack.pop();
4662 
4663     // Restore all saved layers.
4664     wxStack<LayerData> layersToRestore;
4665     // We have to restore layers on the stack from "bottom" to "top",
4666     // so we have to create a "reverted" stack.
4667     while ( !state.layers.empty() )
4668     {
4669         LayerData ld = state.layers.top();
4670         state.layers.pop();
4671 
4672         layersToRestore.push(ld);
4673     }
4674     // And next set layers from the top of "reverted" stack.
4675     while ( !layersToRestore.empty() )
4676     {
4677         LayerData ld = layersToRestore.top();
4678         layersToRestore.pop();
4679 
4680         // Restore layer at original position.
4681         GetRenderTarget()->SetTransform(&ld.transformMatrix);
4682         GetRenderTarget()->PushLayer(ld.params, ld.layer);
4683 
4684         // Store layer parameters.
4685         m_layers.push(ld);
4686     }
4687 
4688     // Restore drawing state.
4689     GetRenderTarget()->RestoreDrawingState(state.drawingState);
4690 
4691     m_isClipBoxValid = false;
4692 }
4693 
GetTextExtent(const wxString & str,wxDouble * width,wxDouble * height,wxDouble * descent,wxDouble * externalLeading) const4694 void wxD2DContext::GetTextExtent(
4695     const wxString& str,
4696     wxDouble* width,
4697     wxDouble* height,
4698     wxDouble* descent,
4699     wxDouble* externalLeading) const
4700 {
4701     wxCHECK_RET(!m_font.IsNull(),
4702         wxS("wxD2DContext::GetTextExtent - no valid font set"));
4703 
4704     wxD2DMeasuringContext::GetTextExtent(
4705         wxGetD2DFontData(m_font), str, width, height, descent, externalLeading);
4706 }
4707 
GetPartialTextExtents(const wxString & text,wxArrayDouble & widths) const4708 void wxD2DContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths) const
4709 {
4710     wxCHECK_RET(!m_font.IsNull(),
4711         wxS("wxD2DContext::GetPartialTextExtents - no valid font set"));
4712 
4713     wxD2DMeasuringContext::GetPartialTextExtents(
4714         wxGetD2DFontData(m_font), text, widths);
4715 }
4716 
ShouldOffset() const4717 bool wxD2DContext::ShouldOffset() const
4718 {
4719     if (!m_enableOffset || m_pen.IsNull())
4720         return false;
4721 
4722     wxD2DPenData* const penData = wxGetD2DPenData(m_pen);
4723 
4724     // always offset for 1-pixel width
4725     if (penData->IsZeroWidth())
4726         return true;
4727 
4728     // no offset if overall scale is not odd integer
4729     const wxGraphicsMatrix matrix(GetTransform());
4730     double x = GetContentScaleFactor(), y = x;
4731     matrix.TransformDistance(&x, &y);
4732     if (!wxIsSameDouble(fmod(wxMin(fabs(x), fabs(y)), 2.0), 1.0))
4733         return false;
4734 
4735     // offset if pen width is odd integer
4736     return wxIsSameDouble(fmod(double(penData->GetWidth()), 2.0), 1.0);
4737 }
4738 
DoDrawText(const wxString & str,wxDouble x,wxDouble y)4739 void wxD2DContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y)
4740 {
4741     wxCHECK_RET(!m_font.IsNull(),
4742         wxS("wxD2DContext::DrawText - no valid font set"));
4743 
4744     if (m_composition == wxCOMPOSITION_DEST)
4745         return;
4746 
4747     wxD2DFontData* fontData = wxGetD2DFontData(m_font);
4748     fontData->GetBrushData().Bind(this);
4749 
4750     wxCOMPtr<IDWriteTextLayout> textLayout = fontData->CreateTextLayout(str);
4751 
4752     // Render the text
4753     GetRenderTarget()->DrawTextLayout(
4754         D2D1::Point2F(x, y),
4755         textLayout,
4756         fontData->GetBrushData().GetBrush());
4757 }
4758 
EnsureInitialized()4759 void wxD2DContext::EnsureInitialized()
4760 {
4761     if (!m_renderTargetHolder->IsResourceAcquired())
4762     {
4763         m_cachedRenderTarget = m_renderTargetHolder->GetD2DResource();
4764         GetRenderTarget()->GetTransform(&m_initTransform);
4765         GetRenderTarget()->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
4766         GetRenderTarget()->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT);
4767         GetRenderTarget()->BeginDraw();
4768     }
4769     else
4770     {
4771         m_cachedRenderTarget = m_renderTargetHolder->GetD2DResource();
4772     }
4773 }
4774 
SetPen(const wxGraphicsPen & pen)4775 void wxD2DContext::SetPen(const wxGraphicsPen& pen)
4776 {
4777     wxGraphicsContext::SetPen(pen);
4778 
4779     if (!m_pen.IsNull())
4780     {
4781         EnsureInitialized();
4782 
4783         wxD2DPenData* penData = wxGetD2DPenData(pen);
4784         penData->Bind(this);
4785     }
4786 }
4787 
AdjustRenderTargetSize()4788 void wxD2DContext::AdjustRenderTargetSize()
4789 {
4790     m_renderTargetHolder->Resize();
4791 
4792     // Currently GetSize() can only be called when using MSVC because gcc
4793     // doesn't handle returning aggregates by value as done by D2D libraries,
4794     // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64384. Not updating the
4795     // size is not great, but it's better than crashing.
4796 #ifdef __VISUALC__
4797     D2D1_SIZE_F renderTargetSize = m_renderTargetHolder->GetD2DResource()->GetSize();
4798     m_width = renderTargetSize.width;
4799     m_height =  renderTargetSize.height;
4800 #endif // __VISUALC__
4801 }
4802 
ReleaseDeviceDependentResources()4803 void wxD2DContext::ReleaseDeviceDependentResources()
4804 {
4805     ReleaseResources();
4806 }
4807 
DrawRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h)4808 void wxD2DContext::DrawRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4809 {
4810     if (m_composition == wxCOMPOSITION_DEST)
4811         return;
4812 
4813     wxD2DOffsetHelper helper(this);
4814 
4815     EnsureInitialized();
4816     AdjustRenderTargetSize();
4817 
4818     D2D1_RECT_F rect = { (FLOAT)x, (FLOAT)y, (FLOAT)(x + w), (FLOAT)(y + h) };
4819 
4820 
4821     if (!m_brush.IsNull())
4822     {
4823         wxD2DBrushData* brushData = wxGetD2DBrushData(m_brush);
4824         brushData->Bind(this);
4825         GetRenderTarget()->FillRectangle(rect, brushData->GetBrush());
4826     }
4827 
4828     if (!m_pen.IsNull())
4829     {
4830         wxD2DPenData* penData = wxGetD2DPenData(m_pen);
4831         penData->SetWidth(this);
4832         penData->Bind(this);
4833         GetRenderTarget()->DrawRectangle(rect, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
4834     }
4835 }
4836 
DrawRoundedRectangle(wxDouble x,wxDouble y,wxDouble w,wxDouble h,wxDouble radius)4837 void wxD2DContext::DrawRoundedRectangle(wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius)
4838 {
4839     if (m_composition == wxCOMPOSITION_DEST)
4840         return;
4841 
4842     wxD2DOffsetHelper helper(this);
4843 
4844     EnsureInitialized();
4845     AdjustRenderTargetSize();
4846 
4847     D2D1_RECT_F rect = { (FLOAT)x, (FLOAT)y, (FLOAT)(x + w), (FLOAT)(y + h) };
4848 
4849     D2D1_ROUNDED_RECT roundedRect = { rect, (FLOAT)radius, (FLOAT)radius };
4850 
4851     if (!m_brush.IsNull())
4852     {
4853         wxD2DBrushData* brushData = wxGetD2DBrushData(m_brush);
4854         brushData->Bind(this);
4855         GetRenderTarget()->FillRoundedRectangle(roundedRect, brushData->GetBrush());
4856     }
4857 
4858     if (!m_pen.IsNull())
4859     {
4860         wxD2DPenData* penData = wxGetD2DPenData(m_pen);
4861         penData->SetWidth(this);
4862         penData->Bind(this);
4863         GetRenderTarget()->DrawRoundedRectangle(roundedRect, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
4864     }
4865 }
4866 
DrawEllipse(wxDouble x,wxDouble y,wxDouble w,wxDouble h)4867 void wxD2DContext::DrawEllipse(wxDouble x, wxDouble y, wxDouble w, wxDouble h)
4868 {
4869     if (m_composition == wxCOMPOSITION_DEST)
4870         return;
4871 
4872     wxD2DOffsetHelper helper(this);
4873 
4874     EnsureInitialized();
4875     AdjustRenderTargetSize();
4876 
4877     D2D1_ELLIPSE ellipse = {
4878         { (FLOAT)(x + w / 2), (FLOAT)(y + h / 2) }, // center point
4879         (FLOAT)(w / 2),                      // radius x
4880         (FLOAT)(h / 2)                       // radius y
4881     };
4882 
4883     if (!m_brush.IsNull())
4884     {
4885         wxD2DBrushData* brushData = wxGetD2DBrushData(m_brush);
4886         brushData->Bind(this);
4887         GetRenderTarget()->FillEllipse(ellipse, brushData->GetBrush());
4888     }
4889 
4890     if (!m_pen.IsNull())
4891     {
4892         wxD2DPenData* penData = wxGetD2DPenData(m_pen);
4893         penData->SetWidth(this);
4894         penData->Bind(this);
4895         GetRenderTarget()->DrawEllipse(ellipse, penData->GetBrush(), penData->GetWidth(), penData->GetStrokeStyle());
4896     }
4897 }
4898 
Flush()4899 void wxD2DContext::Flush()
4900 {
4901     wxStack<LayerData> layersToRestore;
4902     // Temporarily remove all layers from the stack of layers.
4903     while ( !m_layers.empty() )
4904     {
4905         LayerData ld = m_layers.top();
4906         m_layers.pop();
4907 
4908         GetRenderTarget()->PopLayer();
4909 
4910         // Save layer data.
4911         layersToRestore.push(ld);
4912     }
4913 
4914     HRESULT hr = m_renderTargetHolder->Flush();
4915 
4916     if ( hr == (HRESULT)D2DERR_RECREATE_TARGET )
4917     {
4918         ReleaseDeviceDependentResources();
4919     }
4920     else
4921     {
4922         wxCHECK_HRESULT_RET(hr);
4923     }
4924 
4925     // Re-apply all layers.
4926     // First, save current transformation matrix.
4927     D2D1_MATRIX_3X2_F currTransform;
4928     GetRenderTarget()->GetTransform(&currTransform);
4929     while ( !layersToRestore.empty() )
4930     {
4931         LayerData ld = layersToRestore.top();
4932         layersToRestore.pop();
4933 
4934         // Restore layer at original position.
4935         GetRenderTarget()->SetTransform(&ld.transformMatrix);
4936         GetRenderTarget()->PushLayer(ld.params, ld.layer);
4937 
4938         // Store layer parameters.
4939         m_layers.push(ld);
4940     }
4941     // Restore current transformation matrix.
4942     GetRenderTarget()->SetTransform(&currTransform);
4943 }
4944 
GetDPI(wxDouble * dpiX,wxDouble * dpiY) const4945 void wxD2DContext::GetDPI(wxDouble* dpiX, wxDouble* dpiY) const
4946 {
4947     if ( GetWindow() )
4948     {
4949         const wxSize dpi = GetWindow()->GetDPI();
4950 
4951         if ( dpiX )
4952             *dpiX = dpi.x;
4953         if ( dpiY )
4954             *dpiY = dpi.y;
4955     }
4956     else
4957     {
4958         FLOAT x, y;
4959         GetRenderTarget()->GetDpi(&x, &y);
4960 
4961         if ( dpiX )
4962             *dpiX = x;
4963         if ( dpiY )
4964             *dpiY = y;
4965     }
4966 }
4967 
4968 //-----------------------------------------------------------------------------
4969 // wxD2DRenderer declaration
4970 //-----------------------------------------------------------------------------
4971 
4972 class wxD2DRenderer : public wxGraphicsRenderer
4973 {
4974 public :
4975     wxD2DRenderer();
4976 
4977     virtual ~wxD2DRenderer();
4978 
4979     wxGraphicsContext* CreateContext(const wxWindowDC& dc) wxOVERRIDE;
4980 
4981     wxGraphicsContext* CreateContext(const wxMemoryDC& dc) wxOVERRIDE;
4982 
4983 #if wxUSE_PRINTING_ARCHITECTURE
4984     wxGraphicsContext* CreateContext(const wxPrinterDC& dc) wxOVERRIDE;
4985 #endif
4986 
4987 #if wxUSE_ENH_METAFILE
4988     wxGraphicsContext* CreateContext(const wxEnhMetaFileDC& dc) wxOVERRIDE;
4989 #endif
4990 
4991     wxGraphicsContext* CreateContextFromNativeContext(void* context) wxOVERRIDE;
4992 
4993     wxGraphicsContext* CreateContextFromNativeWindow(void* window) wxOVERRIDE;
4994 
4995     wxGraphicsContext * CreateContextFromNativeHDC(WXHDC dc) wxOVERRIDE;
4996 
4997     wxGraphicsContext* CreateContext(wxWindow* window) wxOVERRIDE;
4998 
4999 #if wxUSE_IMAGE
5000     wxGraphicsContext* CreateContextFromImage(wxImage& image) wxOVERRIDE;
5001 #endif // wxUSE_IMAGE
5002 
5003     wxGraphicsContext* CreateMeasuringContext() wxOVERRIDE;
5004 
5005     wxGraphicsPath CreatePath() wxOVERRIDE;
5006 
5007     wxGraphicsMatrix CreateMatrix(
5008         wxDouble a = 1.0, wxDouble b = 0.0, wxDouble c = 0.0, wxDouble d = 1.0,
5009         wxDouble tx = 0.0, wxDouble ty = 0.0) wxOVERRIDE;
5010 
5011     wxGraphicsPen CreatePen(const wxGraphicsPenInfo& info) wxOVERRIDE;
5012 
5013     wxGraphicsBrush CreateBrush(const wxBrush& brush) wxOVERRIDE;
5014 
5015     wxGraphicsBrush CreateLinearGradientBrush(
5016         wxDouble x1, wxDouble y1,
5017         wxDouble x2, wxDouble y2,
5018         const wxGraphicsGradientStops& stops,
5019         const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE;
5020 
5021     wxGraphicsBrush CreateRadialGradientBrush(
5022         wxDouble startX, wxDouble startY,
5023         wxDouble endX, wxDouble endY,
5024         wxDouble radius,
5025         const wxGraphicsGradientStops& stops,
5026         const wxGraphicsMatrix& matrix = wxNullGraphicsMatrix) wxOVERRIDE;
5027 
5028     // create a native bitmap representation
5029     wxGraphicsBitmap CreateBitmap(const wxBitmap& bitmap) wxOVERRIDE;
5030 
5031 #if wxUSE_IMAGE
5032     wxGraphicsBitmap CreateBitmapFromImage(const wxImage& image) wxOVERRIDE;
5033     wxImage CreateImageFromBitmap(const wxGraphicsBitmap& bmp) wxOVERRIDE;
5034 #endif
5035 
5036     wxGraphicsFont CreateFont(const wxFont& font, const wxColour& col) wxOVERRIDE;
5037 
5038     wxGraphicsFont CreateFont(
5039         double sizeInPixels, const wxString& facename,
5040         int flags = wxFONTFLAG_DEFAULT,
5041         const wxColour& col = *wxBLACK) wxOVERRIDE;
5042 
5043     virtual wxGraphicsFont CreateFontAtDPI(const wxFont& font,
5044                                            const wxRealPoint& dpi,
5045                                            const wxColour& col) wxOVERRIDE;
5046 
5047     // create a graphics bitmap from a native bitmap
5048     wxGraphicsBitmap CreateBitmapFromNativeBitmap(void* bitmap) wxOVERRIDE;
5049 
5050     // create a sub-image from a native image representation
5051     wxGraphicsBitmap CreateSubBitmap(const wxGraphicsBitmap& bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h) wxOVERRIDE;
5052 
5053     wxString GetName() const wxOVERRIDE;
5054     void GetVersion(int* major, int* minor, int* micro) const wxOVERRIDE;
5055 
5056     ID2D1Factory* GetD2DFactory();
5057 
5058 private:
5059     wxCOMPtr<ID2D1Factory> m_direct2dFactory;
5060 
5061 private :
5062     wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxD2DRenderer);
5063 };
5064 
5065 //-----------------------------------------------------------------------------
5066 // wxD2DRenderer implementation
5067 //-----------------------------------------------------------------------------
5068 
5069 wxIMPLEMENT_DYNAMIC_CLASS(wxD2DRenderer,wxGraphicsRenderer);
5070 
5071 static wxD2DRenderer *gs_D2DRenderer = NULL;
5072 
GetDirect2DRenderer()5073 wxGraphicsRenderer* wxGraphicsRenderer::GetDirect2DRenderer()
5074 {
5075     if (!wxDirect2D::Initialize())
5076         return NULL;
5077 
5078     if (!gs_D2DRenderer)
5079     {
5080         gs_D2DRenderer = new wxD2DRenderer();
5081     }
5082 
5083     return gs_D2DRenderer;
5084 }
5085 
wxD2DRenderer()5086 wxD2DRenderer::wxD2DRenderer()
5087     : m_direct2dFactory(wxD2D1Factory())
5088 {
5089     if ( m_direct2dFactory.get() == NULL )
5090     {
5091         wxFAIL_MSG("Could not create Direct2D Factory.");
5092     }
5093 }
5094 
~wxD2DRenderer()5095 wxD2DRenderer::~wxD2DRenderer()
5096 {
5097     m_direct2dFactory.reset();
5098 }
5099 
CreateContext(const wxWindowDC & dc)5100 wxGraphicsContext* wxD2DRenderer::CreateContext(const wxWindowDC& dc)
5101 {
5102     return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc);
5103 }
5104 
CreateContext(const wxMemoryDC & dc)5105 wxGraphicsContext* wxD2DRenderer::CreateContext(const wxMemoryDC& dc)
5106 {
5107     wxBitmap bmp = dc.GetSelectedBitmap();
5108     wxASSERT_MSG( bmp.IsOk(), wxS("Should select a bitmap before creating wxGraphicsContext") );
5109 
5110     return new wxD2DContext(this, m_direct2dFactory, dc.GetHDC(), &dc,
5111                             bmp.HasAlpha() ? D2D1_ALPHA_MODE_PREMULTIPLIED : D2D1_ALPHA_MODE_IGNORE);
5112 }
5113 
5114 #if wxUSE_PRINTING_ARCHITECTURE
CreateContext(const wxPrinterDC & WXUNUSED (dc))5115 wxGraphicsContext* wxD2DRenderer::CreateContext(const wxPrinterDC& WXUNUSED(dc))
5116 {
5117     wxFAIL_MSG("not implemented");
5118     return NULL;
5119 }
5120 #endif
5121 
5122 #if wxUSE_ENH_METAFILE
CreateContext(const wxEnhMetaFileDC & WXUNUSED (dc))5123 wxGraphicsContext* wxD2DRenderer::CreateContext(const wxEnhMetaFileDC& WXUNUSED(dc))
5124 {
5125     wxFAIL_MSG("not implemented");
5126     return NULL;
5127 }
5128 #endif
5129 
CreateContextFromNativeContext(void * nativeContext)5130 wxGraphicsContext* wxD2DRenderer::CreateContextFromNativeContext(void* nativeContext)
5131 {
5132     return new wxD2DContext(this, m_direct2dFactory, nativeContext);
5133 }
5134 
CreateContextFromNativeWindow(void * window)5135 wxGraphicsContext* wxD2DRenderer::CreateContextFromNativeWindow(void* window)
5136 {
5137     return new wxD2DContext(this, m_direct2dFactory, (HWND)window);
5138 }
5139 
CreateContextFromNativeHDC(WXHDC dc)5140 wxGraphicsContext* wxD2DRenderer::CreateContextFromNativeHDC(WXHDC dc)
5141 {
5142     return new wxD2DContext(this, m_direct2dFactory, (HDC)dc);
5143 }
5144 
CreateContext(wxWindow * window)5145 wxGraphicsContext* wxD2DRenderer::CreateContext(wxWindow* window)
5146 {
5147     return new wxD2DContext(this, m_direct2dFactory, (HWND)window->GetHWND(), window);
5148 }
5149 
5150 #if wxUSE_IMAGE
CreateContextFromImage(wxImage & image)5151 wxGraphicsContext* wxD2DRenderer::CreateContextFromImage(wxImage& image)
5152 {
5153     return new wxD2DContext(this, m_direct2dFactory, image);
5154 }
5155 #endif // wxUSE_IMAGE
5156 
CreateMeasuringContext()5157 wxGraphicsContext* wxD2DRenderer::CreateMeasuringContext()
5158 {
5159     return new wxD2DMeasuringContext(this);
5160 }
5161 
CreatePath()5162 wxGraphicsPath wxD2DRenderer::CreatePath()
5163 {
5164     wxGraphicsPath p;
5165     p.SetRefData(new wxD2DPathData(this, m_direct2dFactory));
5166 
5167     return p;
5168 }
5169 
CreateMatrix(wxDouble a,wxDouble b,wxDouble c,wxDouble d,wxDouble tx,wxDouble ty)5170 wxGraphicsMatrix wxD2DRenderer::CreateMatrix(
5171     wxDouble a, wxDouble b, wxDouble c, wxDouble d,
5172     wxDouble tx, wxDouble ty)
5173 {
5174     wxD2DMatrixData* matrixData = new wxD2DMatrixData(this);
5175     matrixData->Set(a, b, c, d, tx, ty);
5176 
5177     wxGraphicsMatrix matrix;
5178     matrix.SetRefData(matrixData);
5179 
5180     return matrix;
5181 }
5182 
CreatePen(const wxGraphicsPenInfo & info)5183 wxGraphicsPen wxD2DRenderer::CreatePen(const wxGraphicsPenInfo& info)
5184 {
5185     if ( info.GetStyle() == wxPENSTYLE_TRANSPARENT )
5186     {
5187         return wxNullGraphicsPen;
5188     }
5189     else
5190     {
5191         wxGraphicsPen p;
5192         wxD2DPenData* penData = new wxD2DPenData(this, m_direct2dFactory, info);
5193         p.SetRefData(penData);
5194         return p;
5195     }
5196 }
5197 
CreateBrush(const wxBrush & brush)5198 wxGraphicsBrush wxD2DRenderer::CreateBrush(const wxBrush& brush)
5199 {
5200     if ( !brush.IsOk() || brush.GetStyle() == wxBRUSHSTYLE_TRANSPARENT )
5201     {
5202         return wxNullGraphicsBrush;
5203     }
5204     else
5205     {
5206         wxGraphicsBrush b;
5207         b.SetRefData(new wxD2DBrushData(this, brush));
5208         return b;
5209     }
5210 }
5211 
CreateLinearGradientBrush(wxDouble x1,wxDouble y1,wxDouble x2,wxDouble y2,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)5212 wxGraphicsBrush wxD2DRenderer::CreateLinearGradientBrush(
5213     wxDouble x1, wxDouble y1,
5214     wxDouble x2, wxDouble y2,
5215     const wxGraphicsGradientStops& stops,
5216     const wxGraphicsMatrix& matrix)
5217 {
5218     wxD2DBrushData* brushData = new wxD2DBrushData(this);
5219     brushData->CreateLinearGradientBrush(x1, y1, x2, y2, stops, matrix);
5220 
5221     wxGraphicsBrush brush;
5222     brush.SetRefData(brushData);
5223 
5224     return brush;
5225 }
5226 
CreateRadialGradientBrush(wxDouble startX,wxDouble startY,wxDouble endX,wxDouble endY,wxDouble radius,const wxGraphicsGradientStops & stops,const wxGraphicsMatrix & matrix)5227 wxGraphicsBrush wxD2DRenderer::CreateRadialGradientBrush(
5228     wxDouble startX, wxDouble startY,
5229     wxDouble endX, wxDouble endY,
5230     wxDouble radius,
5231     const wxGraphicsGradientStops& stops,
5232     const wxGraphicsMatrix& matrix)
5233 {
5234     wxD2DBrushData* brushData = new wxD2DBrushData(this);
5235     brushData->CreateRadialGradientBrush(startX, startY, endX, endY, radius, stops, matrix);
5236 
5237     wxGraphicsBrush brush;
5238     brush.SetRefData(brushData);
5239 
5240     return brush;
5241 }
5242 
5243 // create a native bitmap representation
CreateBitmap(const wxBitmap & bitmap)5244 wxGraphicsBitmap wxD2DRenderer::CreateBitmap(const wxBitmap& bitmap)
5245 {
5246     wxD2DBitmapData* bitmapData = new wxD2DBitmapData(this, bitmap);
5247 
5248     wxGraphicsBitmap graphicsBitmap;
5249     graphicsBitmap.SetRefData(bitmapData);
5250 
5251     return graphicsBitmap;
5252 }
5253 
5254 // create a graphics bitmap from a native bitmap
CreateBitmapFromNativeBitmap(void * bitmap)5255 wxGraphicsBitmap wxD2DRenderer::CreateBitmapFromNativeBitmap(void* bitmap)
5256 {
5257     wxD2DBitmapData* bitmapData = new wxD2DBitmapData(this, static_cast<wxD2DBitmapResourceHolder*>(bitmap));
5258 
5259     wxGraphicsBitmap graphicsBitmap;
5260     graphicsBitmap.SetRefData(bitmapData);
5261 
5262     return graphicsBitmap;
5263 }
5264 
5265 #if wxUSE_IMAGE
CreateBitmapFromImage(const wxImage & image)5266 wxGraphicsBitmap wxD2DRenderer::CreateBitmapFromImage(const wxImage& image)
5267 {
5268     wxD2DBitmapData* bitmapData = new wxD2DBitmapData(this, image);
5269 
5270     wxGraphicsBitmap graphicsBitmap;
5271     graphicsBitmap.SetRefData(bitmapData);
5272 
5273     return graphicsBitmap;
5274 }
5275 
CreateImageFromBitmap(const wxGraphicsBitmap & bmp)5276 wxImage wxD2DRenderer::CreateImageFromBitmap(const wxGraphicsBitmap& bmp)
5277 {
5278     return static_cast<wxD2DBitmapData::NativeType*>(bmp.GetNativeBitmap())
5279         ->ConvertToImage();
5280 }
5281 #endif
5282 
CreateFont(const wxFont & font,const wxColour & col)5283 wxGraphicsFont wxD2DRenderer::CreateFont(const wxFont& font, const wxColour& col)
5284 {
5285     return CreateFontAtDPI(font, wxRealPoint(), col);
5286 }
5287 
CreateFont(double sizeInPixels,const wxString & facename,int flags,const wxColour & col)5288 wxGraphicsFont wxD2DRenderer::CreateFont(
5289     double sizeInPixels, const wxString& facename,
5290     int flags,
5291     const wxColour& col)
5292 {
5293     // Use the same DPI as wxFont will use in SetPixelSize, so these cancel
5294     // each other out and we are left with the actual pixel size.
5295     ScreenHDC hdc;
5296     wxRealPoint dpi(::GetDeviceCaps(hdc, LOGPIXELSX),
5297                     ::GetDeviceCaps(hdc, LOGPIXELSY));
5298 
5299     return CreateFontAtDPI(
5300         wxFontInfo(wxSize(sizeInPixels, sizeInPixels)).AllFlags(flags).FaceName(facename),
5301         dpi, col);
5302 }
5303 
CreateFontAtDPI(const wxFont & font,const wxRealPoint & dpi,const wxColour & col)5304 wxGraphicsFont wxD2DRenderer::CreateFontAtDPI(const wxFont& font,
5305                                               const wxRealPoint& dpi,
5306                                               const wxColour& col)
5307 {
5308     wxD2DFontData* fontData = new wxD2DFontData(this, font, dpi, col);
5309     if ( !fontData->GetFont() )
5310     {
5311         // Apparently a non-TrueType font is given and hence
5312         // corresponding DirectWrite font couldn't be created.
5313         delete fontData;
5314         return wxNullGraphicsFont;
5315     }
5316 
5317     wxGraphicsFont graphicsFont;
5318     graphicsFont.SetRefData(fontData);
5319 
5320     return graphicsFont;
5321 }
5322 
5323 // create a sub-image from a native image representation
CreateSubBitmap(const wxGraphicsBitmap & bitmap,wxDouble x,wxDouble y,wxDouble w,wxDouble h)5324 wxGraphicsBitmap wxD2DRenderer::CreateSubBitmap(const wxGraphicsBitmap& bitmap, wxDouble x, wxDouble y, wxDouble w, wxDouble h)
5325 {
5326     typedef wxD2DBitmapData::NativeType* NativeBitmap;
5327 
5328     NativeBitmap natBmp = static_cast<NativeBitmap>(bitmap.GetNativeBitmap())->GetSubBitmap(x, y, w, h);
5329     wxGraphicsBitmap bmpRes;
5330     bmpRes.SetRefData(new wxD2DBitmapData(this, natBmp));
5331     return bmpRes;
5332 }
5333 
GetName() const5334 wxString wxD2DRenderer::GetName() const
5335 {
5336     return "direct2d";
5337 }
5338 
GetVersion(int * major,int * minor,int * micro) const5339 void wxD2DRenderer::GetVersion(int* major, int* minor, int* micro) const
5340 {
5341     if (wxDirect2D::HasDirect2DSupport())
5342     {
5343         if (major)
5344             *major = 1;
5345 
5346         if (minor)
5347         {
5348             switch(wxDirect2D::GetDirect2DVersion())
5349             {
5350             case wxDirect2D::wxD2D_VERSION_1_0:
5351                 *minor = 0;
5352                 break;
5353             case wxDirect2D::wxD2D_VERSION_1_1:
5354                 *minor = 1;
5355                 break;
5356             case wxDirect2D::wxD2D_VERSION_NONE:
5357                 // This is not supposed to happen, but we handle this value in
5358                 // the switch to ensure that we'll get warnings if any new
5359                 // values, not handled here, are added to the enum later.
5360                 *minor = -1;
5361                 break;
5362             }
5363         }
5364 
5365         if (micro)
5366             *micro = 0;
5367     }
5368 }
5369 
GetD2DFactory()5370 ID2D1Factory* wxD2DRenderer::GetD2DFactory()
5371 {
5372     return m_direct2dFactory;
5373 }
5374 
wxGetD2DFactory(wxGraphicsRenderer * renderer)5375 ID2D1Factory* wxGetD2DFactory(wxGraphicsRenderer* renderer)
5376 {
5377     return static_cast<wxD2DRenderer*>(renderer)->GetD2DFactory();
5378 }
5379 
5380 // ----------------------------------------------------------------------------
5381 // Module ensuring all global/singleton objects are destroyed on shutdown.
5382 // ----------------------------------------------------------------------------
5383 
5384 class wxDirect2DModule : public wxModule
5385 {
5386 public:
wxDirect2DModule()5387     wxDirect2DModule()
5388     {
5389         // Using Direct2D requires OLE and, importantly, we must ensure our
5390         // OnExit() runs before it is uninitialized.
5391         AddDependency("wxOleInitModule");
5392     }
5393 
OnInit()5394     virtual bool OnInit() wxOVERRIDE
5395     {
5396         return true;
5397     }
5398 
OnExit()5399     virtual void OnExit() wxOVERRIDE
5400     {
5401         if ( gs_WICImagingFactory )
5402         {
5403             gs_WICImagingFactory->Release();
5404             gs_WICImagingFactory = NULL;
5405         }
5406 
5407         if ( gs_IDWriteFactory )
5408         {
5409 #if wxUSE_PRIVATE_FONTS
5410             if ( wxDirect2DFontCollectionLoader::IsInitialized() )
5411             {
5412                 gs_pPrivateFontCollection.reset();
5413                 gs_IDWriteFactory->UnregisterFontCollectionLoader(wxDirect2DFontCollectionLoader::GetLoader());
5414             }
5415 #endif // wxUSE_PRIVATE_FONTS
5416             gs_IDWriteFactory->Release();
5417             gs_IDWriteFactory = NULL;
5418         }
5419 
5420         if ( gs_D2DRenderer )
5421         {
5422             delete gs_D2DRenderer;
5423             gs_D2DRenderer = NULL;
5424         }
5425 
5426         if ( gs_ID2D1Factory )
5427         {
5428             gs_ID2D1Factory->Release();
5429             gs_ID2D1Factory = NULL;
5430         }
5431     }
5432 
5433 private:
5434     wxDECLARE_DYNAMIC_CLASS(wxDirect2DModule);
5435 };
5436 
5437 wxIMPLEMENT_DYNAMIC_CLASS(wxDirect2DModule, wxModule);
5438 
5439 
5440 #endif // wxUSE_GRAPHICS_DIRECT2D
5441