tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NativeFontResourceDWrite.cpp (8398B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "NativeFontResourceDWrite.h"
      8 #include "UnscaledFontDWrite.h"
      9 
     10 #include <unordered_map>
     11 
     12 #include "Logging.h"
     13 #include "mozilla/RefPtr.h"
     14 #include "mozilla/StaticMutex.h"
     15 #include "nsTArray.h"
     16 
     17 namespace mozilla {
     18 namespace gfx {
     19 
     20 static StaticMutex sFontFileStreamsMutex MOZ_UNANNOTATED;
     21 static uint64_t sNextFontFileKey = 0;
     22 MOZ_RUNINIT static std::unordered_map<uint64_t, IDWriteFontFileStream*>
     23    sFontFileStreams;
     24 
     25 class DWriteFontFileLoader : public IDWriteFontFileLoader {
     26 public:
     27  DWriteFontFileLoader() {}
     28 
     29  // IUnknown interface
     30  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) {
     31    if (iid == __uuidof(IDWriteFontFileLoader)) {
     32      *ppObject = static_cast<IDWriteFontFileLoader*>(this);
     33      return S_OK;
     34    } else if (iid == __uuidof(IUnknown)) {
     35      *ppObject = static_cast<IUnknown*>(this);
     36      return S_OK;
     37    } else {
     38      return E_NOINTERFACE;
     39    }
     40  }
     41 
     42  IFACEMETHOD_(ULONG, AddRef)() { return 1; }
     43 
     44  IFACEMETHOD_(ULONG, Release)() { return 1; }
     45 
     46  // IDWriteFontFileLoader methods
     47  /**
     48   * Important! Note the key here has to be a uint64_t that will have been
     49   * generated by incrementing sNextFontFileKey.
     50   */
     51  virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(
     52      void const* fontFileReferenceKey, UINT32 fontFileReferenceKeySize,
     53      OUT IDWriteFontFileStream** fontFileStream);
     54 
     55  /**
     56   * Gets the singleton loader instance. Note that when using this font
     57   * loader, the key must be a uint64_t that has been generated by incrementing
     58   * sNextFontFileKey.
     59   * Also note that this is _not_ threadsafe.
     60   */
     61  static IDWriteFontFileLoader* Instance() {
     62    if (!mInstance) {
     63      mInstance = new DWriteFontFileLoader();
     64      Factory::GetDWriteFactory()->RegisterFontFileLoader(mInstance);
     65    }
     66    return mInstance;
     67  }
     68 
     69 private:
     70  static IDWriteFontFileLoader* mInstance;
     71 };
     72 
     73 class DWriteFontFileStream final : public IDWriteFontFileStream {
     74 public:
     75  explicit DWriteFontFileStream(uint64_t aFontFileKey);
     76 
     77  /**
     78   * Used by the FontFileLoader to create a new font stream,
     79   * this font stream is created from data in memory. The memory
     80   * passed may be released after object creation, it will be
     81   * copied internally.
     82   *
     83   * @param aData Font data
     84   */
     85  bool Initialize(const uint8_t* aData, uint32_t aSize);
     86 
     87  // IUnknown interface
     88  IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) {
     89    if (iid == __uuidof(IDWriteFontFileStream)) {
     90      *ppObject = static_cast<IDWriteFontFileStream*>(this);
     91      return S_OK;
     92    } else if (iid == __uuidof(IUnknown)) {
     93      *ppObject = static_cast<IUnknown*>(this);
     94      return S_OK;
     95    } else {
     96      return E_NOINTERFACE;
     97    }
     98  }
     99 
    100  IFACEMETHOD_(ULONG, AddRef)() { return ++mRefCnt; }
    101 
    102  IFACEMETHOD_(ULONG, Release)() {
    103    uint32_t count = --mRefCnt;
    104    if (count == 0) {
    105      // Avoid locking unless necessary. Verify the refcount hasn't changed
    106      // while locked. Delete within the scope of the lock when zero.
    107      StaticMutexAutoLock lock(sFontFileStreamsMutex);
    108      if (0 != mRefCnt) {
    109        return mRefCnt;
    110      }
    111      delete this;
    112    }
    113    return count;
    114  }
    115 
    116  // IDWriteFontFileStream methods
    117  virtual HRESULT STDMETHODCALLTYPE
    118  ReadFileFragment(void const** fragmentStart, UINT64 fileOffset,
    119                   UINT64 fragmentSize, OUT void** fragmentContext);
    120 
    121  virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext);
    122 
    123  virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize);
    124 
    125  virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime);
    126 
    127 private:
    128  nsTArray<uint8_t> mData;
    129  Atomic<uint32_t> mRefCnt;
    130  uint64_t mFontFileKey;
    131 
    132  ~DWriteFontFileStream();
    133 };
    134 
    135 IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr;
    136 
    137 HRESULT STDMETHODCALLTYPE DWriteFontFileLoader::CreateStreamFromKey(
    138    const void* fontFileReferenceKey, UINT32 fontFileReferenceKeySize,
    139    IDWriteFontFileStream** fontFileStream) {
    140  if (!fontFileReferenceKey || !fontFileStream) {
    141    return E_POINTER;
    142  }
    143 
    144  StaticMutexAutoLock lock(sFontFileStreamsMutex);
    145  uint64_t fontFileKey = *static_cast<const uint64_t*>(fontFileReferenceKey);
    146  auto found = sFontFileStreams.find(fontFileKey);
    147  if (found == sFontFileStreams.end()) {
    148    *fontFileStream = nullptr;
    149    return E_FAIL;
    150  }
    151 
    152  found->second->AddRef();
    153  *fontFileStream = found->second;
    154  return S_OK;
    155 }
    156 
    157 DWriteFontFileStream::DWriteFontFileStream(uint64_t aFontFileKey)
    158    : mRefCnt(0), mFontFileKey(aFontFileKey) {}
    159 
    160 DWriteFontFileStream::~DWriteFontFileStream() {
    161  sFontFileStreams.erase(mFontFileKey);
    162 }
    163 
    164 bool DWriteFontFileStream::Initialize(const uint8_t* aData, uint32_t aSize) {
    165  if (!mData.SetLength(aSize, fallible)) {
    166    return false;
    167  }
    168  memcpy(mData.Elements(), aData, aSize);
    169  return true;
    170 }
    171 
    172 HRESULT STDMETHODCALLTYPE DWriteFontFileStream::GetFileSize(UINT64* fileSize) {
    173  *fileSize = mData.Length();
    174  return S_OK;
    175 }
    176 
    177 HRESULT STDMETHODCALLTYPE
    178 DWriteFontFileStream::GetLastWriteTime(UINT64* lastWriteTime) {
    179  return E_NOTIMPL;
    180 }
    181 
    182 HRESULT STDMETHODCALLTYPE DWriteFontFileStream::ReadFileFragment(
    183    const void** fragmentStart, UINT64 fileOffset, UINT64 fragmentSize,
    184    void** fragmentContext) {
    185  // We are required to do bounds checking.
    186  if (fileOffset + fragmentSize > mData.Length()) {
    187    return E_FAIL;
    188  }
    189 
    190  // truncate the 64 bit fileOffset to size_t sized index into mData
    191  size_t index = static_cast<size_t>(fileOffset);
    192 
    193  // We should be alive for the duration of this.
    194  *fragmentStart = &mData[index];
    195  *fragmentContext = nullptr;
    196  return S_OK;
    197 }
    198 
    199 void STDMETHODCALLTYPE
    200 DWriteFontFileStream::ReleaseFileFragment(void* fragmentContext) {}
    201 
    202 /* static */
    203 already_AddRefed<NativeFontResourceDWrite> NativeFontResourceDWrite::Create(
    204    const uint8_t* aFontData, uint32_t aDataLength) {
    205  RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
    206  if (!factory) {
    207    gfxWarning() << "Failed to get DWrite Factory.";
    208    return nullptr;
    209  }
    210 
    211  sFontFileStreamsMutex.Lock();
    212  uint64_t fontFileKey = sNextFontFileKey++;
    213  RefPtr<DWriteFontFileStream> ffsRef = new DWriteFontFileStream(fontFileKey);
    214  if (!ffsRef->Initialize(aFontData, aDataLength)) {
    215    sFontFileStreamsMutex.Unlock();
    216    gfxWarning() << "Failed to create DWriteFontFileStream.";
    217    return nullptr;
    218  }
    219  sFontFileStreams[fontFileKey] = ffsRef;
    220  sFontFileStreamsMutex.Unlock();
    221 
    222  RefPtr<IDWriteFontFile> fontFile;
    223  HRESULT hr = factory->CreateCustomFontFileReference(
    224      &fontFileKey, sizeof(fontFileKey), DWriteFontFileLoader::Instance(),
    225      getter_AddRefs(fontFile));
    226  if (FAILED(hr)) {
    227    gfxWarning() << "Failed to load font file from data!";
    228    return nullptr;
    229  }
    230 
    231  BOOL isSupported;
    232  DWRITE_FONT_FILE_TYPE fileType;
    233  DWRITE_FONT_FACE_TYPE faceType;
    234  UINT32 numberOfFaces;
    235  hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces);
    236  if (FAILED(hr) || !isSupported) {
    237    gfxWarning() << "Font file is not supported.";
    238    return nullptr;
    239  }
    240 
    241  RefPtr<NativeFontResourceDWrite> fontResource =
    242      new NativeFontResourceDWrite(factory, fontFile.forget(), ffsRef.forget(),
    243                                   faceType, numberOfFaces, aDataLength);
    244  return fontResource.forget();
    245 }
    246 
    247 already_AddRefed<UnscaledFont> NativeFontResourceDWrite::CreateUnscaledFont(
    248    uint32_t aIndex, const uint8_t* aInstanceData,
    249    uint32_t aInstanceDataLength) {
    250  if (aIndex >= mNumberOfFaces) {
    251    gfxWarning() << "Font face index is too high for font resource.";
    252    return nullptr;
    253  }
    254 
    255  IDWriteFontFile* fontFile = mFontFile;
    256  RefPtr<IDWriteFontFace> fontFace;
    257  if (FAILED(mFactory->CreateFontFace(mFaceType, 1, &fontFile, aIndex,
    258                                      DWRITE_FONT_SIMULATIONS_NONE,
    259                                      getter_AddRefs(fontFace)))) {
    260    gfxWarning() << "Failed to create font face from font file data.";
    261    return nullptr;
    262  }
    263 
    264  RefPtr<UnscaledFont> unscaledFont = new UnscaledFontDWrite(fontFace, nullptr);
    265 
    266  return unscaledFont.forget();
    267 }
    268 
    269 }  // namespace gfx
    270 }  // namespace mozilla