tor-browser

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

Factory.cpp (38988B)


      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 "2D.h"
      8 #include "Swizzle.h"
      9 
     10 #ifdef USE_CAIRO
     11 #  include "DrawTargetCairo.h"
     12 #  include "PathCairo.h"
     13 #  include "SourceSurfaceCairo.h"
     14 #endif
     15 
     16 #include "DrawTargetSkia.h"
     17 #include "PathSkia.h"
     18 #include "ScaledFontBase.h"
     19 
     20 #if defined(WIN32)
     21 #  include "ScaledFontWin.h"
     22 #  include "NativeFontResourceGDI.h"
     23 #  include "UnscaledFontGDI.h"
     24 #endif
     25 
     26 #ifdef XP_DARWIN
     27 #  include "ScaledFontMac.h"
     28 #  include "NativeFontResourceMac.h"
     29 #  include "UnscaledFontMac.h"
     30 #endif
     31 
     32 #ifdef MOZ_WIDGET_GTK
     33 #  include "ScaledFontFontconfig.h"
     34 #  include "NativeFontResourceFreeType.h"
     35 #  include "UnscaledFontFreeType.h"
     36 #endif
     37 
     38 #ifdef MOZ_WIDGET_ANDROID
     39 #  include "ScaledFontFreeType.h"
     40 #  include "NativeFontResourceFreeType.h"
     41 #  include "UnscaledFontFreeType.h"
     42 #endif
     43 
     44 #ifdef WIN32
     45 #  include "ScaledFontDWrite.h"
     46 #  include "NativeFontResourceDWrite.h"
     47 #  include "UnscaledFontDWrite.h"
     48 #  include <d3d10_1.h>
     49 #  include <stdlib.h>
     50 #  include "HelpersWin.h"
     51 #  include "ImageContainer.h"
     52 #  include "mozilla/layers/LayersSurfaces.h"
     53 #  include "mozilla/layers/TextureD3D11.h"
     54 #  include "mozilla/layers/VideoProcessorD3D11.h"
     55 #  include "nsWindowsHelpers.h"
     56 #endif
     57 
     58 #include "DrawTargetOffset.h"
     59 #include "DrawTargetRecording.h"
     60 #include "PathRecording.h"
     61 
     62 #include "SourceSurfaceRawData.h"
     63 
     64 #include "mozilla/CheckedInt.h"
     65 
     66 #ifdef MOZ_ENABLE_FREETYPE
     67 #  include "ft2build.h"
     68 #  include FT_FREETYPE_H
     69 #endif
     70 #include "mozilla/StaticPrefs_gfx.h"
     71 
     72 #if defined(MOZ_LOGGING)
     73 GFX2D_API mozilla::LogModule* GetGFX2DLog() {
     74  static mozilla::LazyLogModule sLog("gfx2d");
     75  return sLog;
     76 }
     77 #endif
     78 
     79 // The following code was largely taken from xpcom/glue/SSE.cpp and
     80 // made a little simpler.
     81 enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
     82 
     83 #ifdef HAVE_CPUID_H
     84 
     85 #  if !(defined(__SSE2__) || defined(_M_X64) ||      \
     86        (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) || \
     87      !defined(__SSE4__)
     88 // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
     89 #    include <cpuid.h>
     90 
     91 static inline bool HasCPUIDBit(unsigned int level, CPUIDRegister reg,
     92                               unsigned int bit) {
     93  unsigned int regs[4];
     94  return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
     95         (regs[reg] & bit);
     96 }
     97 #  endif
     98 
     99 #  define HAVE_CPU_DETECTION
    100 #else
    101 
    102 #  if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
    103 // MSVC 2005 or later supports __cpuid by intrin.h
    104 #    include <intrin.h>
    105 
    106 #    define HAVE_CPU_DETECTION
    107 #  elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
    108 
    109 // Define a function identical to MSVC function.
    110 #    ifdef __i386
    111 static void __cpuid(int CPUInfo[4], int InfoType) {
    112  asm("xchg %esi, %ebx\n"
    113      "cpuid\n"
    114      "movl %eax, (%edi)\n"
    115      "movl %ebx, 4(%edi)\n"
    116      "movl %ecx, 8(%edi)\n"
    117      "movl %edx, 12(%edi)\n"
    118      "xchg %esi, %ebx\n"
    119      :
    120      : "a"(InfoType),  // %eax
    121        "D"(CPUInfo)    // %edi
    122      : "%ecx", "%edx", "%esi");
    123 }
    124 #    else
    125 static void __cpuid(int CPUInfo[4], int InfoType) {
    126  asm("xchg %rsi, %rbx\n"
    127      "cpuid\n"
    128      "movl %eax, (%rdi)\n"
    129      "movl %ebx, 4(%rdi)\n"
    130      "movl %ecx, 8(%rdi)\n"
    131      "movl %edx, 12(%rdi)\n"
    132      "xchg %rsi, %rbx\n"
    133      :
    134      : "a"(InfoType),  // %eax
    135        "D"(CPUInfo)    // %rdi
    136      : "%ecx", "%edx", "%rsi");
    137 }
    138 
    139 #      define HAVE_CPU_DETECTION
    140 #    endif
    141 #  endif
    142 
    143 #  ifdef HAVE_CPU_DETECTION
    144 static inline bool HasCPUIDBit(unsigned int level, CPUIDRegister reg,
    145                               unsigned int bit) {
    146  // Check that the level in question is supported.
    147  volatile int regs[4];
    148  __cpuid((int*)regs, level & 0x80000000u);
    149  if (unsigned(regs[0]) < level) return false;
    150  __cpuid((int*)regs, level);
    151  return !!(unsigned(regs[reg]) & bit);
    152 }
    153 #  endif
    154 #endif
    155 
    156 #ifdef MOZ_ENABLE_FREETYPE
    157 extern "C" {
    158 
    159 void mozilla_AddRefSharedFTFace(void* aContext) {
    160  if (aContext) {
    161    static_cast<mozilla::gfx::SharedFTFace*>(aContext)->AddRef();
    162  }
    163 }
    164 
    165 void mozilla_ReleaseSharedFTFace(void* aContext, void* aOwner) {
    166  if (aContext) {
    167    auto* sharedFace = static_cast<mozilla::gfx::SharedFTFace*>(aContext);
    168    sharedFace->ForgetLockOwner(aOwner);
    169    sharedFace->Release();
    170  }
    171 }
    172 
    173 void mozilla_ForgetSharedFTFaceLockOwner(void* aContext, void* aOwner) {
    174  static_cast<mozilla::gfx::SharedFTFace*>(aContext)->ForgetLockOwner(aOwner);
    175 }
    176 
    177 int mozilla_LockSharedFTFace(void* aContext,
    178                             void* aOwner) MOZ_NO_THREAD_SAFETY_ANALYSIS {
    179  return int(static_cast<mozilla::gfx::SharedFTFace*>(aContext)->Lock(aOwner));
    180 }
    181 
    182 void mozilla_UnlockSharedFTFace(void* aContext) MOZ_NO_THREAD_SAFETY_ANALYSIS {
    183  static_cast<mozilla::gfx::SharedFTFace*>(aContext)->Unlock();
    184 }
    185 
    186 FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
    187                             int32_t aFlags) {
    188  return mozilla::gfx::Factory::LoadFTGlyph(aFace, aGlyphIndex, aFlags);
    189 }
    190 
    191 void mozilla_LockFTLibrary(FT_Library aFTLibrary) {
    192  mozilla::gfx::Factory::LockFTLibrary(aFTLibrary);
    193 }
    194 
    195 void mozilla_UnlockFTLibrary(FT_Library aFTLibrary) {
    196  mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary);
    197 }
    198 }
    199 #endif
    200 
    201 namespace mozilla::gfx {
    202 
    203 #ifdef MOZ_ENABLE_FREETYPE
    204 FT_Library Factory::mFTLibrary = nullptr;
    205 StaticMutex Factory::mFTLock;
    206 
    207 already_AddRefed<SharedFTFace> FTUserFontData::CloneFace(int aFaceIndex) {
    208  if (mFontData) {
    209    RefPtr<SharedFTFace> face = Factory::NewSharedFTFaceFromData(
    210        nullptr, mFontData, mLength, aFaceIndex, this);
    211    if (!face ||
    212        (FT_Select_Charmap(face->GetFace(), FT_ENCODING_UNICODE) != FT_Err_Ok &&
    213         FT_Select_Charmap(face->GetFace(), FT_ENCODING_MS_SYMBOL) !=
    214             FT_Err_Ok)) {
    215      return nullptr;
    216    }
    217    return face.forget();
    218  }
    219  FT_Face face = Factory::NewFTFace(nullptr, mFilename.c_str(), aFaceIndex);
    220  if (face) {
    221    return MakeAndAddRef<SharedFTFace>(face, this);
    222  }
    223  return nullptr;
    224 }
    225 #endif
    226 
    227 #ifdef WIN32
    228 // Note: mDeviceLock must be held when mutating these values.
    229 StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
    230 StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
    231 StaticRefPtr<IDWriteFontCollection> Factory::mDWriteSystemFonts;
    232 StaticMutex Factory::mDeviceLock;
    233 #endif
    234 
    235 SubpixelOrder Factory::mSubpixelOrder = SubpixelOrder::UNKNOWN;
    236 
    237 mozilla::gfx::Config* Factory::sConfig = nullptr;
    238 
    239 void Factory::Init(const Config& aConfig) {
    240  MOZ_ASSERT(!sConfig);
    241  sConfig = new Config(aConfig);
    242 
    243 #ifdef XP_DARWIN
    244  NativeFontResourceMac::RegisterMemoryReporter();
    245 #else
    246  NativeFontResource::RegisterMemoryReporter();
    247 #endif
    248 
    249  SourceSurfaceAlignedRawData::RegisterMemoryReporter();
    250 }
    251 
    252 void Factory::ShutDown() {
    253  if (sConfig) {
    254    delete sConfig->mLogForwarder;
    255    delete sConfig;
    256    sConfig = nullptr;
    257  }
    258 
    259 #ifdef MOZ_ENABLE_FREETYPE
    260  mFTLibrary = nullptr;
    261 #endif
    262 }
    263 
    264 bool Factory::HasSSE2() {
    265 #if defined(__SSE2__) || defined(_M_X64) || \
    266    (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
    267  // gcc with -msse2 (default on OSX and x86-64)
    268  // cl.exe with -arch:SSE2 (default on x64 compiler)
    269  return true;
    270 #elif defined(HAVE_CPU_DETECTION)
    271  static enum {
    272    UNINITIALIZED,
    273    NO_SSE2,
    274    HAS_SSE2
    275  } sDetectionState = UNINITIALIZED;
    276 
    277  if (sDetectionState == UNINITIALIZED) {
    278    sDetectionState = HasCPUIDBit(1u, edx, (1u << 26)) ? HAS_SSE2 : NO_SSE2;
    279  }
    280  return sDetectionState == HAS_SSE2;
    281 #else
    282  return false;
    283 #endif
    284 }
    285 
    286 bool Factory::HasSSE4() {
    287 #if defined(__SSE4__)
    288  // gcc with -msse2 (default on OSX and x86-64)
    289  // cl.exe with -arch:SSE2 (default on x64 compiler)
    290  return true;
    291 #elif defined(HAVE_CPU_DETECTION)
    292  static enum {
    293    UNINITIALIZED,
    294    NO_SSE4,
    295    HAS_SSE4
    296  } sDetectionState = UNINITIALIZED;
    297 
    298  if (sDetectionState == UNINITIALIZED) {
    299    sDetectionState = HasCPUIDBit(1u, ecx, (1u << 19)) ? HAS_SSE4 : NO_SSE4;
    300  }
    301  return sDetectionState == HAS_SSE4;
    302 #else
    303  return false;
    304 #endif
    305 }
    306 
    307 // If the size is "reasonable", we want gfxCriticalError to assert, so
    308 // this is the option set up for it.
    309 inline int LoggerOptionsBasedOnSize(const IntSize& aSize) {
    310  return CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize));
    311 }
    312 
    313 bool Factory::ReasonableSurfaceSize(const IntSize& aSize) {
    314  return Factory::CheckSurfaceSize(aSize, kReasonableSurfaceSize);
    315 }
    316 
    317 bool Factory::AllowedSurfaceSize(const IntSize& aSize) {
    318  if (sConfig) {
    319    return Factory::CheckSurfaceSize(aSize, sConfig->mMaxTextureSize,
    320                                     sConfig->mMaxAllocSize);
    321  }
    322 
    323  return CheckSurfaceSize(aSize);
    324 }
    325 
    326 bool Factory::CheckSurfaceSize(const IntSize& sz, int32_t extentLimit,
    327                               int32_t allocLimit) {
    328  if (sz.width <= 0 || sz.height <= 0) {
    329    return false;
    330  }
    331 
    332  // reject images with sides bigger than limit
    333  if (extentLimit && (sz.width > extentLimit || sz.height > extentLimit)) {
    334    gfxDebug() << "Surface size too large (exceeds extent limit)!";
    335    return false;
    336  }
    337 
    338  // assuming 4 bytes per pixel, make sure the allocation size
    339  // doesn't overflow a int32_t either
    340  CheckedInt<int32_t> stride = GetAlignedStride<16>(sz.width, 4);
    341  if (!stride.isValid() || stride.value() == 0) {
    342    gfxDebug() << "Surface size too large (stride overflows int32_t)!";
    343    return false;
    344  }
    345 
    346  CheckedInt<int32_t> numBytes = stride * sz.height;
    347  if (!numBytes.isValid()) {
    348    gfxDebug()
    349        << "Surface size too large (allocation size would overflow int32_t)!";
    350    return false;
    351  }
    352 
    353  if (allocLimit && allocLimit < numBytes.value()) {
    354    gfxDebug() << "Surface size too large (exceeds allocation limit)!";
    355    return false;
    356  }
    357 
    358  return true;
    359 }
    360 
    361 already_AddRefed<DrawTarget> Factory::CreateDrawTarget(BackendType aBackend,
    362                                                       const IntSize& aSize,
    363                                                       SurfaceFormat aFormat) {
    364  if (!AllowedSurfaceSize(aSize)) {
    365    gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    366        << "Failed to allocate a surface due to invalid size (CDT) " << aSize;
    367    return nullptr;
    368  }
    369 
    370  RefPtr<DrawTarget> retVal;
    371  switch (aBackend) {
    372    case BackendType::SKIA: {
    373      RefPtr<DrawTargetSkia> newTarget;
    374      newTarget = new DrawTargetSkia();
    375      if (newTarget->Init(aSize, aFormat)) {
    376        retVal = newTarget;
    377      }
    378      break;
    379    }
    380 #ifdef USE_CAIRO
    381    case BackendType::CAIRO: {
    382      RefPtr<DrawTargetCairo> newTarget;
    383      newTarget = new DrawTargetCairo();
    384      if (newTarget->Init(aSize, aFormat)) {
    385        retVal = newTarget;
    386      }
    387      break;
    388    }
    389 #endif
    390    default:
    391      return nullptr;
    392  }
    393 
    394  if (!retVal) {
    395    // Failed
    396    gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    397        << "Failed to create DrawTarget, Type: " << int(aBackend)
    398        << " Size: " << aSize;
    399  }
    400 
    401  return retVal.forget();
    402 }
    403 
    404 already_AddRefed<PathBuilder> Factory::CreatePathBuilder(BackendType aBackend,
    405                                                         FillRule aFillRule) {
    406  switch (aBackend) {
    407    case BackendType::SKIA:
    408    case BackendType::WEBGL:
    409      return PathBuilderSkia::Create(aFillRule);
    410 #ifdef USE_CAIRO
    411    case BackendType::CAIRO:
    412      return PathBuilderCairo::Create(aFillRule);
    413 #endif
    414    case BackendType::RECORDING:
    415      return do_AddRef(new PathBuilderRecording(BackendType::SKIA, aFillRule));
    416    default:
    417      gfxCriticalNote << "Invalid PathBuilder type specified: "
    418                      << (int)aBackend;
    419      return nullptr;
    420  }
    421 }
    422 
    423 already_AddRefed<PathBuilder> Factory::CreateSimplePathBuilder() {
    424  return CreatePathBuilder(BackendType::SKIA);
    425 }
    426 
    427 already_AddRefed<DrawTarget> Factory::CreateRecordingDrawTarget(
    428    DrawEventRecorder* aRecorder, DrawTarget* aDT, IntRect aRect) {
    429  return MakeAndAddRef<DrawTargetRecording>(aRecorder, aDT, aRect);
    430 }
    431 
    432 already_AddRefed<DrawTarget> Factory::CreateDrawTargetForData(
    433    BackendType aBackend, unsigned char* aData, const IntSize& aSize,
    434    int32_t aStride, SurfaceFormat aFormat, bool aUninitialized,
    435    bool aIsClear) {
    436  MOZ_ASSERT(aData);
    437  if (!AllowedSurfaceSize(aSize)) {
    438    gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    439        << "Failed to allocate a surface due to invalid size (DTD) " << aSize;
    440    return nullptr;
    441  }
    442 
    443  RefPtr<DrawTarget> retVal;
    444 
    445  switch (aBackend) {
    446    case BackendType::SKIA: {
    447      RefPtr<DrawTargetSkia> newTarget;
    448      newTarget = new DrawTargetSkia();
    449      if (newTarget->Init(aData, aSize, aStride, aFormat, aUninitialized,
    450                          aIsClear)) {
    451        retVal = newTarget;
    452      }
    453      break;
    454    }
    455 #ifdef USE_CAIRO
    456    case BackendType::CAIRO: {
    457      RefPtr<DrawTargetCairo> newTarget;
    458      newTarget = new DrawTargetCairo();
    459      if (newTarget->Init(aData, aSize, aStride, aFormat)) {
    460        retVal = std::move(newTarget);
    461      }
    462      break;
    463    }
    464 #endif
    465    default:
    466      gfxCriticalNote << "Invalid draw target type specified: "
    467                      << (int)aBackend;
    468      return nullptr;
    469  }
    470 
    471  if (!retVal) {
    472    gfxCriticalNote << "Failed to create DrawTarget, Type: " << int(aBackend)
    473                    << " Size: " << aSize << ", Data: " << hexa((void*)aData)
    474                    << ", Stride: " << aStride;
    475  }
    476 
    477  return retVal.forget();
    478 }
    479 
    480 already_AddRefed<DrawTarget> Factory::CreateOffsetDrawTarget(
    481    DrawTarget* aDrawTarget, IntPoint aTileOrigin) {
    482  RefPtr<DrawTargetOffset> dt = new DrawTargetOffset();
    483 
    484  if (!dt->Init(aDrawTarget, aTileOrigin)) {
    485    return nullptr;
    486  }
    487 
    488  return dt.forget();
    489 }
    490 
    491 bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType) {
    492  switch (aType) {
    493    case BackendType::RECORDING:
    494    case BackendType::NONE:
    495    case BackendType::BACKEND_LAST:
    496    case BackendType::WEBRENDER_TEXT:
    497    case BackendType::WEBGL:
    498      return false;
    499    case BackendType::CAIRO:
    500    case BackendType::SKIA:
    501      return true;
    502  }
    503 
    504  return false;
    505 }
    506 
    507 uint32_t Factory::GetMaxSurfaceSize(BackendType aType) {
    508  switch (aType) {
    509    case BackendType::CAIRO:
    510      return DrawTargetCairo::GetMaxSurfaceSize();
    511    case BackendType::SKIA:
    512      return DrawTargetSkia::GetMaxSurfaceSize();
    513    default:
    514      return 0;
    515  }
    516 }
    517 
    518 already_AddRefed<NativeFontResource> Factory::CreateNativeFontResource(
    519    const uint8_t* aData, uint32_t aSize, FontType aFontType,
    520    void* aFontContext) {
    521  switch (aFontType) {
    522 #ifdef WIN32
    523    case FontType::DWRITE:
    524      return NativeFontResourceDWrite::Create(aData, aSize);
    525    case FontType::GDI:
    526      return NativeFontResourceGDI::Create(aData, aSize);
    527 #elif defined(XP_DARWIN)
    528    case FontType::MAC:
    529      return NativeFontResourceMac::Create(aData, aSize);
    530 #elif defined(MOZ_WIDGET_GTK)
    531    case FontType::FONTCONFIG:
    532      return NativeFontResourceFontconfig::Create(
    533          aData, aSize, static_cast<FT_Library>(aFontContext));
    534 #elif defined(MOZ_WIDGET_ANDROID)
    535    case FontType::FREETYPE:
    536      return NativeFontResourceFreeType::Create(
    537          aData, aSize, static_cast<FT_Library>(aFontContext));
    538 #endif
    539    default:
    540      gfxWarning()
    541          << "Unable to create requested font resource from truetype data";
    542      return nullptr;
    543  }
    544 }
    545 
    546 already_AddRefed<UnscaledFont> Factory::CreateUnscaledFontFromFontDescriptor(
    547    FontType aType, const uint8_t* aData, uint32_t aDataLength,
    548    uint32_t aIndex) {
    549  switch (aType) {
    550 #ifdef WIN32
    551    case FontType::DWRITE:
    552      return UnscaledFontDWrite::CreateFromFontDescriptor(aData, aDataLength,
    553                                                          aIndex);
    554    case FontType::GDI:
    555      return UnscaledFontGDI::CreateFromFontDescriptor(aData, aDataLength,
    556                                                       aIndex);
    557 #elif defined(XP_DARWIN)
    558    case FontType::MAC:
    559      return UnscaledFontMac::CreateFromFontDescriptor(aData, aDataLength,
    560                                                       aIndex);
    561 #elif defined(MOZ_WIDGET_GTK)
    562    case FontType::FONTCONFIG:
    563      return UnscaledFontFontconfig::CreateFromFontDescriptor(
    564          aData, aDataLength, aIndex);
    565 #elif defined(MOZ_WIDGET_ANDROID)
    566    case FontType::FREETYPE:
    567      return UnscaledFontFreeType::CreateFromFontDescriptor(aData, aDataLength,
    568                                                            aIndex);
    569 #endif
    570    default:
    571      gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
    572      return nullptr;
    573  }
    574 }
    575 
    576 #ifdef XP_DARWIN
    577 already_AddRefed<ScaledFont> Factory::CreateScaledFontForMacFont(
    578    CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
    579    bool aUseFontSmoothing, bool aApplySyntheticBold, bool aHasColorGlyphs) {
    580  return MakeAndAddRef<ScaledFontMac>(aCGFont, aUnscaledFont, aSize, false,
    581                                      aUseFontSmoothing, aApplySyntheticBold,
    582                                      aHasColorGlyphs);
    583 }
    584 #endif
    585 
    586 #ifdef MOZ_WIDGET_GTK
    587 already_AddRefed<ScaledFont> Factory::CreateScaledFontForFontconfigFont(
    588    const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
    589    RefPtr<SharedFTFace> aFace, FcPattern* aPattern) {
    590  return MakeAndAddRef<ScaledFontFontconfig>(std::move(aFace), aPattern,
    591                                             aUnscaledFont, aSize);
    592 }
    593 #endif
    594 
    595 #ifdef MOZ_WIDGET_ANDROID
    596 already_AddRefed<ScaledFont> Factory::CreateScaledFontForFreeTypeFont(
    597    const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
    598    RefPtr<SharedFTFace> aFace, bool aApplySyntheticBold) {
    599  return MakeAndAddRef<ScaledFontFreeType>(std::move(aFace), aUnscaledFont,
    600                                           aSize, aApplySyntheticBold);
    601 }
    602 #endif
    603 
    604 void Factory::SetSubpixelOrder(SubpixelOrder aOrder) {
    605  mSubpixelOrder = aOrder;
    606 }
    607 
    608 SubpixelOrder Factory::GetSubpixelOrder() { return mSubpixelOrder; }
    609 
    610 #ifdef MOZ_ENABLE_FREETYPE
    611 SharedFTFace::SharedFTFace(FT_Face aFace, SharedFTFaceData* aData)
    612    : mFace(aFace),
    613      mData(aData),
    614      mLock("SharedFTFace::mLock"),
    615      mLastLockOwner(nullptr) {
    616  if (mData) {
    617    mData->BindData();
    618  }
    619 }
    620 
    621 SharedFTFace::~SharedFTFace() {
    622  Factory::ReleaseFTFace(mFace);
    623  if (mData) {
    624    mData->ReleaseData();
    625  }
    626 }
    627 
    628 void Factory::SetFTLibrary(FT_Library aFTLibrary) { mFTLibrary = aFTLibrary; }
    629 
    630 FT_Library Factory::GetFTLibrary() {
    631  MOZ_ASSERT(mFTLibrary);
    632  return mFTLibrary;
    633 }
    634 
    635 FT_Library Factory::NewFTLibrary() {
    636  FT_Library library;
    637  if (FT_Init_FreeType(&library) != FT_Err_Ok) {
    638    return nullptr;
    639  }
    640  return library;
    641 }
    642 
    643 void Factory::ReleaseFTLibrary(FT_Library aFTLibrary) {
    644  FT_Done_FreeType(aFTLibrary);
    645 }
    646 
    647 void Factory::LockFTLibrary(FT_Library aFTLibrary)
    648    MOZ_CAPABILITY_ACQUIRE(mFTLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
    649  mFTLock.Lock();
    650 }
    651 
    652 void Factory::UnlockFTLibrary(FT_Library aFTLibrary)
    653    MOZ_CAPABILITY_RELEASE(mFTLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
    654  mFTLock.Unlock();
    655 }
    656 
    657 FT_Face Factory::NewFTFace(FT_Library aFTLibrary, const char* aFileName,
    658                           int aFaceIndex) {
    659  StaticMutexAutoLock lock(mFTLock);
    660  if (!aFTLibrary) {
    661    aFTLibrary = mFTLibrary;
    662  }
    663  FT_Face face;
    664  if (FT_New_Face(aFTLibrary, aFileName, aFaceIndex, &face) != FT_Err_Ok) {
    665    return nullptr;
    666  }
    667  return face;
    668 }
    669 
    670 already_AddRefed<SharedFTFace> Factory::NewSharedFTFace(FT_Library aFTLibrary,
    671                                                        const char* aFilename,
    672                                                        int aFaceIndex) {
    673  FT_Face face = NewFTFace(aFTLibrary, aFilename, aFaceIndex);
    674  if (!face) {
    675    return nullptr;
    676  }
    677 
    678  RefPtr<FTUserFontData> data;
    679 #  ifdef ANDROID
    680  // If the font has variations, we may later need to "clone" it in
    681  // UnscaledFontFreeType::CreateScaledFont. To support this, we attach an
    682  // FTUserFontData that records the filename used to instantiate the face.
    683  if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
    684    data = new FTUserFontData(aFilename);
    685  }
    686 #  endif
    687  return MakeAndAddRef<SharedFTFace>(face, data);
    688 }
    689 
    690 FT_Face Factory::NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData,
    691                                   size_t aDataSize, int aFaceIndex) {
    692  StaticMutexAutoLock lock(mFTLock);
    693  if (!aFTLibrary) {
    694    aFTLibrary = mFTLibrary;
    695  }
    696  FT_Face face;
    697  if (FT_New_Memory_Face(aFTLibrary, aData, aDataSize, aFaceIndex, &face) !=
    698      FT_Err_Ok) {
    699    return nullptr;
    700  }
    701  return face;
    702 }
    703 
    704 already_AddRefed<SharedFTFace> Factory::NewSharedFTFaceFromData(
    705    FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize,
    706    int aFaceIndex, SharedFTFaceData* aSharedData) {
    707  if (FT_Face face =
    708          NewFTFaceFromData(aFTLibrary, aData, aDataSize, aFaceIndex)) {
    709    return MakeAndAddRef<SharedFTFace>(face, aSharedData);
    710  } else {
    711    return nullptr;
    712  }
    713 }
    714 
    715 void Factory::ReleaseFTFace(FT_Face aFace) {
    716  StaticMutexAutoLock lock(mFTLock);
    717  FT_Done_Face(aFace);
    718 }
    719 
    720 FT_Error Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
    721                              int32_t aFlags) {
    722  StaticMutexAutoLock lock(mFTLock);
    723  return FT_Load_Glyph(aFace, aGlyphIndex, aFlags);
    724 }
    725 #endif
    726 
    727 #ifdef WIN32
    728 bool Factory::SetDirect3D11Device(ID3D11Device* aDevice) {
    729  MOZ_RELEASE_ASSERT(NS_IsMainThread());
    730 
    731  StaticMutexAutoLock lock(mDeviceLock);
    732 
    733  mD3D11Device = aDevice;
    734  return true;
    735 }
    736 
    737 RefPtr<ID3D11Device> Factory::GetDirect3D11Device() {
    738  StaticMutexAutoLock lock(mDeviceLock);
    739  return mD3D11Device;
    740 }
    741 
    742 RefPtr<IDWriteFactory> Factory::GetDWriteFactory() {
    743  StaticMutexAutoLock lock(mDeviceLock);
    744  return mDWriteFactory;
    745 }
    746 
    747 RefPtr<IDWriteFactory> Factory::EnsureDWriteFactory() {
    748  StaticMutexAutoLock lock(mDeviceLock);
    749 
    750  if (mDWriteFactory) {
    751    return mDWriteFactory;
    752  }
    753 
    754  HMODULE dwriteModule = LoadLibrarySystem32(L"dwrite.dll");
    755  decltype(DWriteCreateFactory)* createDWriteFactory =
    756      (decltype(DWriteCreateFactory)*)GetProcAddress(dwriteModule,
    757                                                     "DWriteCreateFactory");
    758 
    759  if (!createDWriteFactory) {
    760    gfxWarning() << "Failed to locate DWriteCreateFactory function.";
    761    return nullptr;
    762  }
    763 
    764  HRESULT hr =
    765      createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
    766                          reinterpret_cast<IUnknown**>(&mDWriteFactory));
    767 
    768  if (FAILED(hr)) {
    769    gfxWarning() << "Failed to create DWrite Factory.";
    770  }
    771 
    772  return mDWriteFactory;
    773 }
    774 
    775 RefPtr<IDWriteFontCollection> Factory::GetDWriteSystemFonts(bool aUpdate) {
    776  StaticMutexAutoLock lock(mDeviceLock);
    777 
    778  if (mDWriteSystemFonts && !aUpdate) {
    779    return mDWriteSystemFonts;
    780  }
    781 
    782  if (!mDWriteFactory) {
    783    if ((rand() & 0x3f) == 0) {
    784      gfxCriticalError(int(gfx::LogOptions::AssertOnCall))
    785          << "Failed to create DWrite factory";
    786    } else {
    787      gfxWarning() << "Failed to create DWrite factory";
    788    }
    789 
    790    return nullptr;
    791  }
    792 
    793  RefPtr<IDWriteFontCollection> systemFonts;
    794  HRESULT hr =
    795      mDWriteFactory->GetSystemFontCollection(getter_AddRefs(systemFonts));
    796  if (FAILED(hr) || !systemFonts) {
    797    // only crash some of the time so those experiencing this problem
    798    // don't stop using Firefox
    799    if ((rand() & 0x3f) == 0) {
    800      gfxCriticalError(int(gfx::LogOptions::AssertOnCall))
    801          << "Failed to create DWrite system font collection";
    802    } else {
    803      gfxWarning() << "Failed to create DWrite system font collection";
    804    }
    805    return nullptr;
    806  }
    807  mDWriteSystemFonts = systemFonts;
    808 
    809  return mDWriteSystemFonts;
    810 }
    811 
    812 BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
    813 void Factory::SetSystemTextQuality(uint8_t aQuality) {
    814  sSystemTextQuality = aQuality;
    815 }
    816 
    817 already_AddRefed<ScaledFont> Factory::CreateScaledFontForDWriteFont(
    818    IDWriteFontFace* aFontFace, const gfxFontStyle* aStyle,
    819    const RefPtr<UnscaledFont>& aUnscaledFont, float aSize,
    820    bool aUseEmbeddedBitmap, bool aUseMultistrikeBold, bool aGDIForced) {
    821  return MakeAndAddRef<ScaledFontDWrite>(
    822      aFontFace, aUnscaledFont, aSize, aUseEmbeddedBitmap, aUseMultistrikeBold,
    823      aGDIForced, aStyle);
    824 }
    825 
    826 already_AddRefed<ScaledFont> Factory::CreateScaledFontForGDIFont(
    827    const void* aLogFont, const RefPtr<UnscaledFont>& aUnscaledFont,
    828    Float aSize) {
    829  return MakeAndAddRef<ScaledFontWin>(static_cast<const LOGFONT*>(aLogFont),
    830                                      aUnscaledFont, aSize);
    831 }
    832 #endif  // WIN32
    833 
    834 already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
    835    SkCanvas* aCanvas) {
    836  RefPtr<DrawTargetSkia> newTarget = new DrawTargetSkia();
    837  if (!newTarget->Init(aCanvas)) {
    838    return nullptr;
    839  }
    840  return newTarget.forget();
    841 }
    842 
    843 void Factory::PurgeAllCaches() {}
    844 
    845 already_AddRefed<DrawTarget> Factory::CreateDrawTargetForCairoSurface(
    846    cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat) {
    847  if (!AllowedSurfaceSize(aSize)) {
    848    gfxWarning() << "Allowing surface with invalid size (Cairo) " << aSize;
    849  }
    850 
    851  RefPtr<DrawTarget> retVal;
    852 
    853 #ifdef USE_CAIRO
    854  RefPtr<DrawTargetCairo> newTarget = new DrawTargetCairo();
    855 
    856  if (newTarget->Init(aSurface, aSize, aFormat)) {
    857    retVal = newTarget;
    858  }
    859 #endif
    860  return retVal.forget();
    861 }
    862 
    863 already_AddRefed<SourceSurface> Factory::CreateSourceSurfaceForCairoSurface(
    864    cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat) {
    865  if (aSize.width <= 0 || aSize.height <= 0) {
    866    gfxWarning() << "Can't create a SourceSurface without a valid size";
    867    return nullptr;
    868  }
    869 
    870 #ifdef USE_CAIRO
    871  return MakeAndAddRef<SourceSurfaceCairo>(aSurface, aSize, aFormat);
    872 #else
    873  return nullptr;
    874 #endif
    875 }
    876 
    877 already_AddRefed<DataSourceSurface> Factory::CreateWrappingDataSourceSurface(
    878    uint8_t* aData, int32_t aStride, const IntSize& aSize,
    879    SurfaceFormat aFormat,
    880    SourceSurfaceDeallocator aDeallocator /* = nullptr */,
    881    void* aClosure /* = nullptr */) {
    882  // Just check for negative/zero size instead of the full AllowedSurfaceSize()
    883  // - since the data is already allocated we do not need to check for a
    884  // possible overflow - it already worked.
    885  if (aSize.width <= 0 || aSize.height <= 0) {
    886    return nullptr;
    887  }
    888  if (!aDeallocator && aClosure) {
    889    return nullptr;
    890  }
    891 
    892  MOZ_ASSERT(aData);
    893 
    894  RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
    895  newSurf->InitWrappingData(aData, aSize, aStride, aFormat, aDeallocator,
    896                            aClosure);
    897 
    898  return newSurf.forget();
    899 }
    900 
    901 already_AddRefed<DataSourceSurface> Factory::CreateDataSourceSurface(
    902    const IntSize& aSize, SurfaceFormat aFormat, bool aZero) {
    903  if (!AllowedSurfaceSize(aSize)) {
    904    gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    905        << "Failed to allocate a surface due to invalid size (DSS) " << aSize;
    906    return nullptr;
    907  }
    908 
    909  // Skia doesn't support RGBX, so memset RGBX to 0xFF
    910  bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
    911  uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
    912 
    913  RefPtr<SourceSurfaceAlignedRawData> newSurf =
    914      new SourceSurfaceAlignedRawData();
    915  if (newSurf->Init(aSize, aFormat, clearSurface, clearValue)) {
    916    return newSurf.forget();
    917  }
    918 
    919  gfxWarning() << "CreateDataSourceSurface failed in init";
    920  return nullptr;
    921 }
    922 
    923 already_AddRefed<DataSourceSurface> Factory::CreateDataSourceSurfaceWithStride(
    924    const IntSize& aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero) {
    925  if (!AllowedSurfaceSize(aSize) ||
    926      aStride < aSize.width * BytesPerPixel(aFormat)) {
    927    gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    928        << "CreateDataSourceSurfaceWithStride failed with bad stride "
    929        << aStride << ", " << aSize << ", " << aFormat;
    930    return nullptr;
    931  }
    932 
    933  // Skia doesn't support RGBX, so memset RGBX to 0xFF
    934  bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
    935  uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
    936 
    937  RefPtr<SourceSurfaceAlignedRawData> newSurf =
    938      new SourceSurfaceAlignedRawData();
    939  if (newSurf->Init(aSize, aFormat, clearSurface, clearValue, aStride)) {
    940    return newSurf.forget();
    941  }
    942 
    943  gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
    944      << "CreateDataSourceSurfaceWithStride failed to initialize " << aSize
    945      << ", " << aFormat << ", " << aStride << ", " << aZero;
    946  return nullptr;
    947 }
    948 
    949 already_AddRefed<DataSourceSurface> Factory::CopyDataSourceSurface(
    950    DataSourceSurface* aSource) {
    951  // Don't worry too much about speed.
    952  MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 ||
    953             aSource->GetFormat() == SurfaceFormat::R8G8B8X8 ||
    954             aSource->GetFormat() == SurfaceFormat::B8G8R8A8 ||
    955             aSource->GetFormat() == SurfaceFormat::B8G8R8X8 ||
    956             aSource->GetFormat() == SurfaceFormat::A8);
    957 
    958  DataSourceSurface::ScopedMap srcMap(aSource, DataSourceSurface::READ);
    959  if (NS_WARN_IF(!srcMap.IsMapped())) {
    960    MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface.");
    961    return nullptr;
    962  }
    963 
    964  IntSize size = aSource->GetSize();
    965  SurfaceFormat format = aSource->GetFormat();
    966 
    967  RefPtr<DataSourceSurface> dst = CreateDataSourceSurfaceWithStride(
    968      size, format, srcMap.GetStride(), /* aZero */ false);
    969  if (NS_WARN_IF(!dst)) {
    970    return nullptr;
    971  }
    972 
    973  DataSourceSurface::ScopedMap dstMap(dst, DataSourceSurface::WRITE);
    974  if (NS_WARN_IF(!dstMap.IsMapped())) {
    975    MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface.");
    976    return nullptr;
    977  }
    978 
    979  SwizzleData(srcMap.GetData(), srcMap.GetStride(), format, dstMap.GetData(),
    980              dstMap.GetStride(), format, size);
    981  return dst.forget();
    982 }
    983 
    984 void Factory::CopyDataSourceSurface(DataSourceSurface* aSource,
    985                                    DataSourceSurface* aDest) {
    986  // Don't worry too much about speed.
    987  MOZ_ASSERT(aSource->GetSize() == aDest->GetSize());
    988  MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 ||
    989             aSource->GetFormat() == SurfaceFormat::R8G8B8X8 ||
    990             aSource->GetFormat() == SurfaceFormat::B8G8R8A8 ||
    991             aSource->GetFormat() == SurfaceFormat::B8G8R8X8 ||
    992             aSource->GetFormat() == SurfaceFormat::A8);
    993  MOZ_ASSERT(aDest->GetFormat() == SurfaceFormat::R8G8B8A8 ||
    994             aDest->GetFormat() == SurfaceFormat::R8G8B8X8 ||
    995             aDest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
    996             aDest->GetFormat() == SurfaceFormat::B8G8R8X8 ||
    997             aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16 ||
    998             aDest->GetFormat() == SurfaceFormat::A8);
    999 
   1000  DataSourceSurface::MappedSurface srcMap;
   1001  DataSourceSurface::MappedSurface destMap;
   1002  if (!aSource->Map(DataSourceSurface::MapType::READ, &srcMap) ||
   1003      !aDest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
   1004    MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface.");
   1005    return;
   1006  }
   1007 
   1008  SwizzleData(srcMap.mData, srcMap.mStride, aSource->GetFormat(), destMap.mData,
   1009              destMap.mStride, aDest->GetFormat(), aSource->GetSize());
   1010 
   1011  aSource->Unmap();
   1012  aDest->Unmap();
   1013 }
   1014 
   1015 #ifdef WIN32
   1016 
   1017 /* static */
   1018 already_AddRefed<DataSourceSurface>
   1019 Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
   1020    ID3D11Texture2D* aSrcTexture, uint32_t aArrayIndex,
   1021    gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange) {
   1022  D3D11_TEXTURE2D_DESC srcDesc = {0};
   1023  aSrcTexture->GetDesc(&srcDesc);
   1024 
   1025  RefPtr<gfx::DataSourceSurface> destTexture =
   1026      gfx::Factory::CreateDataSourceSurface(
   1027          IntSize(srcDesc.Width, srcDesc.Height), gfx::SurfaceFormat::B8G8R8A8);
   1028  if (NS_WARN_IF(!destTexture)) {
   1029    return nullptr;
   1030  }
   1031  if (!ReadbackTexture(destTexture, aSrcTexture, aArrayIndex, aColorSpace,
   1032                       aColorRange)) {
   1033    return nullptr;
   1034  }
   1035  return destTexture.forget();
   1036 }
   1037 
   1038 /* static */ nsresult Factory::CreateSdbForD3D11Texture(
   1039    ID3D11Texture2D* aSrcTexture, const IntSize& aSrcSize,
   1040    layers::SurfaceDescriptorBuffer& aSdBuffer,
   1041    const std::function<layers::MemoryOrShmem(uint32_t)>& aAllocate) {
   1042  D3D11_TEXTURE2D_DESC srcDesc = {0};
   1043  aSrcTexture->GetDesc(&srcDesc);
   1044  if (srcDesc.Width != uint32_t(aSrcSize.width) ||
   1045      srcDesc.Height != uint32_t(aSrcSize.height) ||
   1046      srcDesc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) {
   1047    return NS_ERROR_NOT_IMPLEMENTED;
   1048  }
   1049 
   1050  const auto format = gfx::SurfaceFormat::B8G8R8A8;
   1051  uint8_t* buffer = nullptr;
   1052  int32_t stride = 0;
   1053  nsresult rv = layers::Image::AllocateSurfaceDescriptorBufferRgb(
   1054      aSrcSize, format, buffer, aSdBuffer, stride, aAllocate);
   1055  if (NS_WARN_IF(NS_FAILED(rv))) {
   1056    return rv;
   1057  }
   1058 
   1059  if (!ReadbackTexture(buffer, stride, aSrcTexture)) {
   1060    return NS_ERROR_FAILURE;
   1061  }
   1062 
   1063  return NS_OK;
   1064 }
   1065 
   1066 /* static */
   1067 bool Factory::ConvertSourceAndRetryReadback(DataSourceSurface* aDestCpuTexture,
   1068                                            ID3D11Texture2D* aSrcTexture,
   1069                                            uint32_t aArrayIndex,
   1070                                            gfx::ColorSpace2 aColorSpace,
   1071                                            gfx::ColorRange aColorRange) {
   1072  MOZ_ASSERT(aDestCpuTexture);
   1073  MOZ_ASSERT(aSrcTexture);
   1074 
   1075  RefPtr<ID3D11Device> device;
   1076  aSrcTexture->GetDevice(getter_AddRefs(device));
   1077  if (!device) {
   1078    gfxWarning() << "Failed to get D3D11 device from source texture";
   1079    return false;
   1080  }
   1081 
   1082  CD3D11_TEXTURE2D_DESC desc;
   1083  aSrcTexture->GetDesc(&desc);
   1084 
   1085  if (desc.Format != DXGI_FORMAT_NV12 && desc.Format != DXGI_FORMAT_P010 &&
   1086      desc.Format != DXGI_FORMAT_P016) {
   1087    gfxWarning() << "Unexpected DXGI format";
   1088    return false;
   1089  }
   1090 
   1091  desc = CD3D11_TEXTURE2D_DESC(
   1092      DXGI_FORMAT_B8G8R8A8_UNORM, desc.Width, desc.Height, 1, 1,
   1093      D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
   1094 
   1095  RefPtr<ID3D11Texture2D> newSrcTexture;
   1096  HRESULT hr =
   1097      device->CreateTexture2D(&desc, nullptr, getter_AddRefs(newSrcTexture));
   1098  if (FAILED(hr)) {
   1099    gfxWarning() << "Failed to create newSrcTexture: " << gfx::hexa(hr);
   1100    return false;
   1101  }
   1102 
   1103  RefPtr<layers::VideoProcessorD3D11> videoProcessor =
   1104      layers::VideoProcessorD3D11::Create(device);
   1105  if (!videoProcessor) {
   1106    gfxWarning() << "Failed to create VideoProcessorD3D11";
   1107    return false;
   1108  }
   1109 
   1110  hr = videoProcessor->Init(aDestCpuTexture->GetSize());
   1111  if (FAILED(hr)) {
   1112    gfxWarning() << "Failed to init VideoProcessorD3D11" << gfx::hexa(hr);
   1113    return false;
   1114  }
   1115 
   1116  layers::VideoProcessorD3D11::InputTextureInfo info(aColorSpace, aColorRange,
   1117                                                     aArrayIndex, aSrcTexture);
   1118  if (!videoProcessor->CallVideoProcessorBlt(info, newSrcTexture)) {
   1119    gfxWarning() << "CallVideoProcessorBlt failed";
   1120    return false;
   1121  }
   1122 
   1123  return ReadbackTexture(aDestCpuTexture, newSrcTexture, 0, aColorSpace,
   1124                         aColorRange);
   1125 }
   1126 
   1127 /* static */
   1128 bool Factory::ReadbackTexture(DataSourceSurface* aDestCpuTexture,
   1129                              ID3D11Texture2D* aSrcTexture,
   1130                              uint32_t aArrayIndex,
   1131                              gfx::ColorSpace2 aColorSpace,
   1132                              gfx::ColorRange aColorRange) {
   1133  D3D11_TEXTURE2D_DESC srcDesc = {0};
   1134  aSrcTexture->GetDesc(&srcDesc);
   1135 
   1136  // Special case: If the source and destination have different formats and the
   1137  // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
   1138  if ((srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat())) &&
   1139      (aDestCpuTexture->GetFormat() == SurfaceFormat::B8G8R8A8)) {
   1140    return ConvertSourceAndRetryReadback(aDestCpuTexture, aSrcTexture,
   1141                                         aArrayIndex, aColorSpace, aColorRange);
   1142  }
   1143 
   1144  if ((IntSize(srcDesc.Width, srcDesc.Height) != aDestCpuTexture->GetSize()) ||
   1145      (srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat()))) {
   1146    gfxWarning() << "Attempted readback between incompatible textures";
   1147    return false;
   1148  }
   1149 
   1150  gfx::DataSourceSurface::MappedSurface mappedSurface;
   1151  if (!aDestCpuTexture->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
   1152    return false;
   1153  }
   1154 
   1155  MOZ_ASSERT(aArrayIndex == 0);
   1156 
   1157  bool ret =
   1158      ReadbackTexture(mappedSurface.mData, mappedSurface.mStride, aSrcTexture);
   1159  aDestCpuTexture->Unmap();
   1160  return ret;
   1161 }
   1162 
   1163 /* static */
   1164 bool Factory::ReadbackTexture(uint8_t* aDestData, int32_t aDestStride,
   1165                              ID3D11Texture2D* aSrcTexture) {
   1166  MOZ_ASSERT(aDestData && aDestStride && aSrcTexture);
   1167 
   1168  RefPtr<ID3D11Device> device;
   1169  aSrcTexture->GetDevice(getter_AddRefs(device));
   1170  if (!device) {
   1171    gfxWarning() << "Failed to get D3D11 device from source texture";
   1172    return false;
   1173  }
   1174 
   1175  RefPtr<ID3D11DeviceContext> context;
   1176  device->GetImmediateContext(getter_AddRefs(context));
   1177  if (!context) {
   1178    gfxWarning() << "Could not get an immediate D3D11 context";
   1179    return false;
   1180  }
   1181 
   1182  RefPtr<IDXGIKeyedMutex> mutex;
   1183  HRESULT hr = aSrcTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
   1184                                           (void**)getter_AddRefs(mutex));
   1185  if (SUCCEEDED(hr) && mutex) {
   1186    hr = mutex->AcquireSync(0, 2000);
   1187    if (hr != S_OK) {
   1188      gfxWarning() << "Could not acquire DXGI surface lock in 2 seconds";
   1189      return false;
   1190    }
   1191  }
   1192 
   1193  D3D11_TEXTURE2D_DESC srcDesc = {0};
   1194  aSrcTexture->GetDesc(&srcDesc);
   1195  srcDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
   1196  srcDesc.Usage = D3D11_USAGE_STAGING;
   1197  srcDesc.BindFlags = 0;
   1198  srcDesc.MiscFlags = 0;
   1199  srcDesc.MipLevels = 1;
   1200  RefPtr<ID3D11Texture2D> srcCpuTexture;
   1201  hr =
   1202      device->CreateTexture2D(&srcDesc, nullptr, getter_AddRefs(srcCpuTexture));
   1203  if (FAILED(hr)) {
   1204    gfxWarning() << "Could not create source texture for mapping";
   1205    if (mutex) {
   1206      mutex->ReleaseSync(0);
   1207    }
   1208    return false;
   1209  }
   1210 
   1211  context->CopyResource(srcCpuTexture, aSrcTexture);
   1212 
   1213  if (mutex) {
   1214    mutex->ReleaseSync(0);
   1215    mutex = nullptr;
   1216  }
   1217 
   1218  D3D11_MAPPED_SUBRESOURCE srcMap;
   1219  hr = context->Map(srcCpuTexture, 0, D3D11_MAP_READ, 0, &srcMap);
   1220  if (FAILED(hr)) {
   1221    gfxWarning() << "Could not map source texture";
   1222    return false;
   1223  }
   1224 
   1225  uint32_t width = srcDesc.Width;
   1226  uint32_t height = srcDesc.Height;
   1227  int bpp = BytesPerPixel(gfx::ToPixelFormat(srcDesc.Format));
   1228  for (uint32_t y = 0; y < height; y++) {
   1229    memcpy(aDestData + aDestStride * y,
   1230           (unsigned char*)(srcMap.pData) + srcMap.RowPitch * y, width * bpp);
   1231  }
   1232 
   1233  context->Unmap(srcCpuTexture, 0);
   1234  return true;
   1235 }
   1236 
   1237 #endif  // WIN32
   1238 
   1239 // static
   1240 void CriticalLogger::OutputMessage(const std::string& aString, int aLevel,
   1241                                   bool aNoNewline) {
   1242  if (Factory::GetLogForwarder()) {
   1243    Factory::GetLogForwarder()->Log(aString);
   1244  }
   1245 
   1246  BasicLogger::OutputMessage(aString, aLevel, aNoNewline);
   1247 }
   1248 
   1249 void CriticalLogger::CrashAction(LogReason aReason) {
   1250  if (Factory::GetLogForwarder()) {
   1251    Factory::GetLogForwarder()->CrashAction(aReason);
   1252  }
   1253 }
   1254 
   1255 #ifdef WIN32
   1256 void LogWStr(const wchar_t* aWStr, std::stringstream& aOut) {
   1257  int n =
   1258      WideCharToMultiByte(CP_ACP, 0, aWStr, -1, nullptr, 0, nullptr, nullptr);
   1259  if (n > 1) {
   1260    std::vector<char> str(n);
   1261    WideCharToMultiByte(CP_ACP, 0, aWStr, -1, str.data(), n, nullptr, nullptr);
   1262    aOut << str.data();
   1263  }
   1264 }
   1265 #endif
   1266 
   1267 }  // namespace mozilla::gfx