forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			308 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			308 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "NativeFontResourceDWrite.h"
 | |
| #include "UnscaledFontDWrite.h"
 | |
| 
 | |
| #include <unordered_map>
 | |
| 
 | |
| #include "Logging.h"
 | |
| #include "mozilla/RefPtr.h"
 | |
| #include "mozilla/StaticMutex.h"
 | |
| #include "nsTArray.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace gfx {
 | |
| 
 | |
| static StaticMutex sFontFileStreamsMutex;
 | |
| static uint64_t sNextFontFileKey = 0;
 | |
| static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
 | |
| 
 | |
| class DWriteFontFileLoader : public IDWriteFontFileLoader
 | |
| {
 | |
| public:
 | |
|   DWriteFontFileLoader()
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   // IUnknown interface
 | |
|   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
 | |
|   {
 | |
|     if (iid == __uuidof(IDWriteFontFileLoader)) {
 | |
|       *ppObject = static_cast<IDWriteFontFileLoader*>(this);
 | |
|       return S_OK;
 | |
|     } else if (iid == __uuidof(IUnknown)) {
 | |
|       *ppObject = static_cast<IUnknown*>(this);
 | |
|       return S_OK;
 | |
|     } else {
 | |
|       return E_NOINTERFACE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IFACEMETHOD_(ULONG, AddRef)()
 | |
|   {
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   IFACEMETHOD_(ULONG, Release)()
 | |
|   {
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   // IDWriteFontFileLoader methods
 | |
|   /**
 | |
|     * Important! Note the key here has to be a uint64_t that will have been
 | |
|     * generated by incrementing sNextFontFileKey.
 | |
|     */
 | |
|   virtual HRESULT STDMETHODCALLTYPE
 | |
|     CreateStreamFromKey(void const* fontFileReferenceKey,
 | |
|                         UINT32 fontFileReferenceKeySize,
 | |
|                         OUT IDWriteFontFileStream** fontFileStream);
 | |
| 
 | |
|   /**
 | |
|     * Gets the singleton loader instance. Note that when using this font
 | |
|     * loader, the key must be a uint64_t that has been generated by incrementing
 | |
|     * sNextFontFileKey.
 | |
|     * Also note that this is _not_ threadsafe.
 | |
|     */
 | |
|   static IDWriteFontFileLoader* Instance()
 | |
|   {
 | |
|     if (!mInstance) {
 | |
|       mInstance = new DWriteFontFileLoader();
 | |
|       Factory::GetDWriteFactory()->
 | |
|           RegisterFontFileLoader(mInstance);
 | |
|     }
 | |
|     return mInstance;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   static IDWriteFontFileLoader* mInstance;
 | |
| };
 | |
| 
 | |
| class DWriteFontFileStream final : public IDWriteFontFileStream
 | |
| {
 | |
| public:
 | |
|   explicit DWriteFontFileStream(uint64_t aFontFileKey);
 | |
| 
 | |
|   /**
 | |
|     * Used by the FontFileLoader to create a new font stream,
 | |
|     * this font stream is created from data in memory. The memory
 | |
|     * passed may be released after object creation, it will be
 | |
|     * copied internally.
 | |
|     *
 | |
|     * @param aData Font data
 | |
|     */
 | |
|   bool Initialize(uint8_t *aData, uint32_t aSize);
 | |
| 
 | |
|   // IUnknown interface
 | |
|   IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
 | |
|   {
 | |
|     if (iid == __uuidof(IDWriteFontFileStream)) {
 | |
|       *ppObject = static_cast<IDWriteFontFileStream*>(this);
 | |
|       return S_OK;
 | |
|     } else if (iid == __uuidof(IUnknown)) {
 | |
|       *ppObject = static_cast<IUnknown*>(this);
 | |
|       return S_OK;
 | |
|     } else {
 | |
|       return E_NOINTERFACE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IFACEMETHOD_(ULONG, AddRef)()
 | |
|   {
 | |
|     return ++mRefCnt;
 | |
|   }
 | |
| 
 | |
|   IFACEMETHOD_(ULONG, Release)()
 | |
|   {
 | |
|     uint32_t count = --mRefCnt;
 | |
|     if (count == 0) {
 | |
|       delete this;
 | |
|     }
 | |
|     return count;
 | |
|   }
 | |
| 
 | |
|   // IDWriteFontFileStream methods
 | |
|   virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
 | |
|                                                      UINT64 fileOffset,
 | |
|                                                      UINT64 fragmentSize,
 | |
|                                                      OUT void** fragmentContext);
 | |
| 
 | |
|   virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
 | |
| 
 | |
|   virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
 | |
| 
 | |
|   virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
 | |
| 
 | |
| private:
 | |
|   nsTArray<uint8_t> mData;
 | |
|   Atomic<uint32_t> mRefCnt;
 | |
|   uint64_t mFontFileKey;
 | |
| 
 | |
|   ~DWriteFontFileStream();
 | |
| };
 | |
| 
 | |
| IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
 | |
| 
 | |
| HRESULT STDMETHODCALLTYPE
 | |
| DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey,
 | |
|                                           UINT32 fontFileReferenceKeySize,
 | |
|                                           IDWriteFontFileStream **fontFileStream)
 | |
| {
 | |
|   if (!fontFileReferenceKey || !fontFileStream) {
 | |
|     return E_POINTER;
 | |
|   }
 | |
| 
 | |
|   StaticMutexAutoLock lock(sFontFileStreamsMutex);
 | |
|   uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
 | |
|   auto found = sFontFileStreams.find(fontFileKey);
 | |
|   if (found == sFontFileStreams.end()) {
 | |
|     *fontFileStream = nullptr;
 | |
|     return E_FAIL;
 | |
|   }
 | |
| 
 | |
|   found->second->AddRef();
 | |
|   *fontFileStream = found->second;
 | |
|   return S_OK;
 | |
| }
 | |
| 
 | |
| DWriteFontFileStream::DWriteFontFileStream(uint64_t aFontFileKey)
 | |
|   : mRefCnt(0)
 | |
|   , mFontFileKey(aFontFileKey)
 | |
| {
 | |
| }
 | |
| 
 | |
| DWriteFontFileStream::~DWriteFontFileStream()
 | |
| {
 | |
|   StaticMutexAutoLock lock(sFontFileStreamsMutex);
 | |
|   sFontFileStreams.erase(mFontFileKey);
 | |
| }
 | |
| 
 | |
| bool
 | |
| DWriteFontFileStream::Initialize(uint8_t *aData, uint32_t aSize)
 | |
| {
 | |
|   if (!mData.SetLength(aSize, fallible)) {
 | |
|     return false;
 | |
|   }
 | |
|   memcpy(mData.Elements(), aData, aSize);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| HRESULT STDMETHODCALLTYPE
 | |
| DWriteFontFileStream::GetFileSize(UINT64 *fileSize)
 | |
| {
 | |
|   *fileSize = mData.Length();
 | |
|   return S_OK;
 | |
| }
 | |
| 
 | |
| HRESULT STDMETHODCALLTYPE
 | |
| DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
 | |
| {
 | |
|   return E_NOTIMPL;
 | |
| }
 | |
| 
 | |
| HRESULT STDMETHODCALLTYPE
 | |
| DWriteFontFileStream::ReadFileFragment(const void **fragmentStart,
 | |
|                                        UINT64 fileOffset,
 | |
|                                        UINT64 fragmentSize,
 | |
|                                        void **fragmentContext)
 | |
| {
 | |
|   // We are required to do bounds checking.
 | |
|   if (fileOffset + fragmentSize > mData.Length()) {
 | |
|     return E_FAIL;
 | |
|   }
 | |
| 
 | |
|   // truncate the 64 bit fileOffset to size_t sized index into mData
 | |
|   size_t index = static_cast<size_t>(fileOffset);
 | |
| 
 | |
|   // We should be alive for the duration of this.
 | |
|   *fragmentStart = &mData[index];
 | |
|   *fragmentContext = nullptr;
 | |
|   return S_OK;
 | |
| }
 | |
| 
 | |
| void STDMETHODCALLTYPE
 | |
| DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext)
 | |
| {
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| already_AddRefed<NativeFontResourceDWrite>
 | |
| NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
 | |
|                                  bool aNeedsCairo)
 | |
| {
 | |
|   RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
 | |
|   if (!factory) {
 | |
|     gfxWarning() << "Failed to get DWrite Factory.";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   sFontFileStreamsMutex.Lock();
 | |
|   uint64_t fontFileKey = sNextFontFileKey++;
 | |
|   RefPtr<DWriteFontFileStream> ffsRef = new DWriteFontFileStream(fontFileKey);
 | |
|   if (!ffsRef->Initialize(aFontData, aDataLength)) {
 | |
|     sFontFileStreamsMutex.Unlock();
 | |
|     gfxWarning() << "Failed to create DWriteFontFileStream.";
 | |
|     return nullptr;
 | |
|   }
 | |
|   sFontFileStreams[fontFileKey] = ffsRef;
 | |
|   sFontFileStreamsMutex.Unlock();
 | |
| 
 | |
|   RefPtr<IDWriteFontFile> fontFile;
 | |
|   HRESULT hr =
 | |
|     factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey),
 | |
|                                            DWriteFontFileLoader::Instance(),
 | |
|                                            getter_AddRefs(fontFile));
 | |
|   if (FAILED(hr)) {
 | |
|     gfxWarning() << "Failed to load font file from data!";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   BOOL isSupported;
 | |
|   DWRITE_FONT_FILE_TYPE fileType;
 | |
|   DWRITE_FONT_FACE_TYPE faceType;
 | |
|   UINT32 numberOfFaces;
 | |
|   hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces);
 | |
|   if (FAILED(hr) || !isSupported) {
 | |
|     gfxWarning() << "Font file is not supported.";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   RefPtr<NativeFontResourceDWrite> fontResource =
 | |
|     new NativeFontResourceDWrite(factory, fontFile.forget(), faceType,
 | |
|                                  numberOfFaces, aNeedsCairo);
 | |
|   return fontResource.forget();
 | |
| }
 | |
| 
 | |
| already_AddRefed<UnscaledFont>
 | |
| NativeFontResourceDWrite::CreateUnscaledFont(uint32_t aIndex,
 | |
|                                              const uint8_t* aInstanceData,
 | |
|                                              uint32_t aInstanceDataLength)
 | |
| {
 | |
|   if (aIndex >= mNumberOfFaces) {
 | |
|     gfxWarning() << "Font face index is too high for font resource.";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   IDWriteFontFile *fontFile = mFontFile;
 | |
|   RefPtr<IDWriteFontFace> fontFace;
 | |
|   if (FAILED(mFactory->CreateFontFace(mFaceType, 1, &fontFile, aIndex,
 | |
|     DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(fontFace)))) {
 | |
|     gfxWarning() << "Failed to create font face from font file data.";
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   RefPtr<UnscaledFont> unscaledFont =
 | |
|     new UnscaledFontDWrite(fontFace,
 | |
|                            nullptr,
 | |
|                            DWRITE_FONT_SIMULATIONS_NONE,
 | |
|                            mNeedsCairo);
 | |
| 
 | |
|   return unscaledFont.forget();
 | |
| }
 | |
| 
 | |
| } // gfx
 | |
| } // mozilla
 | 
