no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / gfx / 2d / Factory.cpp
blob1bdf5971426ae87a6846e3e995fe9c9efcae3451
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/. */
7 #include "2D.h"
8 #include "Swizzle.h"
10 #ifdef USE_CAIRO
11 # include "DrawTargetCairo.h"
12 # include "PathCairo.h"
13 # include "SourceSurfaceCairo.h"
14 #endif
16 #include "DrawTargetSkia.h"
17 #include "PathSkia.h"
18 #include "ScaledFontBase.h"
20 #if defined(WIN32)
21 # include "ScaledFontWin.h"
22 # include "NativeFontResourceGDI.h"
23 # include "UnscaledFontGDI.h"
24 #endif
26 #ifdef XP_DARWIN
27 # include "ScaledFontMac.h"
28 # include "NativeFontResourceMac.h"
29 # include "UnscaledFontMac.h"
30 #endif
32 #ifdef MOZ_WIDGET_GTK
33 # include "ScaledFontFontconfig.h"
34 # include "NativeFontResourceFreeType.h"
35 # include "UnscaledFontFreeType.h"
36 #endif
38 #ifdef MOZ_WIDGET_ANDROID
39 # include "ScaledFontFreeType.h"
40 # include "NativeFontResourceFreeType.h"
41 # include "UnscaledFontFreeType.h"
42 #endif
44 #ifdef WIN32
45 # include "DrawTargetD2D1.h"
46 # include "PathD2D.h"
47 # include "ScaledFontDWrite.h"
48 # include "NativeFontResourceDWrite.h"
49 # include "UnscaledFontDWrite.h"
50 # include <d3d10_1.h>
51 # include <stdlib.h>
52 # include "HelpersD2D.h"
53 # include "DXVA2Manager.h"
54 # include "ImageContainer.h"
55 # include "mozilla/layers/LayersSurfaces.h"
56 # include "mozilla/layers/TextureD3D11.h"
57 # include "nsWindowsHelpers.h"
58 #endif
60 #include "DrawTargetOffset.h"
61 #include "DrawTargetRecording.h"
63 #include "SourceSurfaceRawData.h"
65 #include "mozilla/CheckedInt.h"
67 #ifdef MOZ_ENABLE_FREETYPE
68 # include "ft2build.h"
69 # include FT_FREETYPE_H
70 #endif
71 #include "mozilla/StaticPrefs_gfx.h"
73 #if defined(MOZ_LOGGING)
74 GFX2D_API mozilla::LogModule* GetGFX2DLog() {
75 static mozilla::LazyLogModule sLog("gfx2d");
76 return sLog;
78 #endif
80 // The following code was largely taken from xpcom/glue/SSE.cpp and
81 // made a little simpler.
82 enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
84 #ifdef HAVE_CPUID_H
86 # if !(defined(__SSE2__) || defined(_M_X64) || \
87 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) || \
88 !defined(__SSE4__)
89 // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
90 # include <cpuid.h>
92 static inline bool HasCPUIDBit(unsigned int level, CPUIDRegister reg,
93 unsigned int bit) {
94 unsigned int regs[4];
95 return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
96 (regs[reg] & bit);
98 # endif
100 # define HAVE_CPU_DETECTION
101 #else
103 # if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
104 // MSVC 2005 or later supports __cpuid by intrin.h
105 # include <intrin.h>
107 # define HAVE_CPU_DETECTION
108 # elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
110 // Define a function identical to MSVC function.
111 # ifdef __i386
112 static void __cpuid(int CPUInfo[4], int InfoType) {
113 asm("xchg %esi, %ebx\n"
114 "cpuid\n"
115 "movl %eax, (%edi)\n"
116 "movl %ebx, 4(%edi)\n"
117 "movl %ecx, 8(%edi)\n"
118 "movl %edx, 12(%edi)\n"
119 "xchg %esi, %ebx\n"
121 : "a"(InfoType), // %eax
122 "D"(CPUInfo) // %edi
123 : "%ecx", "%edx", "%esi");
125 # else
126 static void __cpuid(int CPUInfo[4], int InfoType) {
127 asm("xchg %rsi, %rbx\n"
128 "cpuid\n"
129 "movl %eax, (%rdi)\n"
130 "movl %ebx, 4(%rdi)\n"
131 "movl %ecx, 8(%rdi)\n"
132 "movl %edx, 12(%rdi)\n"
133 "xchg %rsi, %rbx\n"
135 : "a"(InfoType), // %eax
136 "D"(CPUInfo) // %rdi
137 : "%ecx", "%edx", "%rsi");
140 # define HAVE_CPU_DETECTION
141 # endif
142 # endif
144 # ifdef HAVE_CPU_DETECTION
145 static inline bool HasCPUIDBit(unsigned int level, CPUIDRegister reg,
146 unsigned int bit) {
147 // Check that the level in question is supported.
148 volatile int regs[4];
149 __cpuid((int*)regs, level & 0x80000000u);
150 if (unsigned(regs[0]) < level) return false;
151 __cpuid((int*)regs, level);
152 return !!(unsigned(regs[reg]) & bit);
154 # endif
155 #endif
157 #ifdef MOZ_ENABLE_FREETYPE
158 extern "C" {
160 void mozilla_AddRefSharedFTFace(void* aContext) {
161 if (aContext) {
162 static_cast<mozilla::gfx::SharedFTFace*>(aContext)->AddRef();
166 void mozilla_ReleaseSharedFTFace(void* aContext, void* aOwner) {
167 if (aContext) {
168 auto* sharedFace = static_cast<mozilla::gfx::SharedFTFace*>(aContext);
169 sharedFace->ForgetLockOwner(aOwner);
170 sharedFace->Release();
174 void mozilla_ForgetSharedFTFaceLockOwner(void* aContext, void* aOwner) {
175 static_cast<mozilla::gfx::SharedFTFace*>(aContext)->ForgetLockOwner(aOwner);
178 int mozilla_LockSharedFTFace(void* aContext,
179 void* aOwner) MOZ_NO_THREAD_SAFETY_ANALYSIS {
180 return int(static_cast<mozilla::gfx::SharedFTFace*>(aContext)->Lock(aOwner));
183 void mozilla_UnlockSharedFTFace(void* aContext) MOZ_NO_THREAD_SAFETY_ANALYSIS {
184 static_cast<mozilla::gfx::SharedFTFace*>(aContext)->Unlock();
187 FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
188 int32_t aFlags) {
189 return mozilla::gfx::Factory::LoadFTGlyph(aFace, aGlyphIndex, aFlags);
192 void mozilla_LockFTLibrary(FT_Library aFTLibrary) {
193 mozilla::gfx::Factory::LockFTLibrary(aFTLibrary);
196 void mozilla_UnlockFTLibrary(FT_Library aFTLibrary) {
197 mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary);
200 #endif
202 namespace mozilla::gfx {
204 #ifdef MOZ_ENABLE_FREETYPE
205 FT_Library Factory::mFTLibrary = nullptr;
206 StaticMutex Factory::mFTLock;
208 already_AddRefed<SharedFTFace> FTUserFontData::CloneFace(int aFaceIndex) {
209 if (mFontData) {
210 RefPtr<SharedFTFace> face = Factory::NewSharedFTFaceFromData(
211 nullptr, mFontData, mLength, aFaceIndex, this);
212 if (!face ||
213 (FT_Select_Charmap(face->GetFace(), FT_ENCODING_UNICODE) != FT_Err_Ok &&
214 FT_Select_Charmap(face->GetFace(), FT_ENCODING_MS_SYMBOL) !=
215 FT_Err_Ok)) {
216 return nullptr;
218 return face.forget();
220 FT_Face face = Factory::NewFTFace(nullptr, mFilename.c_str(), aFaceIndex);
221 if (face) {
222 return MakeAndAddRef<SharedFTFace>(face, this);
224 return nullptr;
226 #endif
228 #ifdef WIN32
229 // Note: mDeviceLock must be held when mutating these values.
230 static uint32_t mDeviceSeq = 0;
231 StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
232 StaticRefPtr<ID2D1Device> Factory::mD2D1Device;
233 StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
234 StaticRefPtr<ID2D1DeviceContext> Factory::mMTDC;
235 StaticRefPtr<ID2D1DeviceContext> Factory::mOffMTDC;
236 bool Factory::mDWriteFactoryInitialized = false;
237 StaticRefPtr<IDWriteFontCollection> Factory::mDWriteSystemFonts;
238 StaticMutex Factory::mDeviceLock;
239 StaticMutex Factory::mDTDependencyLock;
240 #endif
242 bool Factory::mBGRSubpixelOrder = false;
244 mozilla::gfx::Config* Factory::sConfig = nullptr;
246 void Factory::Init(const Config& aConfig) {
247 MOZ_ASSERT(!sConfig);
248 sConfig = new Config(aConfig);
250 #ifdef XP_DARWIN
251 NativeFontResourceMac::RegisterMemoryReporter();
252 #else
253 NativeFontResource::RegisterMemoryReporter();
254 #endif
257 void Factory::ShutDown() {
258 if (sConfig) {
259 delete sConfig->mLogForwarder;
260 delete sConfig;
261 sConfig = nullptr;
264 #ifdef MOZ_ENABLE_FREETYPE
265 mFTLibrary = nullptr;
266 #endif
269 bool Factory::HasSSE2() {
270 #if defined(__SSE2__) || defined(_M_X64) || \
271 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
272 // gcc with -msse2 (default on OSX and x86-64)
273 // cl.exe with -arch:SSE2 (default on x64 compiler)
274 return true;
275 #elif defined(HAVE_CPU_DETECTION)
276 static enum {
277 UNINITIALIZED,
278 NO_SSE2,
279 HAS_SSE2
280 } sDetectionState = UNINITIALIZED;
282 if (sDetectionState == UNINITIALIZED) {
283 sDetectionState = HasCPUIDBit(1u, edx, (1u << 26)) ? HAS_SSE2 : NO_SSE2;
285 return sDetectionState == HAS_SSE2;
286 #else
287 return false;
288 #endif
291 bool Factory::HasSSE4() {
292 #if defined(__SSE4__)
293 // gcc with -msse2 (default on OSX and x86-64)
294 // cl.exe with -arch:SSE2 (default on x64 compiler)
295 return true;
296 #elif defined(HAVE_CPU_DETECTION)
297 static enum {
298 UNINITIALIZED,
299 NO_SSE4,
300 HAS_SSE4
301 } sDetectionState = UNINITIALIZED;
303 if (sDetectionState == UNINITIALIZED) {
304 sDetectionState = HasCPUIDBit(1u, ecx, (1u << 19)) ? HAS_SSE4 : NO_SSE4;
306 return sDetectionState == HAS_SSE4;
307 #else
308 return false;
309 #endif
312 // If the size is "reasonable", we want gfxCriticalError to assert, so
313 // this is the option set up for it.
314 inline int LoggerOptionsBasedOnSize(const IntSize& aSize) {
315 return CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize));
318 bool Factory::ReasonableSurfaceSize(const IntSize& aSize) {
319 return Factory::CheckSurfaceSize(aSize, kReasonableSurfaceSize);
322 bool Factory::AllowedSurfaceSize(const IntSize& aSize) {
323 if (sConfig) {
324 return Factory::CheckSurfaceSize(aSize, sConfig->mMaxTextureSize,
325 sConfig->mMaxAllocSize);
328 return CheckSurfaceSize(aSize);
331 bool Factory::CheckSurfaceSize(const IntSize& sz, int32_t extentLimit,
332 int32_t allocLimit) {
333 if (sz.width <= 0 || sz.height <= 0) {
334 return false;
337 // reject images with sides bigger than limit
338 if (extentLimit && (sz.width > extentLimit || sz.height > extentLimit)) {
339 gfxDebug() << "Surface size too large (exceeds extent limit)!";
340 return false;
343 // assuming 4 bytes per pixel, make sure the allocation size
344 // doesn't overflow a int32_t either
345 CheckedInt<int32_t> stride = GetAlignedStride<16>(sz.width, 4);
346 if (!stride.isValid() || stride.value() == 0) {
347 gfxDebug() << "Surface size too large (stride overflows int32_t)!";
348 return false;
351 CheckedInt<int32_t> numBytes = stride * sz.height;
352 if (!numBytes.isValid()) {
353 gfxDebug()
354 << "Surface size too large (allocation size would overflow int32_t)!";
355 return false;
358 if (allocLimit && allocLimit < numBytes.value()) {
359 gfxDebug() << "Surface size too large (exceeds allocation limit)!";
360 return false;
363 return true;
366 already_AddRefed<DrawTarget> Factory::CreateDrawTarget(BackendType aBackend,
367 const IntSize& aSize,
368 SurfaceFormat aFormat) {
369 if (!AllowedSurfaceSize(aSize)) {
370 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
371 << "Failed to allocate a surface due to invalid size (CDT) " << aSize;
372 return nullptr;
375 RefPtr<DrawTarget> retVal;
376 switch (aBackend) {
377 #ifdef WIN32
378 case BackendType::DIRECT2D1_1: {
379 RefPtr<DrawTargetD2D1> newTarget;
380 newTarget = new DrawTargetD2D1();
381 if (newTarget->Init(aSize, aFormat)) {
382 retVal = newTarget;
384 break;
386 #endif
387 case BackendType::SKIA: {
388 RefPtr<DrawTargetSkia> newTarget;
389 newTarget = new DrawTargetSkia();
390 if (newTarget->Init(aSize, aFormat)) {
391 retVal = newTarget;
393 break;
395 #ifdef USE_CAIRO
396 case BackendType::CAIRO: {
397 RefPtr<DrawTargetCairo> newTarget;
398 newTarget = new DrawTargetCairo();
399 if (newTarget->Init(aSize, aFormat)) {
400 retVal = newTarget;
402 break;
404 #endif
405 default:
406 return nullptr;
409 if (!retVal) {
410 // Failed
411 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
412 << "Failed to create DrawTarget, Type: " << int(aBackend)
413 << " Size: " << aSize;
416 return retVal.forget();
419 already_AddRefed<PathBuilder> Factory::CreatePathBuilder(BackendType aBackend,
420 FillRule aFillRule) {
421 switch (aBackend) {
422 #ifdef WIN32
423 case BackendType::DIRECT2D1_1:
424 return PathBuilderD2D::Create(aFillRule);
425 #endif
426 case BackendType::SKIA:
427 case BackendType::WEBGL:
428 return PathBuilderSkia::Create(aFillRule);
429 #ifdef USE_CAIRO
430 case BackendType::CAIRO:
431 return PathBuilderCairo::Create(aFillRule);
432 #endif
433 default:
434 gfxCriticalNote << "Invalid PathBuilder type specified: "
435 << (int)aBackend;
436 return nullptr;
440 already_AddRefed<PathBuilder> Factory::CreateSimplePathBuilder() {
441 return CreatePathBuilder(BackendType::SKIA);
444 already_AddRefed<DrawTarget> Factory::CreateRecordingDrawTarget(
445 DrawEventRecorder* aRecorder, DrawTarget* aDT, IntRect aRect) {
446 return MakeAndAddRef<DrawTargetRecording>(aRecorder, aDT, aRect);
449 already_AddRefed<DrawTarget> Factory::CreateDrawTargetForData(
450 BackendType aBackend, unsigned char* aData, const IntSize& aSize,
451 int32_t aStride, SurfaceFormat aFormat, bool aUninitialized) {
452 MOZ_ASSERT(aData);
453 if (!AllowedSurfaceSize(aSize)) {
454 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
455 << "Failed to allocate a surface due to invalid size (DTD) " << aSize;
456 return nullptr;
459 RefPtr<DrawTarget> retVal;
461 switch (aBackend) {
462 case BackendType::SKIA: {
463 RefPtr<DrawTargetSkia> newTarget;
464 newTarget = new DrawTargetSkia();
465 if (newTarget->Init(aData, aSize, aStride, aFormat, aUninitialized)) {
466 retVal = newTarget;
468 break;
470 #ifdef USE_CAIRO
471 case BackendType::CAIRO: {
472 RefPtr<DrawTargetCairo> newTarget;
473 newTarget = new DrawTargetCairo();
474 if (newTarget->Init(aData, aSize, aStride, aFormat)) {
475 retVal = std::move(newTarget);
477 break;
479 #endif
480 default:
481 gfxCriticalNote << "Invalid draw target type specified: "
482 << (int)aBackend;
483 return nullptr;
486 if (!retVal) {
487 gfxCriticalNote << "Failed to create DrawTarget, Type: " << int(aBackend)
488 << " Size: " << aSize << ", Data: " << hexa((void*)aData)
489 << ", Stride: " << aStride;
492 return retVal.forget();
495 already_AddRefed<DrawTarget> Factory::CreateOffsetDrawTarget(
496 DrawTarget* aDrawTarget, IntPoint aTileOrigin) {
497 RefPtr<DrawTargetOffset> dt = new DrawTargetOffset();
499 if (!dt->Init(aDrawTarget, aTileOrigin)) {
500 return nullptr;
503 return dt.forget();
506 bool Factory::DoesBackendSupportDataDrawtarget(BackendType aType) {
507 switch (aType) {
508 case BackendType::DIRECT2D:
509 case BackendType::DIRECT2D1_1:
510 case BackendType::RECORDING:
511 case BackendType::NONE:
512 case BackendType::BACKEND_LAST:
513 case BackendType::WEBRENDER_TEXT:
514 case BackendType::WEBGL:
515 return false;
516 case BackendType::CAIRO:
517 case BackendType::SKIA:
518 return true;
521 return false;
524 uint32_t Factory::GetMaxSurfaceSize(BackendType aType) {
525 switch (aType) {
526 case BackendType::CAIRO:
527 return DrawTargetCairo::GetMaxSurfaceSize();
528 case BackendType::SKIA:
529 return DrawTargetSkia::GetMaxSurfaceSize();
530 #ifdef WIN32
531 case BackendType::DIRECT2D1_1:
532 return DrawTargetD2D1::GetMaxSurfaceSize();
533 #endif
534 default:
535 return 0;
539 already_AddRefed<NativeFontResource> Factory::CreateNativeFontResource(
540 uint8_t* aData, uint32_t aSize, FontType aFontType, void* aFontContext) {
541 switch (aFontType) {
542 #ifdef WIN32
543 case FontType::DWRITE:
544 return NativeFontResourceDWrite::Create(aData, aSize);
545 case FontType::GDI:
546 return NativeFontResourceGDI::Create(aData, aSize);
547 #elif defined(XP_DARWIN)
548 case FontType::MAC:
549 return NativeFontResourceMac::Create(aData, aSize);
550 #elif defined(MOZ_WIDGET_GTK)
551 case FontType::FONTCONFIG:
552 return NativeFontResourceFontconfig::Create(
553 aData, aSize, static_cast<FT_Library>(aFontContext));
554 #elif defined(MOZ_WIDGET_ANDROID)
555 case FontType::FREETYPE:
556 return NativeFontResourceFreeType::Create(
557 aData, aSize, static_cast<FT_Library>(aFontContext));
558 #endif
559 default:
560 gfxWarning()
561 << "Unable to create requested font resource from truetype data";
562 return nullptr;
566 already_AddRefed<UnscaledFont> Factory::CreateUnscaledFontFromFontDescriptor(
567 FontType aType, const uint8_t* aData, uint32_t aDataLength,
568 uint32_t aIndex) {
569 switch (aType) {
570 #ifdef WIN32
571 case FontType::DWRITE:
572 return UnscaledFontDWrite::CreateFromFontDescriptor(aData, aDataLength,
573 aIndex);
574 case FontType::GDI:
575 return UnscaledFontGDI::CreateFromFontDescriptor(aData, aDataLength,
576 aIndex);
577 #elif defined(XP_DARWIN)
578 case FontType::MAC:
579 return UnscaledFontMac::CreateFromFontDescriptor(aData, aDataLength,
580 aIndex);
581 #elif defined(MOZ_WIDGET_GTK)
582 case FontType::FONTCONFIG:
583 return UnscaledFontFontconfig::CreateFromFontDescriptor(
584 aData, aDataLength, aIndex);
585 #elif defined(MOZ_WIDGET_ANDROID)
586 case FontType::FREETYPE:
587 return UnscaledFontFreeType::CreateFromFontDescriptor(aData, aDataLength,
588 aIndex);
589 #endif
590 default:
591 gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
592 return nullptr;
596 #ifdef XP_DARWIN
597 already_AddRefed<ScaledFont> Factory::CreateScaledFontForMacFont(
598 CGFontRef aCGFont, const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
599 bool aUseFontSmoothing, bool aApplySyntheticBold, bool aHasColorGlyphs) {
600 return MakeAndAddRef<ScaledFontMac>(aCGFont, aUnscaledFont, aSize, false,
601 aUseFontSmoothing, aApplySyntheticBold,
602 aHasColorGlyphs);
604 #endif
606 #ifdef MOZ_WIDGET_GTK
607 already_AddRefed<ScaledFont> Factory::CreateScaledFontForFontconfigFont(
608 const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
609 RefPtr<SharedFTFace> aFace, FcPattern* aPattern) {
610 return MakeAndAddRef<ScaledFontFontconfig>(std::move(aFace), aPattern,
611 aUnscaledFont, aSize);
613 #endif
615 #ifdef MOZ_WIDGET_ANDROID
616 already_AddRefed<ScaledFont> Factory::CreateScaledFontForFreeTypeFont(
617 const RefPtr<UnscaledFont>& aUnscaledFont, Float aSize,
618 RefPtr<SharedFTFace> aFace, bool aApplySyntheticBold) {
619 return MakeAndAddRef<ScaledFontFreeType>(std::move(aFace), aUnscaledFont,
620 aSize, aApplySyntheticBold);
622 #endif
624 void Factory::SetBGRSubpixelOrder(bool aBGR) { mBGRSubpixelOrder = aBGR; }
626 bool Factory::GetBGRSubpixelOrder() { return mBGRSubpixelOrder; }
628 #ifdef MOZ_ENABLE_FREETYPE
629 SharedFTFace::SharedFTFace(FT_Face aFace, SharedFTFaceData* aData)
630 : mFace(aFace),
631 mData(aData),
632 mLock("SharedFTFace::mLock"),
633 mLastLockOwner(nullptr) {
634 if (mData) {
635 mData->BindData();
639 SharedFTFace::~SharedFTFace() {
640 Factory::ReleaseFTFace(mFace);
641 if (mData) {
642 mData->ReleaseData();
646 void Factory::SetFTLibrary(FT_Library aFTLibrary) { mFTLibrary = aFTLibrary; }
648 FT_Library Factory::GetFTLibrary() {
649 MOZ_ASSERT(mFTLibrary);
650 return mFTLibrary;
653 FT_Library Factory::NewFTLibrary() {
654 FT_Library library;
655 if (FT_Init_FreeType(&library) != FT_Err_Ok) {
656 return nullptr;
658 return library;
661 void Factory::ReleaseFTLibrary(FT_Library aFTLibrary) {
662 FT_Done_FreeType(aFTLibrary);
665 void Factory::LockFTLibrary(FT_Library aFTLibrary)
666 MOZ_CAPABILITY_ACQUIRE(mFTLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
667 mFTLock.Lock();
670 void Factory::UnlockFTLibrary(FT_Library aFTLibrary)
671 MOZ_CAPABILITY_RELEASE(mFTLock) MOZ_NO_THREAD_SAFETY_ANALYSIS {
672 mFTLock.Unlock();
675 FT_Face Factory::NewFTFace(FT_Library aFTLibrary, const char* aFileName,
676 int aFaceIndex) {
677 StaticMutexAutoLock lock(mFTLock);
678 if (!aFTLibrary) {
679 aFTLibrary = mFTLibrary;
681 FT_Face face;
682 if (FT_New_Face(aFTLibrary, aFileName, aFaceIndex, &face) != FT_Err_Ok) {
683 return nullptr;
685 return face;
688 already_AddRefed<SharedFTFace> Factory::NewSharedFTFace(FT_Library aFTLibrary,
689 const char* aFilename,
690 int aFaceIndex) {
691 FT_Face face = NewFTFace(aFTLibrary, aFilename, aFaceIndex);
692 if (!face) {
693 return nullptr;
696 RefPtr<FTUserFontData> data;
697 # ifdef ANDROID
698 // If the font has variations, we may later need to "clone" it in
699 // UnscaledFontFreeType::CreateScaledFont. To support this, we attach an
700 // FTUserFontData that records the filename used to instantiate the face.
701 if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
702 data = new FTUserFontData(aFilename);
704 # endif
705 return MakeAndAddRef<SharedFTFace>(face, data);
708 FT_Face Factory::NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData,
709 size_t aDataSize, int aFaceIndex) {
710 StaticMutexAutoLock lock(mFTLock);
711 if (!aFTLibrary) {
712 aFTLibrary = mFTLibrary;
714 FT_Face face;
715 if (FT_New_Memory_Face(aFTLibrary, aData, aDataSize, aFaceIndex, &face) !=
716 FT_Err_Ok) {
717 return nullptr;
719 return face;
722 already_AddRefed<SharedFTFace> Factory::NewSharedFTFaceFromData(
723 FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize,
724 int aFaceIndex, SharedFTFaceData* aSharedData) {
725 if (FT_Face face =
726 NewFTFaceFromData(aFTLibrary, aData, aDataSize, aFaceIndex)) {
727 return MakeAndAddRef<SharedFTFace>(face, aSharedData);
728 } else {
729 return nullptr;
733 void Factory::ReleaseFTFace(FT_Face aFace) {
734 StaticMutexAutoLock lock(mFTLock);
735 FT_Done_Face(aFace);
738 FT_Error Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
739 int32_t aFlags) {
740 StaticMutexAutoLock lock(mFTLock);
741 return FT_Load_Glyph(aFace, aGlyphIndex, aFlags);
743 #endif
745 AutoSerializeWithMoz2D::AutoSerializeWithMoz2D(BackendType aBackendType) {
746 #ifdef WIN32
747 // We use a multi-threaded ID2D1Factory1, so that makes the calls through the
748 // Direct2D API thread-safe. However, if the Moz2D objects are using Direct3D
749 // resources we need to make sure that calls through the Direct3D or DXGI API
750 // use the Direct2D synchronization. It's possible that this should be pushed
751 // down into the TextureD3D11 objects, so that we always use this.
752 if (aBackendType == BackendType::DIRECT2D1_1 ||
753 aBackendType == BackendType::DIRECT2D) {
754 auto factory = D2DFactory();
755 if (factory) {
756 factory->QueryInterface(
757 static_cast<ID2D1Multithread**>(getter_AddRefs(mMT)));
758 if (mMT) {
759 mMT->Enter();
763 #endif
766 AutoSerializeWithMoz2D::~AutoSerializeWithMoz2D() {
767 #ifdef WIN32
768 if (mMT) {
769 mMT->Leave();
771 #endif
774 #ifdef WIN32
775 already_AddRefed<DrawTarget> Factory::CreateDrawTargetForD3D11Texture(
776 ID3D11Texture2D* aTexture, SurfaceFormat aFormat) {
777 MOZ_ASSERT(aTexture);
779 RefPtr<DrawTargetD2D1> newTarget;
781 newTarget = new DrawTargetD2D1();
782 if (newTarget->Init(aTexture, aFormat)) {
783 RefPtr<DrawTarget> retVal = newTarget;
784 return retVal.forget();
787 gfxWarning() << "Failed to create draw target for D3D11 texture.";
789 // Failed
790 return nullptr;
793 bool Factory::SetDirect3D11Device(ID3D11Device* aDevice) {
794 MOZ_RELEASE_ASSERT(NS_IsMainThread());
796 // D2DFactory already takes the device lock, so we get the factory before
797 // entering the lock scope.
798 RefPtr<ID2D1Factory1> factory = D2DFactory();
800 StaticMutexAutoLock lock(mDeviceLock);
802 mD3D11Device = aDevice;
804 if (mD2D1Device) {
805 mD2D1Device = nullptr;
806 mMTDC = nullptr;
807 mOffMTDC = nullptr;
810 if (!aDevice) {
811 return true;
814 RefPtr<IDXGIDevice> device;
815 aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(device));
817 RefPtr<ID2D1Device> d2dDevice;
818 HRESULT hr = factory->CreateDevice(device, getter_AddRefs(d2dDevice));
819 if (FAILED(hr)) {
820 gfxCriticalError()
821 << "[D2D1] Failed to create gfx factory's D2D1 device, code: "
822 << hexa(hr);
824 mD3D11Device = nullptr;
825 return false;
828 mDeviceSeq++;
829 mD2D1Device = d2dDevice;
830 return true;
833 RefPtr<ID3D11Device> Factory::GetDirect3D11Device() {
834 StaticMutexAutoLock lock(mDeviceLock);
835 return mD3D11Device;
838 RefPtr<ID2D1Device> Factory::GetD2D1Device(uint32_t* aOutSeqNo) {
839 StaticMutexAutoLock lock(mDeviceLock);
840 if (aOutSeqNo) {
841 *aOutSeqNo = mDeviceSeq;
843 return mD2D1Device.get();
846 bool Factory::HasD2D1Device() { return !!GetD2D1Device(); }
848 RefPtr<IDWriteFactory> Factory::GetDWriteFactory() {
849 StaticMutexAutoLock lock(mDeviceLock);
850 return mDWriteFactory;
853 RefPtr<IDWriteFactory> Factory::EnsureDWriteFactory() {
854 StaticMutexAutoLock lock(mDeviceLock);
856 if (mDWriteFactoryInitialized) {
857 return mDWriteFactory;
860 mDWriteFactoryInitialized = true;
862 HMODULE dwriteModule = LoadLibrarySystem32(L"dwrite.dll");
863 decltype(DWriteCreateFactory)* createDWriteFactory =
864 (decltype(DWriteCreateFactory)*)GetProcAddress(dwriteModule,
865 "DWriteCreateFactory");
867 if (!createDWriteFactory) {
868 gfxWarning() << "Failed to locate DWriteCreateFactory function.";
869 return nullptr;
872 HRESULT hr =
873 createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
874 reinterpret_cast<IUnknown**>(&mDWriteFactory));
876 if (FAILED(hr)) {
877 gfxWarning() << "Failed to create DWrite Factory.";
880 return mDWriteFactory;
883 RefPtr<IDWriteFontCollection> Factory::GetDWriteSystemFonts(bool aUpdate) {
884 StaticMutexAutoLock lock(mDeviceLock);
886 if (mDWriteSystemFonts && !aUpdate) {
887 return mDWriteSystemFonts;
890 if (!mDWriteFactory) {
891 if ((rand() & 0x3f) == 0) {
892 gfxCriticalError(int(gfx::LogOptions::AssertOnCall))
893 << "Failed to create DWrite factory";
894 } else {
895 gfxWarning() << "Failed to create DWrite factory";
898 return nullptr;
901 RefPtr<IDWriteFontCollection> systemFonts;
902 HRESULT hr =
903 mDWriteFactory->GetSystemFontCollection(getter_AddRefs(systemFonts));
904 if (FAILED(hr) || !systemFonts) {
905 // only crash some of the time so those experiencing this problem
906 // don't stop using Firefox
907 if ((rand() & 0x3f) == 0) {
908 gfxCriticalError(int(gfx::LogOptions::AssertOnCall))
909 << "Failed to create DWrite system font collection";
910 } else {
911 gfxWarning() << "Failed to create DWrite system font collection";
913 return nullptr;
915 mDWriteSystemFonts = systemFonts;
917 return mDWriteSystemFonts;
920 RefPtr<ID2D1DeviceContext> Factory::GetD2DDeviceContext() {
921 StaticRefPtr<ID2D1DeviceContext>* ptr;
923 if (NS_IsMainThread()) {
924 ptr = &mMTDC;
925 } else {
926 ptr = &mOffMTDC;
929 if (*ptr) {
930 return *ptr;
933 RefPtr<ID2D1Device> device = GetD2D1Device();
935 if (!device) {
936 return nullptr;
939 RefPtr<ID2D1DeviceContext> dc;
940 HRESULT hr = device->CreateDeviceContext(
941 D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
942 getter_AddRefs(dc));
944 if (FAILED(hr)) {
945 gfxCriticalError() << "Failed to create global device context";
946 return nullptr;
949 *ptr = dc;
951 return *ptr;
954 bool Factory::SupportsD2D1() { return !!D2DFactory(); }
956 BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
957 void Factory::SetSystemTextQuality(uint8_t aQuality) {
958 sSystemTextQuality = aQuality;
961 uint64_t Factory::GetD2DVRAMUsageDrawTarget() {
962 return DrawTargetD2D1::mVRAMUsageDT;
965 uint64_t Factory::GetD2DVRAMUsageSourceSurface() {
966 return DrawTargetD2D1::mVRAMUsageSS;
969 void Factory::D2DCleanup() {
970 StaticMutexAutoLock lock(mDeviceLock);
971 if (mD2D1Device) {
972 mD2D1Device = nullptr;
974 DrawTargetD2D1::CleanupD2D();
977 already_AddRefed<ScaledFont> Factory::CreateScaledFontForDWriteFont(
978 IDWriteFontFace* aFontFace, const gfxFontStyle* aStyle,
979 const RefPtr<UnscaledFont>& aUnscaledFont, float aSize,
980 bool aUseEmbeddedBitmap, bool aUseMultistrikeBold, bool aGDIForced) {
981 return MakeAndAddRef<ScaledFontDWrite>(
982 aFontFace, aUnscaledFont, aSize, aUseEmbeddedBitmap, aUseMultistrikeBold,
983 aGDIForced, aStyle);
986 already_AddRefed<ScaledFont> Factory::CreateScaledFontForGDIFont(
987 const void* aLogFont, const RefPtr<UnscaledFont>& aUnscaledFont,
988 Float aSize) {
989 return MakeAndAddRef<ScaledFontWin>(static_cast<const LOGFONT*>(aLogFont),
990 aUnscaledFont, aSize);
992 #endif // WIN32
994 already_AddRefed<DrawTarget> Factory::CreateDrawTargetWithSkCanvas(
995 SkCanvas* aCanvas) {
996 RefPtr<DrawTargetSkia> newTarget = new DrawTargetSkia();
997 if (!newTarget->Init(aCanvas)) {
998 return nullptr;
1000 return newTarget.forget();
1003 void Factory::PurgeAllCaches() {}
1005 already_AddRefed<DrawTarget> Factory::CreateDrawTargetForCairoSurface(
1006 cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat) {
1007 if (!AllowedSurfaceSize(aSize)) {
1008 gfxWarning() << "Allowing surface with invalid size (Cairo) " << aSize;
1011 RefPtr<DrawTarget> retVal;
1013 #ifdef USE_CAIRO
1014 RefPtr<DrawTargetCairo> newTarget = new DrawTargetCairo();
1016 if (newTarget->Init(aSurface, aSize, aFormat)) {
1017 retVal = newTarget;
1019 #endif
1020 return retVal.forget();
1023 already_AddRefed<SourceSurface> Factory::CreateSourceSurfaceForCairoSurface(
1024 cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat) {
1025 if (aSize.width <= 0 || aSize.height <= 0) {
1026 gfxWarning() << "Can't create a SourceSurface without a valid size";
1027 return nullptr;
1030 #ifdef USE_CAIRO
1031 return MakeAndAddRef<SourceSurfaceCairo>(aSurface, aSize, aFormat);
1032 #else
1033 return nullptr;
1034 #endif
1037 already_AddRefed<DataSourceSurface> Factory::CreateWrappingDataSourceSurface(
1038 uint8_t* aData, int32_t aStride, const IntSize& aSize,
1039 SurfaceFormat aFormat,
1040 SourceSurfaceDeallocator aDeallocator /* = nullptr */,
1041 void* aClosure /* = nullptr */) {
1042 // Just check for negative/zero size instead of the full AllowedSurfaceSize()
1043 // - since the data is already allocated we do not need to check for a
1044 // possible overflow - it already worked.
1045 if (aSize.width <= 0 || aSize.height <= 0) {
1046 return nullptr;
1048 if (!aDeallocator && aClosure) {
1049 return nullptr;
1052 MOZ_ASSERT(aData);
1054 RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
1055 newSurf->InitWrappingData(aData, aSize, aStride, aFormat, aDeallocator,
1056 aClosure);
1058 return newSurf.forget();
1061 already_AddRefed<DataSourceSurface> Factory::CreateDataSourceSurface(
1062 const IntSize& aSize, SurfaceFormat aFormat, bool aZero) {
1063 if (!AllowedSurfaceSize(aSize)) {
1064 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
1065 << "Failed to allocate a surface due to invalid size (DSS) " << aSize;
1066 return nullptr;
1069 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1070 bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
1071 uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
1073 RefPtr<SourceSurfaceAlignedRawData> newSurf =
1074 new SourceSurfaceAlignedRawData();
1075 if (newSurf->Init(aSize, aFormat, clearSurface, clearValue)) {
1076 return newSurf.forget();
1079 gfxWarning() << "CreateDataSourceSurface failed in init";
1080 return nullptr;
1083 already_AddRefed<DataSourceSurface> Factory::CreateDataSourceSurfaceWithStride(
1084 const IntSize& aSize, SurfaceFormat aFormat, int32_t aStride, bool aZero) {
1085 if (!AllowedSurfaceSize(aSize) ||
1086 aStride < aSize.width * BytesPerPixel(aFormat)) {
1087 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
1088 << "CreateDataSourceSurfaceWithStride failed with bad stride "
1089 << aStride << ", " << aSize << ", " << aFormat;
1090 return nullptr;
1093 // Skia doesn't support RGBX, so memset RGBX to 0xFF
1094 bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
1095 uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
1097 RefPtr<SourceSurfaceAlignedRawData> newSurf =
1098 new SourceSurfaceAlignedRawData();
1099 if (newSurf->Init(aSize, aFormat, clearSurface, clearValue, aStride)) {
1100 return newSurf.forget();
1103 gfxCriticalError(LoggerOptionsBasedOnSize(aSize))
1104 << "CreateDataSourceSurfaceWithStride failed to initialize " << aSize
1105 << ", " << aFormat << ", " << aStride << ", " << aZero;
1106 return nullptr;
1109 already_AddRefed<DataSourceSurface> Factory::CopyDataSourceSurface(
1110 DataSourceSurface* aSource) {
1111 // Don't worry too much about speed.
1112 MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 ||
1113 aSource->GetFormat() == SurfaceFormat::R8G8B8X8 ||
1114 aSource->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1115 aSource->GetFormat() == SurfaceFormat::B8G8R8X8);
1117 DataSourceSurface::ScopedMap srcMap(aSource, DataSourceSurface::READ);
1118 if (NS_WARN_IF(!srcMap.IsMapped())) {
1119 MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface.");
1120 return nullptr;
1123 IntSize size = aSource->GetSize();
1124 SurfaceFormat format = aSource->GetFormat();
1126 RefPtr<DataSourceSurface> dst = CreateDataSourceSurfaceWithStride(
1127 size, format, srcMap.GetStride(), /* aZero */ false);
1128 if (NS_WARN_IF(!dst)) {
1129 return nullptr;
1132 DataSourceSurface::ScopedMap dstMap(dst, DataSourceSurface::WRITE);
1133 if (NS_WARN_IF(!dstMap.IsMapped())) {
1134 MOZ_ASSERT_UNREACHABLE("CopyDataSourceSurface: Failed to map surface.");
1135 return nullptr;
1138 SwizzleData(srcMap.GetData(), srcMap.GetStride(), format, dstMap.GetData(),
1139 dstMap.GetStride(), format, size);
1140 return dst.forget();
1143 void Factory::CopyDataSourceSurface(DataSourceSurface* aSource,
1144 DataSourceSurface* aDest) {
1145 // Don't worry too much about speed.
1146 MOZ_ASSERT(aSource->GetSize() == aDest->GetSize());
1147 MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 ||
1148 aSource->GetFormat() == SurfaceFormat::R8G8B8X8 ||
1149 aSource->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1150 aSource->GetFormat() == SurfaceFormat::B8G8R8X8);
1151 MOZ_ASSERT(aDest->GetFormat() == SurfaceFormat::R8G8B8A8 ||
1152 aDest->GetFormat() == SurfaceFormat::R8G8B8X8 ||
1153 aDest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1154 aDest->GetFormat() == SurfaceFormat::B8G8R8X8 ||
1155 aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16);
1157 DataSourceSurface::MappedSurface srcMap;
1158 DataSourceSurface::MappedSurface destMap;
1159 if (!aSource->Map(DataSourceSurface::MapType::READ, &srcMap) ||
1160 !aDest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
1161 MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface.");
1162 return;
1165 SwizzleData(srcMap.mData, srcMap.mStride, aSource->GetFormat(), destMap.mData,
1166 destMap.mStride, aDest->GetFormat(), aSource->GetSize());
1168 aSource->Unmap();
1169 aDest->Unmap();
1172 #ifdef WIN32
1174 /* static */
1175 already_AddRefed<DataSourceSurface>
1176 Factory::CreateBGRA8DataSourceSurfaceForD3D11Texture(
1177 ID3D11Texture2D* aSrcTexture, uint32_t aArrayIndex) {
1178 D3D11_TEXTURE2D_DESC srcDesc = {0};
1179 aSrcTexture->GetDesc(&srcDesc);
1181 RefPtr<gfx::DataSourceSurface> destTexture =
1182 gfx::Factory::CreateDataSourceSurface(
1183 IntSize(srcDesc.Width, srcDesc.Height), gfx::SurfaceFormat::B8G8R8A8);
1184 if (NS_WARN_IF(!destTexture)) {
1185 return nullptr;
1187 if (!ReadbackTexture(destTexture, aSrcTexture, aArrayIndex)) {
1188 return nullptr;
1190 return destTexture.forget();
1193 /* static */ nsresult Factory::CreateSdbForD3D11Texture(
1194 ID3D11Texture2D* aSrcTexture, const IntSize& aSrcSize,
1195 layers::SurfaceDescriptorBuffer& aSdBuffer,
1196 const std::function<layers::MemoryOrShmem(uint32_t)>& aAllocate) {
1197 D3D11_TEXTURE2D_DESC srcDesc = {0};
1198 aSrcTexture->GetDesc(&srcDesc);
1199 if (srcDesc.Width != uint32_t(aSrcSize.width) ||
1200 srcDesc.Height != uint32_t(aSrcSize.height) ||
1201 srcDesc.Format != DXGI_FORMAT_B8G8R8A8_UNORM) {
1202 return NS_ERROR_NOT_IMPLEMENTED;
1205 const auto format = gfx::SurfaceFormat::B8G8R8A8;
1206 uint8_t* buffer = nullptr;
1207 int32_t stride = 0;
1208 nsresult rv = layers::Image::AllocateSurfaceDescriptorBufferRgb(
1209 aSrcSize, format, buffer, aSdBuffer, stride, aAllocate);
1210 if (NS_WARN_IF(NS_FAILED(rv))) {
1211 return rv;
1214 if (!ReadbackTexture(buffer, stride, aSrcTexture)) {
1215 return NS_ERROR_FAILURE;
1218 return NS_OK;
1221 /* static */
1222 template <typename DestTextureT>
1223 bool Factory::ConvertSourceAndRetryReadback(DestTextureT* aDestCpuTexture,
1224 ID3D11Texture2D* aSrcTexture,
1225 uint32_t aArrayIndex) {
1226 RefPtr<ID3D11Device> device;
1227 aSrcTexture->GetDevice(getter_AddRefs(device));
1228 if (!device) {
1229 gfxWarning() << "Failed to get D3D11 device from source texture";
1230 return false;
1233 nsAutoCString error;
1234 std::unique_ptr<DXVA2Manager> manager(
1235 DXVA2Manager::CreateD3D11DXVA(nullptr, error, device));
1236 if (!manager) {
1237 gfxWarning() << "Failed to create DXVA2 manager!";
1238 return false;
1241 RefPtr<ID3D11Texture2D> newSrcTexture;
1242 HRESULT hr = manager->CopyToBGRATexture(aSrcTexture, aArrayIndex,
1243 getter_AddRefs(newSrcTexture));
1244 if (FAILED(hr)) {
1245 gfxWarning() << "Failed to copy to BGRA texture.";
1246 return false;
1249 return ReadbackTexture(aDestCpuTexture, newSrcTexture);
1252 /* static */
1253 bool Factory::ReadbackTexture(layers::TextureData* aDestCpuTexture,
1254 ID3D11Texture2D* aSrcTexture) {
1255 layers::MappedTextureData mappedData;
1256 if (!aDestCpuTexture->BorrowMappedData(mappedData)) {
1257 gfxWarning() << "Could not access in-memory texture";
1258 return false;
1261 D3D11_TEXTURE2D_DESC srcDesc = {0};
1262 aSrcTexture->GetDesc(&srcDesc);
1264 // Special case: If the source and destination have different formats and the
1265 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1266 if ((srcDesc.Format != DXGIFormat(mappedData.format)) &&
1267 (mappedData.format == SurfaceFormat::B8G8R8A8)) {
1268 return ConvertSourceAndRetryReadback(aDestCpuTexture, aSrcTexture);
1271 if ((IntSize(srcDesc.Width, srcDesc.Height) != mappedData.size) ||
1272 (srcDesc.Format != DXGIFormat(mappedData.format))) {
1273 gfxWarning() << "Attempted readback between incompatible textures";
1274 return false;
1277 return ReadbackTexture(mappedData.data, mappedData.stride, aSrcTexture);
1280 /* static */
1281 bool Factory::ReadbackTexture(DataSourceSurface* aDestCpuTexture,
1282 ID3D11Texture2D* aSrcTexture,
1283 uint32_t aArrayIndex) {
1284 D3D11_TEXTURE2D_DESC srcDesc = {0};
1285 aSrcTexture->GetDesc(&srcDesc);
1287 // Special case: If the source and destination have different formats and the
1288 // destination is B8G8R8A8 then convert the source to B8G8R8A8 and readback.
1289 if ((srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat())) &&
1290 (aDestCpuTexture->GetFormat() == SurfaceFormat::B8G8R8A8)) {
1291 return ConvertSourceAndRetryReadback(aDestCpuTexture, aSrcTexture,
1292 aArrayIndex);
1295 if ((IntSize(srcDesc.Width, srcDesc.Height) != aDestCpuTexture->GetSize()) ||
1296 (srcDesc.Format != DXGIFormat(aDestCpuTexture->GetFormat()))) {
1297 gfxWarning() << "Attempted readback between incompatible textures";
1298 return false;
1301 gfx::DataSourceSurface::MappedSurface mappedSurface;
1302 if (!aDestCpuTexture->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) {
1303 return false;
1306 MOZ_ASSERT(aArrayIndex == 0);
1308 bool ret =
1309 ReadbackTexture(mappedSurface.mData, mappedSurface.mStride, aSrcTexture);
1310 aDestCpuTexture->Unmap();
1311 return ret;
1314 /* static */
1315 bool Factory::ReadbackTexture(uint8_t* aDestData, int32_t aDestStride,
1316 ID3D11Texture2D* aSrcTexture) {
1317 MOZ_ASSERT(aDestData && aDestStride && aSrcTexture);
1319 RefPtr<ID3D11Device> device;
1320 aSrcTexture->GetDevice(getter_AddRefs(device));
1321 if (!device) {
1322 gfxWarning() << "Failed to get D3D11 device from source texture";
1323 return false;
1326 RefPtr<ID3D11DeviceContext> context;
1327 device->GetImmediateContext(getter_AddRefs(context));
1328 if (!context) {
1329 gfxWarning() << "Could not get an immediate D3D11 context";
1330 return false;
1333 RefPtr<IDXGIKeyedMutex> mutex;
1334 HRESULT hr = aSrcTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
1335 (void**)getter_AddRefs(mutex));
1336 if (SUCCEEDED(hr) && mutex) {
1337 hr = mutex->AcquireSync(0, 2000);
1338 if (hr != S_OK) {
1339 gfxWarning() << "Could not acquire DXGI surface lock in 2 seconds";
1340 return false;
1344 D3D11_TEXTURE2D_DESC srcDesc = {0};
1345 aSrcTexture->GetDesc(&srcDesc);
1346 srcDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
1347 srcDesc.Usage = D3D11_USAGE_STAGING;
1348 srcDesc.BindFlags = 0;
1349 srcDesc.MiscFlags = 0;
1350 srcDesc.MipLevels = 1;
1351 RefPtr<ID3D11Texture2D> srcCpuTexture;
1352 hr =
1353 device->CreateTexture2D(&srcDesc, nullptr, getter_AddRefs(srcCpuTexture));
1354 if (FAILED(hr)) {
1355 gfxWarning() << "Could not create source texture for mapping";
1356 if (mutex) {
1357 mutex->ReleaseSync(0);
1359 return false;
1362 context->CopyResource(srcCpuTexture, aSrcTexture);
1364 if (mutex) {
1365 mutex->ReleaseSync(0);
1366 mutex = nullptr;
1369 D3D11_MAPPED_SUBRESOURCE srcMap;
1370 hr = context->Map(srcCpuTexture, 0, D3D11_MAP_READ, 0, &srcMap);
1371 if (FAILED(hr)) {
1372 gfxWarning() << "Could not map source texture";
1373 return false;
1376 uint32_t width = srcDesc.Width;
1377 uint32_t height = srcDesc.Height;
1378 int bpp = BytesPerPixel(gfx::ToPixelFormat(srcDesc.Format));
1379 for (uint32_t y = 0; y < height; y++) {
1380 memcpy(aDestData + aDestStride * y,
1381 (unsigned char*)(srcMap.pData) + srcMap.RowPitch * y, width * bpp);
1384 context->Unmap(srcCpuTexture, 0);
1385 return true;
1388 #endif // WIN32
1390 // static
1391 void CriticalLogger::OutputMessage(const std::string& aString, int aLevel,
1392 bool aNoNewline) {
1393 if (Factory::GetLogForwarder()) {
1394 Factory::GetLogForwarder()->Log(aString);
1397 BasicLogger::OutputMessage(aString, aLevel, aNoNewline);
1400 void CriticalLogger::CrashAction(LogReason aReason) {
1401 if (Factory::GetLogForwarder()) {
1402 Factory::GetLogForwarder()->CrashAction(aReason);
1406 #ifdef WIN32
1407 void LogWStr(const wchar_t* aWStr, std::stringstream& aOut) {
1408 int n =
1409 WideCharToMultiByte(CP_ACP, 0, aWStr, -1, nullptr, 0, nullptr, nullptr);
1410 if (n > 1) {
1411 std::vector<char> str(n);
1412 WideCharToMultiByte(CP_ACP, 0, aWStr, -1, str.data(), n, nullptr, nullptr);
1413 aOut << str.data();
1416 #endif
1418 } // namespace mozilla::gfx