/* * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. * * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Author(s): Behdad Esfahbod */ #ifndef HB_DIRECTWRITE_HH #define HB_DIRECTWRITE_HH #include "hb.hh" #include "hb-directwrite.h" #include "hb-mutex.hh" #include "hb-map.hh" /* * DirectWrite font stream helpers */ // Have a look at to NativeFontResourceDWrite.cpp in Mozilla /* Declare object creator for dynamic support of DWRITE */ typedef HRESULT (WINAPI *t_DWriteCreateFactory)( DWRITE_FACTORY_TYPE factoryType, REFIID iid, IUnknown **factory ); class DWriteFontFileLoader : public IDWriteFontFileLoader { private: hb_reference_count_t mRefCount; hb_mutex_t mutex; hb_hashmap_t mFontStreams; uint64_t mNextFontFileKey = 0; public: DWriteFontFileLoader () { mRefCount.init (); } uint64_t RegisterFontFileStream (IDWriteFontFileStream *fontFileStream) { fontFileStream->AddRef (); hb_lock_t lock {mutex}; mFontStreams.set (mNextFontFileKey, fontFileStream); return mNextFontFileKey++; } void UnregisterFontFileStream (uint64_t fontFileKey) { hb_lock_t lock {mutex}; IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey); if (stream) { mFontStreams.del (fontFileKey); stream->Release (); } } // IUnknown interface IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; } IFACEMETHOD_ (ULONG, AddRef) () { return mRefCount.inc () + 1; } IFACEMETHOD_ (ULONG, Release) () { signed refCount = mRefCount.dec () - 1; assert (refCount >= 0); if (refCount) return refCount; delete this; return 0; } // IDWriteFontFileLoader methods virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey (void const* fontFileReferenceKey, uint32_t fontFileReferenceKeySize, OUT IDWriteFontFileStream** fontFileStream) { if (fontFileReferenceKeySize != sizeof (uint64_t)) return E_INVALIDARG; uint64_t fontFileKey = * (uint64_t *) fontFileReferenceKey; IDWriteFontFileStream *stream = mFontStreams.get (fontFileKey); if (!stream) return E_FAIL; stream->AddRef (); *fontFileStream = stream; return S_OK; } virtual ~DWriteFontFileLoader() { for (auto v : mFontStreams.values ()) v->Release (); } }; class DWriteFontFileStream : public IDWriteFontFileStream { private: hb_reference_count_t mRefCount; hb_blob_t *mBlob; uint8_t *mData; unsigned mSize; DWriteFontFileLoader *mLoader; public: uint64_t fontFileKey; public: DWriteFontFileStream (hb_blob_t *blob); // IUnknown interface IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; } IFACEMETHOD_ (ULONG, AddRef) () { return mRefCount.inc () + 1; } IFACEMETHOD_ (ULONG, Release) () { signed refCount = mRefCount.dec () - 1; assert (refCount >= 0); if (refCount) return refCount; delete this; return 0; } // IDWriteFontFileStream methods virtual HRESULT STDMETHODCALLTYPE ReadFileFragment (void const** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize, OUT void** fragmentContext) { // We are required to do bounds checking. if (fileOffset + fragmentSize > mSize) return E_FAIL; // truncate the 64 bit fileOffset to size_t sized index into mData size_t index = static_cast (fileOffset); // We should be alive for the duration of this. *fragmentStart = &mData[index]; *fragmentContext = nullptr; return S_OK; } virtual void STDMETHODCALLTYPE ReleaseFileFragment (void* fragmentContext) {} virtual HRESULT STDMETHODCALLTYPE GetFileSize (OUT UINT64* fileSize) { *fileSize = mSize; return S_OK; } virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; } virtual ~DWriteFontFileStream(); }; struct hb_directwrite_global_t { hb_directwrite_global_t () { HRESULT hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), (IUnknown**) &dwriteFactory); if (unlikely (hr != S_OK)) return; fontFileLoader = new DWriteFontFileLoader (); dwriteFactory->RegisterFontFileLoader (fontFileLoader); success = true; } ~hb_directwrite_global_t () { if (fontFileLoader) fontFileLoader->Release (); if (dwriteFactory) dwriteFactory->Release (); } bool success = false; IDWriteFactory *dwriteFactory; DWriteFontFileLoader *fontFileLoader; }; HB_INTERNAL hb_directwrite_global_t * get_directwrite_global (); HB_INTERNAL IDWriteFontFace * dw_face_create (hb_blob_t *blob, unsigned index); #endif /* HB_DIRECTWRITE_HH */