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