mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			269 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			269 lines
		
	
	
	
		
			8.2 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 MOZ_UNANNOTATED;
 | 
						|
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) {
 | 
						|
      // Avoid locking unless necessary. Verify the refcount hasn't changed
 | 
						|
      // while locked. Delete within the scope of the lock when zero.
 | 
						|
      StaticMutexAutoLock lock(sFontFileStreamsMutex);
 | 
						|
      if (0 != mRefCnt) {
 | 
						|
        return mRefCnt;
 | 
						|
      }
 | 
						|
      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() {
 | 
						|
  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) {
 | 
						|
  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(), ffsRef.forget(),
 | 
						|
                                   faceType, numberOfFaces, aDataLength);
 | 
						|
  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);
 | 
						|
 | 
						|
  return unscaledFont.forget();
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace gfx
 | 
						|
}  // namespace mozilla
 |