tor-browser

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

ScaledFontDWrite.cpp (22125B)


      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 "ScaledFontDWrite.h"
      8 #include "gfxDWriteCommon.h"
      9 #include "UnscaledFontDWrite.h"
     10 #include "gfxFont.h"
     11 #include "Logging.h"
     12 #include "mozilla/FontPropertyTypes.h"
     13 #include "mozilla/webrender/WebRenderTypes.h"
     14 #include "StackArray.h"
     15 
     16 #include "dwrite_3.h"
     17 
     18 #include "PathSkia.h"
     19 #include "skia/include/core/SkPaint.h"
     20 #include "skia/include/core/SkPath.h"
     21 #include "skia/include/ports/SkTypeface_win.h"
     22 
     23 #include <vector>
     24 
     25 #include "cairo-dwrite.h"
     26 
     27 #include "HelpersWinFonts.h"
     28 
     29 namespace mozilla {
     30 namespace gfx {
     31 
     32 #define GASP_TAG 0x70736167
     33 #define GASP_DOGRAY 0x2
     34 
     35 static inline unsigned short readShort(const char* aBuf) {
     36  return (*aBuf << 8) | *(aBuf + 1);
     37 }
     38 
     39 static bool DoGrayscale(IDWriteFontFace* aDWFace, Float ppem) {
     40  void* tableContext;
     41  char* tableData;
     42  UINT32 tableSize;
     43  BOOL exists;
     44  aDWFace->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize,
     45                           &tableContext, &exists);
     46 
     47  if (exists) {
     48    if (tableSize < 4) {
     49      aDWFace->ReleaseFontTable(tableContext);
     50      return true;
     51    }
     52    struct gaspRange {
     53      unsigned short maxPPEM;   // Stored big-endian
     54      unsigned short behavior;  // Stored big-endian
     55    };
     56    unsigned short numRanges = readShort(tableData + 2);
     57    if (tableSize < (UINT)4 + numRanges * 4) {
     58      aDWFace->ReleaseFontTable(tableContext);
     59      return true;
     60    }
     61    gaspRange* ranges = (gaspRange*)(tableData + 4);
     62    for (int i = 0; i < numRanges; i++) {
     63      if (readShort((char*)&ranges[i].maxPPEM) >= ppem) {
     64        if (!(readShort((char*)&ranges[i].behavior) & GASP_DOGRAY)) {
     65          aDWFace->ReleaseFontTable(tableContext);
     66          return false;
     67        }
     68        break;
     69      }
     70    }
     71    aDWFace->ReleaseFontTable(tableContext);
     72  }
     73  return true;
     74 }
     75 
     76 ScaledFontDWrite::ScaledFontDWrite(IDWriteFontFace* aFontFace,
     77                                   const RefPtr<UnscaledFont>& aUnscaledFont,
     78                                   Float aSize, bool aUseEmbeddedBitmap,
     79                                   bool aUseMultistrikeBold, bool aGDIForced,
     80                                   const gfxFontStyle* aStyle)
     81    : ScaledFontBase(aUnscaledFont, aSize),
     82      mFontFace(aFontFace),
     83      mUseEmbeddedBitmap(aUseEmbeddedBitmap),
     84      mUseMultistrikeBold(aUseMultistrikeBold),
     85      mGDIForced(aGDIForced) {
     86  if (aStyle) {
     87    mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
     88                         DWriteFontStretchFromStretch(aStyle->stretch),
     89                         // FIXME(jwatt): also use kOblique_Slant
     90                         aStyle->style == FontSlantStyle::NORMAL
     91                             ? SkFontStyle::kUpright_Slant
     92                             : SkFontStyle::kItalic_Slant);
     93  }
     94 }
     95 
     96 SkTypeface* ScaledFontDWrite::CreateSkTypeface() {
     97  RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
     98  if (!factory) {
     99    return nullptr;
    100  }
    101 
    102  auto& settings = DWriteSettings();
    103  Float gamma = settings.Gamma();
    104  // Skia doesn't support a gamma value outside of 0-4, so default to 2.2
    105  if (gamma < 0.0f || gamma > 4.0f) {
    106    gamma = 2.2f;
    107  }
    108 
    109  Float contrast = settings.EnhancedContrast();
    110  // Skia doesn't support a contrast value outside of 0-1, so default to 1.0
    111  if (contrast < 0.0f || contrast > 1.0f) {
    112    contrast = 1.0f;
    113  }
    114 
    115  Float clearTypeLevel = settings.ClearTypeLevel();
    116  if (clearTypeLevel < 0.0f || clearTypeLevel > 1.0f) {
    117    clearTypeLevel = 1.0f;
    118  }
    119 
    120  IDWriteFont* font =
    121      static_cast<UnscaledFontDWrite*>(mUnscaledFont.get())->GetFont();
    122  RefPtr<IDWriteFontFamily> family;
    123  if (font) {
    124    font->GetFontFamily(getter_AddRefs(family));
    125  }
    126  return SkCreateTypefaceFromDWriteFont(factory, mFontFace, font, family,
    127                                        mStyle, (int)settings.RenderingMode(),
    128                                        gamma, contrast, clearTypeLevel);
    129 }
    130 
    131 void ScaledFontDWrite::SetupSkFontDrawOptions(SkFont& aFont) {
    132  if (ForceGDIMode()) {
    133    aFont.setEmbeddedBitmaps(true);
    134    aFont.setSubpixel(false);
    135  } else {
    136    aFont.setEmbeddedBitmaps(UseEmbeddedBitmaps());
    137    aFont.setSubpixel(true);
    138  }
    139 }
    140 
    141 bool ScaledFontDWrite::MayUseBitmaps() {
    142  return ForceGDIMode() || UseEmbeddedBitmaps();
    143 }
    144 
    145 bool UnscaledFontDWrite::GetFontFileData(FontFileDataOutput aDataCallback,
    146                                         void* aBaton) {
    147  UINT32 fileCount = 0;
    148  HRESULT hr = mFontFace->GetFiles(&fileCount, nullptr);
    149 
    150  if (FAILED(hr) || fileCount > 1) {
    151    MOZ_ASSERT(false);
    152    return false;
    153  }
    154 
    155  if (!aDataCallback) {
    156    return true;
    157  }
    158 
    159  RefPtr<IDWriteFontFile> file;
    160  hr = mFontFace->GetFiles(&fileCount, getter_AddRefs(file));
    161  if (FAILED(hr)) {
    162    return false;
    163  }
    164 
    165  const void* referenceKey;
    166  UINT32 refKeySize;
    167  // XXX - This can currently crash for webfonts, as when we get the reference
    168  // key out of the file, that can be an invalid reference key for the loader
    169  // we use it with. The fix to this is not obvious but it will probably
    170  // have to happen inside thebes.
    171  hr = file->GetReferenceKey(&referenceKey, &refKeySize);
    172  if (FAILED(hr)) {
    173    return false;
    174  }
    175 
    176  RefPtr<IDWriteFontFileLoader> loader;
    177  hr = file->GetLoader(getter_AddRefs(loader));
    178  if (FAILED(hr)) {
    179    return false;
    180  }
    181 
    182  RefPtr<IDWriteFontFileStream> stream;
    183  hr = loader->CreateStreamFromKey(referenceKey, refKeySize,
    184                                   getter_AddRefs(stream));
    185  if (FAILED(hr)) {
    186    return false;
    187  }
    188 
    189  UINT64 fileSize64;
    190  hr = stream->GetFileSize(&fileSize64);
    191  if (FAILED(hr) || fileSize64 > UINT32_MAX) {
    192    MOZ_ASSERT(false);
    193    return false;
    194  }
    195 
    196  // Try to catch any device memory exceptions that may occur while attempting
    197  // to read the file fragment.
    198  void* context = nullptr;
    199  hr = E_FAIL;
    200  MOZ_SEH_TRY {
    201    uint32_t fileSize = static_cast<uint32_t>(fileSize64);
    202    const void* fragmentStart = nullptr;
    203    hr = stream->ReadFileFragment(&fragmentStart, 0, fileSize, &context);
    204    if (SUCCEEDED(hr)) {
    205      aDataCallback((uint8_t*)fragmentStart, fileSize, mFontFace->GetIndex(),
    206                    aBaton);
    207    }
    208  }
    209  MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    210    gfxCriticalNote << "Exception occurred reading DWrite font file data";
    211  }
    212  if (FAILED(hr)) {
    213    return false;
    214  }
    215  stream->ReleaseFileFragment(context);
    216  return true;
    217 }
    218 
    219 static bool GetFontFileName(RefPtr<IDWriteFontFace> aFontFace,
    220                            std::vector<WCHAR>& aFileName) {
    221  UINT32 numFiles;
    222  HRESULT hr = aFontFace->GetFiles(&numFiles, nullptr);
    223  if (FAILED(hr)) {
    224    gfxDebug() << "Failed getting file count for WR font";
    225    return false;
    226  } else if (numFiles != 1) {
    227    gfxDebug() << "Invalid file count " << numFiles << " for WR font";
    228    return false;
    229  }
    230 
    231  RefPtr<IDWriteFontFile> file;
    232  hr = aFontFace->GetFiles(&numFiles, getter_AddRefs(file));
    233  if (FAILED(hr)) {
    234    gfxDebug() << "Failed getting file for WR font";
    235    return false;
    236  }
    237 
    238  const void* key;
    239  UINT32 keySize;
    240  hr = file->GetReferenceKey(&key, &keySize);
    241  if (FAILED(hr)) {
    242    gfxDebug() << "Failed getting file ref key for WR font";
    243    return false;
    244  }
    245  RefPtr<IDWriteFontFileLoader> loader;
    246  hr = file->GetLoader(getter_AddRefs(loader));
    247  if (FAILED(hr)) {
    248    gfxDebug() << "Failed getting file loader for WR font";
    249    return false;
    250  }
    251  RefPtr<IDWriteLocalFontFileLoader> localLoader;
    252  loader->QueryInterface(__uuidof(IDWriteLocalFontFileLoader),
    253                         (void**)getter_AddRefs(localLoader));
    254  if (!localLoader) {
    255    gfxDebug() << "Failed querying loader interface for WR font";
    256    return false;
    257  }
    258  UINT32 pathLen;
    259  hr = localLoader->GetFilePathLengthFromKey(key, keySize, &pathLen);
    260  if (FAILED(hr)) {
    261    gfxDebug() << "Failed getting path length for WR font";
    262    return false;
    263  }
    264  aFileName.resize(pathLen + 1);
    265  hr = localLoader->GetFilePathFromKey(key, keySize, aFileName.data(),
    266                                       pathLen + 1);
    267  if (FAILED(hr) || aFileName.back() != 0) {
    268    gfxDebug() << "Failed getting path for WR font";
    269    return false;
    270  }
    271 
    272  // We leave the null terminator at the end of the returned file name.
    273  return true;
    274 }
    275 
    276 bool UnscaledFontDWrite::GetFontDescriptor(FontDescriptorOutput aCb,
    277                                           void* aBaton) {
    278  MOZ_ASSERT(NS_IsMainThread());
    279 
    280  if (!mFont) {
    281    return false;
    282  }
    283 
    284  // We cache the font file name as it involves multiple DirectWrite calls.
    285  if (mFontFileName.empty()) {
    286    if (!GetFontFileName(mFontFace, mFontFileName)) {
    287      return false;
    288    }
    289  }
    290  uint32_t index = mFontFace->GetIndex();
    291 
    292  aCb(reinterpret_cast<const uint8_t*>(mFontFileName.data()),
    293      mFontFileName.size() * sizeof(WCHAR), index, aBaton);
    294  return true;
    295 }
    296 
    297 ScaledFontDWrite::InstanceData::InstanceData(
    298    const wr::FontInstanceOptions* aOptions,
    299    const wr::FontInstancePlatformOptions* aPlatformOptions) {
    300  if (aOptions) {
    301    if (aOptions->flags & wr::FontInstanceFlags::EMBEDDED_BITMAPS) {
    302      mUseEmbeddedBitmap = true;
    303    }
    304    if (aOptions->flags & wr::FontInstanceFlags::SYNTHETIC_BOLD) {
    305      mUseBoldSimulation = true;
    306    }
    307    if (aOptions->flags & wr::FontInstanceFlags::MULTISTRIKE_BOLD) {
    308      mUseMultistrikeBold = true;
    309    }
    310    if (aOptions->flags & wr::FontInstanceFlags::FORCE_GDI) {
    311      mGDIForced = true;
    312    }
    313  }
    314 }
    315 
    316 bool ScaledFontDWrite::HasVariationSettings() {
    317  RefPtr<IDWriteFontFace5> ff5;
    318  mFontFace->QueryInterface(__uuidof(IDWriteFontFace5),
    319                            (void**)getter_AddRefs(ff5));
    320  if (!ff5 || !ff5->HasVariations()) {
    321    return false;
    322  }
    323 
    324  uint32_t count = ff5->GetFontAxisValueCount();
    325  if (!count) {
    326    return false;
    327  }
    328 
    329  RefPtr<IDWriteFontResource> res;
    330  if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
    331    return false;
    332  }
    333 
    334  std::vector<DWRITE_FONT_AXIS_VALUE> defaults(count);
    335  if (FAILED(res->GetDefaultFontAxisValues(defaults.data(), count))) {
    336    return false;
    337  }
    338 
    339  std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
    340  if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
    341    return false;
    342  }
    343 
    344  for (uint32_t i = 0; i < count; i++) {
    345    DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
    346    if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
    347      if (values[i].value != defaults[i].value) {
    348        return true;
    349      }
    350    }
    351  }
    352 
    353  return false;
    354 }
    355 
    356 // Helper for ScaledFontDWrite::GetFontInstanceData: if the font has variation
    357 // axes, get their current values into the aOutput vector.
    358 static void GetVariationsFromFontFace(IDWriteFontFace* aFace,
    359                                      std::vector<FontVariation>* aOutput) {
    360  RefPtr<IDWriteFontFace5> ff5;
    361  aFace->QueryInterface(__uuidof(IDWriteFontFace5),
    362                        (void**)getter_AddRefs(ff5));
    363  if (!ff5 || !ff5->HasVariations()) {
    364    return;
    365  }
    366 
    367  uint32_t count = ff5->GetFontAxisValueCount();
    368  if (!count) {
    369    return;
    370  }
    371 
    372  RefPtr<IDWriteFontResource> res;
    373  if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
    374    return;
    375  }
    376 
    377  std::vector<DWRITE_FONT_AXIS_VALUE> values(count);
    378  if (FAILED(ff5->GetFontAxisValues(values.data(), count))) {
    379    return;
    380  }
    381 
    382  aOutput->reserve(count);
    383  for (uint32_t i = 0; i < count; i++) {
    384    DWRITE_FONT_AXIS_ATTRIBUTES attr = res->GetFontAxisAttributes(i);
    385    if (attr & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) {
    386      float v = values[i].value;
    387      uint32_t t = TRUETYPE_TAG(
    388          uint8_t(values[i].axisTag), uint8_t(values[i].axisTag >> 8),
    389          uint8_t(values[i].axisTag >> 16), uint8_t(values[i].axisTag >> 24));
    390      aOutput->push_back(FontVariation{uint32_t(t), float(v)});
    391    }
    392  }
    393 }
    394 
    395 bool ScaledFontDWrite::GetFontInstanceData(FontInstanceDataOutput aCb,
    396                                           void* aBaton) {
    397  InstanceData instance(this);
    398 
    399  // If the font has variations, get the list of axis values.
    400  std::vector<FontVariation> variations;
    401  GetVariationsFromFontFace(mFontFace, &variations);
    402 
    403  aCb(reinterpret_cast<uint8_t*>(&instance), sizeof(instance),
    404      variations.data(), variations.size(), aBaton);
    405 
    406  return true;
    407 }
    408 
    409 bool ScaledFontDWrite::GetWRFontInstanceOptions(
    410    Maybe<wr::FontInstanceOptions>* aOutOptions,
    411    Maybe<wr::FontInstancePlatformOptions>* aOutPlatformOptions,
    412    std::vector<FontVariation>* aOutVariations) {
    413  wr::FontInstanceOptions options = {};
    414  options.render_mode = wr::ToFontRenderMode(GetDefaultAAMode());
    415  options.flags = wr::FontInstanceFlags{0};
    416  if (HasBoldSimulation()) {
    417    options.flags |= wr::FontInstanceFlags::SYNTHETIC_BOLD;
    418  }
    419  if (UseMultistrikeBold()) {
    420    options.flags |= wr::FontInstanceFlags::MULTISTRIKE_BOLD;
    421  }
    422  if (UseEmbeddedBitmaps()) {
    423    options.flags |= wr::FontInstanceFlags::EMBEDDED_BITMAPS;
    424  }
    425  if (ForceGDIMode()) {
    426    options.flags |= wr::FontInstanceFlags::FORCE_GDI;
    427  } else {
    428    options.flags |= wr::FontInstanceFlags::SUBPIXEL_POSITION;
    429  }
    430  auto& settings = DWriteSettings();
    431  switch (settings.RenderingMode()) {
    432    case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
    433      options.flags |= wr::FontInstanceFlags::FORCE_SYMMETRIC;
    434      break;
    435    case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
    436      options.flags |= wr::FontInstanceFlags::NO_SYMMETRIC;
    437      break;
    438    default:
    439      break;
    440  }
    441  if (Factory::GetSubpixelOrder() == SubpixelOrder::BGR) {
    442    options.flags |= wr::FontInstanceFlags::SUBPIXEL_BGR;
    443  }
    444  options.synthetic_italics =
    445      wr::DegreesToSyntheticItalics(GetSyntheticObliqueAngle());
    446 
    447  wr::FontInstancePlatformOptions platformOptions;
    448  platformOptions.gamma = uint16_t(std::round(settings.Gamma() * 100.0f));
    449  platformOptions.contrast =
    450      uint8_t(std::round(std::min(settings.EnhancedContrast(), 1.0f) * 100.0f));
    451  platformOptions.cleartype_level =
    452      uint8_t(std::round(std::min(settings.ClearTypeLevel(), 1.0f) * 100.0f));
    453 
    454  *aOutOptions = Some(options);
    455  *aOutPlatformOptions = Some(platformOptions);
    456 
    457  GetVariationsFromFontFace(mFontFace, aOutVariations);
    458 
    459  return true;
    460 }
    461 
    462 DWriteSettings& ScaledFontDWrite::DWriteSettings() const {
    463  return DWriteSettings::Get(mGDIForced);
    464 }
    465 
    466 // Helper for UnscaledFontDWrite::CreateScaledFont: create a clone of the
    467 // given IDWriteFontFace, with specified variation-axis values applied.
    468 // Returns nullptr in case of failure.
    469 static already_AddRefed<IDWriteFontFace5> CreateFaceWithVariations(
    470    IDWriteFontFace* aFace, DWRITE_FONT_SIMULATIONS aSimulations,
    471    const FontVariation* aVariations = nullptr, uint32_t aNumVariations = 0) {
    472  auto makeDWriteAxisTag = [](uint32_t aTag) {
    473    return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff, (aTag >> 16) & 0xff,
    474                                     (aTag >> 8) & 0xff, aTag & 0xff);
    475  };
    476 
    477  MOZ_SEH_TRY {
    478    RefPtr<IDWriteFontFace5> ff5;
    479    aFace->QueryInterface(__uuidof(IDWriteFontFace5),
    480                          (void**)getter_AddRefs(ff5));
    481    if (!ff5) {
    482      return nullptr;
    483    }
    484 
    485    RefPtr<IDWriteFontResource> res;
    486    if (FAILED(ff5->GetFontResource(getter_AddRefs(res)))) {
    487      return nullptr;
    488    }
    489 
    490    std::vector<DWRITE_FONT_AXIS_VALUE> fontAxisValues;
    491    if (aNumVariations) {
    492      fontAxisValues.reserve(aNumVariations);
    493      for (uint32_t i = 0; i < aNumVariations; i++) {
    494        DWRITE_FONT_AXIS_VALUE axisValue = {
    495            makeDWriteAxisTag(aVariations[i].mTag), aVariations[i].mValue};
    496        fontAxisValues.push_back(axisValue);
    497      }
    498    } else {
    499      uint32_t count = ff5->GetFontAxisValueCount();
    500      if (count) {
    501        fontAxisValues.resize(count);
    502        if (FAILED(ff5->GetFontAxisValues(fontAxisValues.data(), count))) {
    503          fontAxisValues.clear();
    504        }
    505      }
    506    }
    507 
    508    RefPtr<IDWriteFontFace5> newFace;
    509    if (FAILED(res->CreateFontFace(aSimulations, fontAxisValues.data(),
    510                                   fontAxisValues.size(),
    511                                   getter_AddRefs(newFace)))) {
    512      return nullptr;
    513    }
    514    return newFace.forget();
    515  }
    516  MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    517    gfxCriticalNote << "Exception occurred initializing variation face";
    518    return nullptr;
    519  }
    520 }
    521 
    522 bool UnscaledFontDWrite::InitBold() {
    523  if (mFontFaceBold) {
    524    return true;
    525  }
    526 
    527  DWRITE_FONT_SIMULATIONS sims = mFontFace->GetSimulations();
    528  if (sims & DWRITE_FONT_SIMULATIONS_BOLD) {
    529    mFontFaceBold = mFontFace;
    530    return true;
    531  }
    532  sims |= DWRITE_FONT_SIMULATIONS_BOLD;
    533 
    534  RefPtr<IDWriteFontFace5> ff5 = CreateFaceWithVariations(mFontFace, sims);
    535  if (ff5) {
    536    mFontFaceBold = ff5;
    537  } else {
    538    MOZ_SEH_TRY {
    539      UINT32 numFiles = 0;
    540      if (FAILED(mFontFace->GetFiles(&numFiles, nullptr))) {
    541        return false;
    542      }
    543      StackArray<IDWriteFontFile*, 1> files(numFiles);
    544      if (FAILED(mFontFace->GetFiles(&numFiles, files.data()))) {
    545        return false;
    546      }
    547      HRESULT hr = Factory::GetDWriteFactory()->CreateFontFace(
    548          mFontFace->GetType(), numFiles, files.data(), mFontFace->GetIndex(),
    549          sims, getter_AddRefs(mFontFaceBold));
    550      for (UINT32 i = 0; i < numFiles; ++i) {
    551        files[i]->Release();
    552      }
    553      if (FAILED(hr) || !mFontFaceBold) {
    554        return false;
    555      }
    556    }
    557    MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    558      gfxCriticalNote << "Exception occurred initializing bold face";
    559      return false;
    560    }
    561  }
    562  return true;
    563 }
    564 
    565 already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFont(
    566    Float aGlyphSize, const uint8_t* aInstanceData,
    567    uint32_t aInstanceDataLength, const FontVariation* aVariations,
    568    uint32_t aNumVariations) {
    569  if (aInstanceDataLength < sizeof(ScaledFontDWrite::InstanceData)) {
    570    gfxWarning() << "DWrite scaled font instance data is truncated.";
    571    return nullptr;
    572  }
    573  const ScaledFontDWrite::InstanceData& instanceData =
    574      *reinterpret_cast<const ScaledFontDWrite::InstanceData*>(aInstanceData);
    575 
    576  IDWriteFontFace* face = mFontFace;
    577  if (instanceData.mUseBoldSimulation) {
    578    if (!InitBold()) {
    579      gfxWarning() << "Failed creating bold IDWriteFontFace.";
    580      return nullptr;
    581    }
    582    face = mFontFaceBold;
    583  }
    584  DWRITE_FONT_SIMULATIONS sims = face->GetSimulations();
    585 
    586  // If variations are required, we create a separate IDWriteFontFace5 with
    587  // the requested settings applied.
    588  RefPtr<IDWriteFontFace5> ff5;
    589  if (aNumVariations) {
    590    ff5 =
    591        CreateFaceWithVariations(mFontFace, sims, aVariations, aNumVariations);
    592    if (ff5) {
    593      face = ff5;
    594    } else {
    595      gfxWarning() << "Failed to create IDWriteFontFace5 with variations.";
    596    }
    597  }
    598 
    599  return MakeAndAddRef<ScaledFontDWrite>(
    600      face, this, aGlyphSize, instanceData.mUseEmbeddedBitmap,
    601      instanceData.mUseMultistrikeBold, instanceData.mGDIForced, nullptr);
    602 }
    603 
    604 already_AddRefed<ScaledFont> UnscaledFontDWrite::CreateScaledFontFromWRFont(
    605    Float aGlyphSize, const wr::FontInstanceOptions* aOptions,
    606    const wr::FontInstancePlatformOptions* aPlatformOptions,
    607    const FontVariation* aVariations, uint32_t aNumVariations) {
    608  ScaledFontDWrite::InstanceData instanceData(aOptions, aPlatformOptions);
    609  return CreateScaledFont(aGlyphSize, reinterpret_cast<uint8_t*>(&instanceData),
    610                          sizeof(instanceData), aVariations, aNumVariations);
    611 }
    612 
    613 AntialiasMode ScaledFontDWrite::GetDefaultAAMode() {
    614  AntialiasMode defaultMode = GetSystemDefaultAAMode();
    615 
    616  switch (defaultMode) {
    617    case AntialiasMode::SUBPIXEL:
    618    case AntialiasMode::DEFAULT:
    619      if (DWriteSettings().ClearTypeLevel() == 0.0f) {
    620        defaultMode = AntialiasMode::GRAY;
    621      }
    622      break;
    623    case AntialiasMode::GRAY:
    624      if (!DoGrayscale(mFontFace, mSize)) {
    625        defaultMode = AntialiasMode::NONE;
    626      }
    627      break;
    628    case AntialiasMode::NONE:
    629      break;
    630  }
    631 
    632  return defaultMode;
    633 }
    634 
    635 cairo_font_face_t* ScaledFontDWrite::CreateCairoFontFace(
    636    cairo_font_options_t* aFontOptions) {
    637  if (!mFontFace) {
    638    return nullptr;
    639  }
    640 
    641  return cairo_dwrite_font_face_create_for_dwrite_fontface(mFontFace);
    642 }
    643 
    644 void ScaledFontDWrite::PrepareCairoScaledFont(cairo_scaled_font_t* aFont) {
    645 #if 0
    646  if (mGDIForced) {
    647    cairo_dwrite_scaled_font_set_force_GDI_classic(aFont, true);
    648  }
    649 #endif
    650 }
    651 
    652 already_AddRefed<UnscaledFont> UnscaledFontDWrite::CreateFromFontDescriptor(
    653    const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex) {
    654  // Note that despite the type of aData here, it actually points to a 16-bit
    655  // Windows font file path (hence the cast to WCHAR* below).
    656  if (aDataLength == 0) {
    657    gfxWarning() << "DWrite font descriptor is truncated.";
    658    return nullptr;
    659  }
    660 
    661  RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
    662  if (!factory) {
    663    return nullptr;
    664  }
    665 
    666  MOZ_SEH_TRY {
    667    RefPtr<IDWriteFontFile> fontFile;
    668    HRESULT hr = factory->CreateFontFileReference((const WCHAR*)aData, nullptr,
    669                                                  getter_AddRefs(fontFile));
    670    if (FAILED(hr)) {
    671      return nullptr;
    672    }
    673    BOOL isSupported;
    674    DWRITE_FONT_FILE_TYPE fileType;
    675    DWRITE_FONT_FACE_TYPE faceType;
    676    UINT32 numFaces;
    677    hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numFaces);
    678    if (FAILED(hr) || !isSupported || aIndex >= numFaces) {
    679      return nullptr;
    680    }
    681    IDWriteFontFile* fontFiles[1] = {fontFile.get()};
    682    RefPtr<IDWriteFontFace> fontFace;
    683    hr = factory->CreateFontFace(faceType, 1, fontFiles, aIndex,
    684                                 DWRITE_FONT_SIMULATIONS_NONE,
    685                                 getter_AddRefs(fontFace));
    686    if (FAILED(hr)) {
    687      return nullptr;
    688    }
    689    RefPtr unscaledFont = new UnscaledFontDWrite(fontFace, nullptr);
    690    return unscaledFont.forget();
    691  }
    692  MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
    693    gfxCriticalNote << "Exception occurred creating unscaledFont for "
    694                    << NS_ConvertUTF16toUTF8((const char16_t*)aData).get();
    695    return nullptr;
    696  }
    697 }
    698 
    699 }  // namespace gfx
    700 }  // namespace mozilla