iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IGraphicsPrivate.h
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
18#include <codecvt>
19#include <string>
20#include <memory>
21
22#include "mutex.h"
23#include "wdlstring.h"
24#include "wdlendian.h"
25#include "ptrlist.h"
26#include "heapbuf.h"
27
28#if defined IGRAPHICS_SKIA && !defined IGRAPHICS_NO_SKIA_SVG
29#define SVG_USE_SKIA
30#endif
31
32#ifdef SVG_USE_SKIA
33 #pragma warning( push )
34 #pragma warning( disable : 4244 )
35 #pragma warning( disable : 5030 )
36 #include "modules/svg/include/SkSVGDOM.h"
37 #include "include/core/SkCanvas.h"
38 #include "include/core/SkStream.h"
39 #include "src/xml/SkDOM.h"
40 #pragma warning( pop )
41 #pragma comment(lib, "svg.lib")
42 #pragma comment(lib, "skshaper.lib")
43 #pragma comment(lib, "skunicode_core.lib")
44 #pragma comment(lib, "skunicode_icu.lib")
45#else
46 #include "nanosvg.h"
47#endif
48
49#include "IPlugPlatform.h"
50
51#if defined IGRAPHICS_NANOVG
52 #define BITMAP_DATA_TYPE int;
53#elif defined IGRAPHICS_SKIA
54 #pragma warning( push )
55 #pragma warning( disable : 4244 )
56 #include "include/core/SkImage.h"
57 #include "include/core/SkSurface.h"
58 #pragma warning( pop )
59 struct SkiaDrawable
60 {
61 bool mIsSurface;
62 sk_sp<SkImage> mImage;
63 sk_sp<SkSurface> mSurface;
64 };
65 #define BITMAP_DATA_TYPE SkiaDrawable*
66#elif defined IGRAPHICS_CANVAS
67 #include <emscripten.h>
68 #include <emscripten/val.h>
69 #define BITMAP_DATA_TYPE emscripten::val*
70#else // NO_IGRAPHICS
71 #define BITMAP_DATA_TYPE void*;
72#endif
73
74#if defined OS_MAC || defined OS_IOS
75 #include <CoreText/CoreText.h>
76 #define FONT_DESCRIPTOR_TYPE CTFontDescriptorRef
77#elif defined OS_WIN
78 #include "wingdi.h"
79 #define FONT_DESCRIPTOR_TYPE HFONT
80#elif defined OS_WEB
81 #define FONT_DESCRIPTOR_TYPE std::pair<WDL_String, WDL_String>*
82#else
83 // NO_IGRAPHICS
84#endif
85
86BEGIN_IPLUG_NAMESPACE
87BEGIN_IGRAPHICS_NAMESPACE
88using BitmapData = BITMAP_DATA_TYPE;
89using FontDescriptor = FONT_DESCRIPTOR_TYPE;
90using RawBitmapData = WDL_TypedBuf<uint8_t>;
91
96{
97public:
98
105 APIBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
106 : mBitmap(pBitmap)
107 , mWidth(w)
108 , mHeight(h)
109 , mScale(scale)
110 , mDrawScale(drawScale)
111 {}
112
113 APIBitmap()
114 : mBitmap(0)
115 , mWidth(0)
116 , mHeight(0)
117 , mScale(0)
118 , mDrawScale(1.f)
119 {}
120
121 virtual ~APIBitmap() {}
122
123 APIBitmap(const APIBitmap&) = delete;
124 APIBitmap& operator=(const APIBitmap&) = delete;
125
132 void SetBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
133 {
134 mBitmap = pBitmap;
135 mWidth = w;
136 mHeight = h;
137 mScale = scale;
138 mDrawScale = drawScale;
139 }
140
142 BitmapData GetBitmap() const { return mBitmap; }
143
145 int GetWidth() const { return mWidth; }
146
148 int GetHeight() const { return mHeight; }
149
151 float GetScale() const { return mScale; }
152
154 float GetDrawScale() const { return mDrawScale; }
155
156private:
157 BitmapData mBitmap; // for most drawing APIs BitmapData is a pointer. For Nanovg it is an integer index
158 int mWidth;
159 int mHeight;
160 float mScale;
161 float mDrawScale;
162};
163
165class IFontInfo
166{
167public:
168 IFontInfo(const void* data, uint32_t dataSize, uint32_t faceIdx)
169 : mData(reinterpret_cast<const unsigned char*>(data))
170 {
171 if (mData)
172 FindFace(faceIdx);
173
174 if (mData)
175 {
176 mHeadLocation = LocateTable("head");
177 mNameLocation = LocateTable("name");
178 mHheaLocation = LocateTable("hhea");
179 mFDscLocation = LocateTable("fdsc");
180
181 if (IsValid())
182 {
183 mUnitsPerEM = GetUInt16(mHeadLocation + 18);
184 mMacStyle = GetUInt16(mHeadLocation + 44);
185 mFamily = SearchFontString(1);
186 mStyle = SearchFontString(2);
187 mAscender = GetSInt16(mHheaLocation + 4);
188 mDescender = GetSInt16(mHheaLocation + 6);
189 mLineGap = GetSInt16(mHheaLocation + 8);
190 }
191 }
192 }
193
194 bool IsValid() const { return mData && mHeadLocation && mNameLocation && mHheaLocation; }
195
196 const WDL_String& GetFamily() const { return mFamily; }
197 const WDL_String& GetStyle() const { return mStyle; }
198
199 bool IsBold() const { return mMacStyle & (1 << 0); }
200 bool IsItalic() const { return mMacStyle & (1 << 1); }
201 bool IsUnderline() const { return mMacStyle & (1 << 2); }
202 bool IsOutline() const { return mMacStyle & (1 << 3); }
203 bool IsShadow() const { return mMacStyle & (1 << 4); }
204 bool IsCondensed() const { return mMacStyle & (1 << 5); }
205 bool IsExpanded() const { return mMacStyle & (1 << 6); }
206
207 double GetHeightEMRatio() const { return mUnitsPerEM / static_cast<double>(mAscender - mDescender); }
208
209 uint16_t GetUnitsPerEM() const { return mUnitsPerEM; }
210 int16_t GetAscender() const { return mAscender; }
211 int16_t GetDescender() const { return mDescender; }
212 int16_t GetLineGap() const { return mLineGap; }
213 int16_t GetLineHeight() const { return (mAscender - mDescender) + mLineGap; }
214
215private:
216
217 enum class EStringID { Mac, Windows };
218
219 bool MatchTag(uint32_t loc, const char* tag)
220 {
221 return mData[loc+0] == tag[0] && mData[loc+1] == tag[1] && mData[loc+2] == tag[2] && mData[loc+3] == tag[3];
222 }
223
224 uint32_t LocateTable(const char *tag)
225 {
226 uint16_t numTables = GetUInt16(4);
227
228 for (uint16_t i = 0; i < numTables; ++i)
229 {
230 uint32_t tableLocation = 12 + (16 * i);
231 if (MatchTag(tableLocation, tag))
232 return GetUInt32(tableLocation + 8);
233 }
234
235 return 0;
236 }
237
238 WDL_String SearchFontString(int nameID)
239 {
240 WDL_String str = GetFontString(nameID, EStringID::Windows);
241
242 if (str.GetLength())
243 return str;
244
245 return GetFontString(nameID, EStringID::Mac);
246 }
247
248 WDL_String GetFontString(int nameID, EStringID stringID)
249 {
250 // Default to windows values
251
252 int platformID = 3;
253 int encodingID = 1;
254 int languageID = 0x409;
255
256 switch (stringID)
257 {
258 case EStringID::Mac:
259 platformID = 1;
260 encodingID = 0;
261 languageID = 0;
262 break;
263
264 case EStringID::Windows:
265 break;
266 }
267
268 for (uint16_t i = 0; i < GetUInt16(mNameLocation + 2); ++i)
269 {
270 uint32_t loc = mNameLocation + 6 + (12 * i);
271
272 if (platformID == GetUInt16(loc + 0) && encodingID == GetUInt16(loc + 2)
273 && languageID == GetUInt16(loc + 4) && nameID == GetUInt16(loc + 6))
274 {
275 uint32_t stringLocation = GetUInt16(mNameLocation + 4) + GetUInt16(loc + 10);
276 uint16_t length = GetUInt16(loc + 8);
277
278 switch (stringID)
279 {
280 case EStringID::Windows:
281 {
282 WDL_TypedBuf<char> utf8;
283 WDL_TypedBuf<char16_t> utf16;
284 utf8.Resize((length * 3) / 2);
285 utf16.Resize(length / sizeof(char16_t));
286
287 for (int j = 0; j < length; j++)
288 utf16.Get()[j] = GetUInt16(mNameLocation + stringLocation + j * 2);
289
290 std::codecvt_utf8_utf16<char16_t> conv;
291 const char16_t *a;
292 char *b;
293 mbstate_t mbs;
294 memset(&mbs, 0, sizeof(mbs));
295 conv.out(mbs, utf16.Get(), utf16.Get() + utf16.GetSize(), a, utf8.Get(), utf8.Get() + utf8.GetSize(), b);
296
297 return WDL_String(utf8.Get(), (int) (b - utf8.Get()));
298 }
299
300 case EStringID::Mac:
301 return WDL_String((const char*)(mData + mNameLocation + stringLocation), length);
302 }
303 }
304 }
305
306 return WDL_String();
307 }
308
309 void FindFace(uint32_t faceIdx)
310 {
311 bool singleFont = IsSingleFont();
312
313 if (singleFont && faceIdx == 0 )
314 return;
315
316 // Check if it's a TTC file
317 if (!singleFont && MatchTag(0, "ttcf"))
318 {
319 // Check version
320 if (GetUInt32(4) == 0x00010000 || GetUInt32(4) == 0x00020000)
321 {
322 if (faceIdx < GetSInt32(8))
323 {
324 mData += GetUInt32(12 + faceIdx * 4);
325 return;
326 }
327 }
328 }
329 mData = nullptr;
330 }
331
332 bool IsSingleFont()
333 {
334 char TTV1[4] = { '1', 0, 0, 0 };
335 char OTV1[4] = { 0, 1, 0, 0 };
336
337 // Check the version number
338 if (MatchTag(0, TTV1)) return true; // TrueType 1
339 if (MatchTag(0, "typ1")) return true; // TrueType with type 1 font -- we don't support this!
340 if (MatchTag(0, "OTTO")) return true; // OpenType with CFF
341 if (MatchTag(0, OTV1)) return true; // OpenType 1.0
342
343 return false;
344 }
345
346#if defined WDL_LITTLE_ENDIAN
347 uint16_t GetUInt16(uint32_t loc) { return (((uint16_t)mData[loc + 0]) << 8) | (uint16_t)mData[loc + 1]; }
348 int16_t GetSInt16(uint32_t loc) { return (((uint16_t)mData[loc + 0]) << 8) | (uint16_t)mData[loc + 1]; }
349 uint32_t GetUInt32(uint32_t loc) { return (((uint32_t)GetUInt16(loc + 0)) << 16) | (uint32_t)GetUInt16(loc + 2); }
350 int32_t GetSInt32(uint32_t loc) { return (((uint32_t)GetUInt16(loc + 0)) << 16) | (uint32_t)GetUInt16(loc + 2); }
351#else
352 uint16_t GetUInt16(uint32_t loc) { return (((uint16_t)mData[loc + 1]) << 8) | (uint16_t)mData[loc + 0]; }
353 int16_t GetSInt16(uint32_t loc) { return (((uint16_t)mData[loc + 1]) << 8) | (uint16_t)mData[loc + 0]; }
354 uint32_t GetUInt32(uint32_t loc) { return (((uint32_t)GetUInt16(loc + 2)) << 16) | (uint32_t)GetUInt16(loc + 0); }
355 int32_t GetSInt32(uint32_t loc) { return (((uint32_t)GetUInt16(loc + 2)) << 16) | (uint32_t)GetUInt16(loc + 0); }
356#endif
357
358private:
359 const unsigned char* mData;
360
361 uint32_t mHeadLocation = 0;
362 uint32_t mNameLocation = 0;
363 uint32_t mHheaLocation = 0;
364 uint32_t mFDscLocation = 0;
365
366 // Font Identifiers
367 WDL_String mFamily;
368 WDL_String mStyle;
369 uint16_t mMacStyle = 0;
370
371 // Metrics
372 uint16_t mUnitsPerEM = 0;
373 int16_t mAscender = 0;
374 int16_t mDescender = 0;
375 int16_t mLineGap = 0;
376};
377
379class IFontData : public IFontInfo, private WDL_TypedBuf<unsigned char>
380{
381public:
382 IFontData() : IFontInfo(nullptr, 0, -1), mFaceIdx(-1) {}
383
384 IFontData(const void* data, int size, int faceIdx) : IFontInfo(data, size, faceIdx), mFaceIdx(faceIdx)
385 {
386 const unsigned char* src = reinterpret_cast<const unsigned char*>(data);
387 unsigned char* dest = ResizeOK(size);
388
389 if (dest)
390 std::copy(src, src + size, dest);
391 }
392
393 IFontData(int size) : IFontInfo(nullptr, 0, -1), mFaceIdx(-1)
394 {
395 Resize(size);
396 }
397
398 void SetFaceIdx(int faceIdx)
399 {
400 mFaceIdx = faceIdx;
401 static_cast<IFontData&>(*this) = IFontData(Get(), GetSize(), mFaceIdx);
402 }
403
404 bool IsValid() const { return GetSize() && mFaceIdx >= 0 && IFontInfo::IsValid(); }
405
406 unsigned char* Get() { return WDL_TypedBuf<unsigned char>::Get(); }
407 int GetSize() const { return WDL_TypedBuf<unsigned char>::GetSize(); }
408 int GetFaceIdx() const { return mFaceIdx; }
409
410private:
411 int mFaceIdx;
412};
413
415using IFontDataPtr = std::unique_ptr<IFontData>;
416
418class PlatformFont
419{
420public:
421 PlatformFont(bool system) : mSystem(system) {}
422 virtual ~PlatformFont() {}
423
424 PlatformFont(const PlatformFont&) = delete;
425 PlatformFont& operator=(const PlatformFont&) = delete;
426
427 virtual FontDescriptor GetDescriptor() { return nullptr; }
428 virtual IFontDataPtr GetFontData() { return IFontDataPtr(new IFontData()); }
429 bool IsSystem() { return mSystem; }
430
431protected:
432 int GetFaceIdx(const void* data, int dataSize, const char* styleName)
433 {
434 for (int idx = 0; ; idx++)
435 {
436 IFontInfo fontInfo(data, dataSize, idx);
437
438 if (!fontInfo.IsValid())
439 return -1;
440
441 const WDL_String& style = fontInfo.GetStyle();
442
443 if (style.GetLength() && (!styleName[0] || !strcmp(style.Get(), styleName)))
444 return idx;
445 }
446 }
447
448 bool mSystem;
449};
450
451using PlatformFontPtr = std::unique_ptr<PlatformFont>;
452
453#ifdef SVG_USE_SKIA
454struct SVGHolder
455{
456 SVGHolder(sk_sp<SkSVGDOM> svgDom)
457 : mSVGDom(svgDom)
458 {
459 }
460
461 ~SVGHolder()
462 {
463 mSVGDom = nullptr;
464 }
465
466 SVGHolder(const SVGHolder&) = delete;
467 SVGHolder& operator=(const SVGHolder&) = delete;
468
469 sk_sp<SkSVGDOM> mSVGDom;
470};
471#else
473struct SVGHolder
474{
475 SVGHolder(NSVGimage* pImage)
476 : mImage(pImage)
477 {
478 }
479
480 ~SVGHolder()
481 {
482 if(mImage)
483 nsvgDelete(mImage);
484
485 mImage = nullptr;
486 }
487
488 SVGHolder(const SVGHolder&) = delete;
489 SVGHolder& operator=(const SVGHolder&) = delete;
490
491 NSVGimage* mImage = nullptr;
492};
493#endif
494
496template <class T>
497class StaticStorage
498{
499public:
501 class Accessor : private WDL_MutexLock
502 {
503 public:
504 Accessor(StaticStorage& storage)
505 : WDL_MutexLock(&storage.mMutex)
506 , mStorage(storage)
507 {}
508
509 T* Find(const char* str, double scale = 1.) { return mStorage.Find(str, scale); }
510 void Add(T* pData, const char* str, double scale = 1.) { return mStorage.Add(pData, str, scale); }
511 void Remove(T* pData) { return mStorage.Remove(pData); }
512 void Clear() { return mStorage.Clear(); }
513 void Retain() { return mStorage.Retain(); }
514 void Release() { return mStorage.Release(); }
515
516 private:
517 StaticStorage& mStorage;
518 };
519
520 StaticStorage() {}
521
522 ~StaticStorage()
523 {
524 Clear();
525 }
526
527 StaticStorage(const StaticStorage&) = delete;
528 StaticStorage& operator=(const StaticStorage&) = delete;
529
530private:
532 struct DataKey
533 {
534 // N.B. - hashID is not guaranteed to be unique
535 size_t hashID;
536 WDL_String name;
537 double scale;
538 std::unique_ptr<T> data;
539 };
540
544 size_t Hash(const char* str)
545 {
546 std::string string(str);
547 return std::hash<std::string>()(string);
548 }
549
554 T* Find(const char* str, double scale = 1.)
555 {
556 WDL_String cacheName(str);
557 cacheName.AppendFormatted((int) strlen(str) + 6, "-%.1fx", scale);
558
559 size_t hashID = Hash(cacheName.Get());
560
561 int i, n = mDatas.GetSize();
562 for (i = 0; i < n; ++i)
563 {
564 DataKey* pKey = mDatas.Get(i);
565
566 // Use the hash id for a quick search and then confirm with the scale and identifier to ensure uniqueness
567 if (pKey->hashID == hashID && scale == pKey->scale && !strcmp(str, pKey->name.Get()))
568 return pKey->data.get();
569 }
570 return nullptr;
571 }
572
577 void Add(T* pData, const char* str, double scale = 1.)
578 {
579 DataKey* pKey = mDatas.Add(new DataKey);
580
581 WDL_String cacheName(str);
582 cacheName.AppendFormatted((int) strlen(str) + 6, "-%.1fx", scale);
583
584 pKey->hashID = Hash(cacheName.Get());
585 pKey->data = std::unique_ptr<T>(pData);
586 pKey->scale = scale;
587 pKey->name.Set(str);
588
589 //DBGMSG("adding %s to the static storage at %.1fx the original scale\n", str, scale);
590 }
591
593 void Remove(T* pData)
594 {
595 for (int i = 0; i < mDatas.GetSize(); ++i)
596 {
597 if (mDatas.Get(i)->data.get() == pData)
598 {
599 mDatas.Delete(i, true);
600 break;
601 }
602 }
603 }
604
606 void Clear()
607 {
608 mDatas.Empty(true);
609 };
610
612 void Retain()
613 {
614 mCount++;
615 }
616
618 void Release()
619 {
620 if (--mCount == 0)
621 Clear();
622 }
623
624 int mCount = 0;
625 WDL_Mutex mMutex;
626 WDL_PtrList<DataKey> mDatas;
627};
628
630struct IVec2
631{
632 float x, y;
633 IVec2() = default;
634 IVec2(float x, float y) : x(x), y(y) {}
635
636 IVec2 operator-(const IVec2 b) { return IVec2{x-b.x, y-b.y}; }
637 IVec2 operator+(const IVec2 b) { return IVec2{x+b.x, y+b.y}; }
638};
639
640END_IGRAPHICS_NAMESPACE
641END_IPLUG_NAMESPACE
642
Include to get consistently named preprocessor macros for different platforms and logging functionali...
A base class interface for a bitmap abstraction around the different drawing back end bitmap represen...
float GetScale() const
APIBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
APIBitmap constructor.
BitmapData GetBitmap() const
void SetBitmap(BitmapData pBitmap, int w, int h, float scale, float drawScale)
Used to initialise the members after construction.
int GetHeight() const
float GetDrawScale() const
int GetWidth() const
Encapsulate an xy point in one struct.