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