Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/Factory.cpp
Line
Count
Source (jump to first uncovered line)
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
#ifdef USE_SKIA
16
#include "DrawTargetSkia.h"
17
#include "ScaledFontBase.h"
18
#endif
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
#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
#endif
41
42
#ifdef WIN32
43
#include "DrawTargetD2D1.h"
44
#include "ScaledFontDWrite.h"
45
#include "NativeFontResourceDWrite.h"
46
#include <d3d10_1.h>
47
#include "HelpersD2D.h"
48
#include "HelpersWinFonts.h"
49
#include "mozilla/Mutex.h"
50
#endif
51
52
#include "DrawTargetCapture.h"
53
#include "DrawTargetDual.h"
54
#include "DrawTargetTiled.h"
55
#include "DrawTargetOffset.h"
56
#include "DrawTargetWrapAndRecord.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
#ifdef MOZ_ENABLE_FREETYPE
68
#include "ft2build.h"
69
#include FT_FREETYPE_H
70
71
#include "mozilla/Mutex.h"
72
#endif
73
#include "MainThreadUtils.h"
74
75
#if defined(MOZ_LOGGING)
76
GFX2D_API mozilla::LogModule*
77
GetGFX2DLog()
78
0
{
79
0
  static mozilla::LazyLogModule sLog("gfx2d");
80
0
  return sLog;
81
0
}
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
96
static inline bool
97
HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
98
0
{
99
0
  unsigned int regs[4];
100
0
  return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
101
0
         (regs[reg] & bit);
102
0
}
103
#endif
104
105
#define HAVE_CPU_DETECTION
106
#else
107
108
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
109
// MSVC 2005 or later supports __cpuid by intrin.h
110
#include <intrin.h>
111
112
#define HAVE_CPU_DETECTION
113
#elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
114
115
// Define a function identical to MSVC function.
116
#ifdef __i386
117
static void
118
__cpuid(int CPUInfo[4], int InfoType)
119
{
120
  asm (
121
    "xchg %esi, %ebx\n"
122
    "cpuid\n"
123
    "movl %eax, (%edi)\n"
124
    "movl %ebx, 4(%edi)\n"
125
    "movl %ecx, 8(%edi)\n"
126
    "movl %edx, 12(%edi)\n"
127
    "xchg %esi, %ebx\n"
128
    :
129
    : "a"(InfoType), // %eax
130
      "D"(CPUInfo) // %edi
131
    : "%ecx", "%edx", "%esi"
132
  );
133
}
134
#else
135
static void
136
__cpuid(int CPUInfo[4], int InfoType)
137
{
138
  asm (
139
    "xchg %rsi, %rbx\n"
140
    "cpuid\n"
141
    "movl %eax, (%rdi)\n"
142
    "movl %ebx, 4(%rdi)\n"
143
    "movl %ecx, 8(%rdi)\n"
144
    "movl %edx, 12(%rdi)\n"
145
    "xchg %rsi, %rbx\n"
146
    :
147
    : "a"(InfoType), // %eax
148
      "D"(CPUInfo) // %rdi
149
    : "%ecx", "%edx", "%rsi"
150
  );
151
}
152
153
#define HAVE_CPU_DETECTION
154
#endif
155
#endif
156
157
#ifdef HAVE_CPU_DETECTION
158
static inline bool
159
HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
160
{
161
  // Check that the level in question is supported.
162
  volatile int regs[4];
163
  __cpuid((int *)regs, level & 0x80000000u);
164
  if (unsigned(regs[0]) < level)
165
    return false;
166
  __cpuid((int *)regs, level);
167
  return !!(unsigned(regs[reg]) & bit);
168
}
169
#endif
170
#endif
171
172
#ifdef MOZ_ENABLE_FREETYPE
173
extern "C" {
174
175
FT_Face
176
mozilla_NewFTFace(FT_Library aFTLibrary, const char* aFileName, int aFaceIndex)
177
0
{
178
0
  return mozilla::gfx::Factory::NewFTFace(aFTLibrary, aFileName, aFaceIndex);
179
0
}
180
181
FT_Face
182
mozilla_NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize, int aFaceIndex)
183
0
{
184
0
  return mozilla::gfx::Factory::NewFTFaceFromData(aFTLibrary, aData, aDataSize, aFaceIndex);
185
0
}
186
187
void
188
mozilla_ReleaseFTFace(FT_Face aFace)
189
0
{
190
0
  mozilla::gfx::Factory::ReleaseFTFace(aFace);
191
0
}
192
193
FT_Error
194
mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags)
195
0
{
196
0
  return mozilla::gfx::Factory::LoadFTGlyph(aFace, aGlyphIndex, aFlags);
197
0
}
198
199
void
200
mozilla_LockFTLibrary(FT_Library aFTLibrary)
201
0
{
202
0
  mozilla::gfx::Factory::LockFTLibrary(aFTLibrary);
203
0
}
204
205
void
206
mozilla_UnlockFTLibrary(FT_Library aFTLibrary)
207
0
{
208
0
  mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary);
209
0
}
210
211
}
212
#endif
213
214
namespace mozilla {
215
namespace gfx {
216
217
// In Gecko, this value is managed by gfx.logging.level in gfxPrefs.
218
int32_t LoggingPrefs::sGfxLogLevel = LOG_DEFAULT;
219
220
#ifdef MOZ_ENABLE_FREETYPE
221
FT_Library Factory::mFTLibrary = nullptr;
222
Mutex* Factory::mFTLock = nullptr;
223
#endif
224
225
#ifdef WIN32
226
// Note: mDeviceLock must be held when mutating these values.
227
static uint32_t mDeviceSeq = 0;
228
StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
229
StaticRefPtr<ID2D1Device> Factory::mD2D1Device;
230
StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
231
bool Factory::mDWriteFactoryInitialized = false;
232
StaticMutex Factory::mDeviceLock;
233
StaticMutex Factory::mDTDependencyLock;
234
#endif
235
236
DrawEventRecorder *Factory::mRecorder;
237
238
mozilla::gfx::Config* Factory::sConfig = nullptr;
239
240
void
241
Factory::Init(const Config& aConfig)
242
0
{
243
0
  MOZ_ASSERT(!sConfig);
244
0
  sConfig = new Config(aConfig);
245
0
246
0
#ifdef MOZ_ENABLE_FREETYPE
247
0
  mFTLock = new Mutex("Factory::mFTLock");
248
0
#endif
249
0
}
250
251
void
252
Factory::ShutDown()
253
0
{
254
0
  if (sConfig) {
255
0
    delete sConfig->mLogForwarder;
256
0
    delete sConfig;
257
0
    sConfig = nullptr;
258
0
  }
259
0
260
0
#ifdef MOZ_ENABLE_FREETYPE
261
0
  mFTLibrary = nullptr;
262
0
  if (mFTLock) {
263
0
    delete mFTLock;
264
0
    mFTLock = nullptr;
265
0
  }
266
0
#endif
267
0
}
268
269
bool
270
Factory::HasSSE2()
271
0
{
272
0
#if defined(__SSE2__) || defined(_M_X64) || \
273
0
    (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
274
0
  // gcc with -msse2 (default on OSX and x86-64)
275
0
  // cl.exe with -arch:SSE2 (default on x64 compiler)
276
0
  return true;
277
#elif defined(HAVE_CPU_DETECTION)
278
  static enum {
279
    UNINITIALIZED,
280
    NO_SSE2,
281
    HAS_SSE2
282
  } sDetectionState = UNINITIALIZED;
283
284
  if (sDetectionState == UNINITIALIZED) {
285
    sDetectionState = HasCPUIDBit(1u, edx, (1u<<26)) ? HAS_SSE2 : NO_SSE2;
286
  }
287
  return sDetectionState == HAS_SSE2;
288
#else
289
  return false;
290
#endif
291
}
292
293
bool
294
Factory::HasSSE4()
295
0
{
296
#if defined(__SSE4__)
297
  // gcc with -msse2 (default on OSX and x86-64)
298
  // cl.exe with -arch:SSE2 (default on x64 compiler)
299
  return true;
300
#elif defined(HAVE_CPU_DETECTION)
301
  static enum {
302
0
    UNINITIALIZED,
303
0
    NO_SSE4,
304
0
    HAS_SSE4
305
0
  } sDetectionState = UNINITIALIZED;
306
0
307
0
  if (sDetectionState == UNINITIALIZED) {
308
0
    sDetectionState = HasCPUIDBit(1u, ecx, (1u << 19)) ? HAS_SSE4 : NO_SSE4;
309
0
  }
310
0
  return sDetectionState == HAS_SSE4;
311
#else
312
  return false;
313
#endif
314
}
315
316
// If the size is "reasonable", we want gfxCriticalError to assert, so
317
// this is the option set up for it.
318
inline int LoggerOptionsBasedOnSize(const IntSize& aSize)
319
0
{
320
0
  return CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize));
321
0
}
322
323
bool
324
Factory::ReasonableSurfaceSize(const IntSize &aSize)
325
0
{
326
0
  return Factory::CheckSurfaceSize(aSize, 8192);
327
0
}
328
329
bool
330
Factory::AllowedSurfaceSize(const IntSize &aSize)
331
0
{
332
0
  if (sConfig) {
333
0
    return Factory::CheckSurfaceSize(aSize,
334
0
                                     sConfig->mMaxTextureSize,
335
0
                                     sConfig->mMaxAllocSize);
336
0
  }
337
0
338
0
  return CheckSurfaceSize(aSize);
339
0
}
340
341
bool
342
Factory::CheckBufferSize(int32_t bufSize)
343
0
{
344
0
  return !sConfig || bufSize < sConfig->mMaxAllocSize;
345
0
}
346
347
bool
348
Factory::CheckSurfaceSize(const IntSize &sz,
349
                          int32_t extentLimit,
350
                          int32_t allocLimit)
351
0
{
352
0
  if (sz.width <= 0 || sz.height <= 0) {
353
0
    return false;
354
0
  }
355
0
356
0
  // reject images with sides bigger than limit
357
0
  if (extentLimit && (sz.width > extentLimit || sz.height > extentLimit)) {
358
0
    gfxDebug() << "Surface size too large (exceeds extent limit)!";
359
0
    return false;
360
0
  }
361
0
362
0
  // assuming 4 bytes per pixel, make sure the allocation size
363
0
  // doesn't overflow a int32_t either
364
0
  CheckedInt<int32_t> stride = GetAlignedStride<16>(sz.width, 4);
365
0
  if (!stride.isValid() || stride.value() == 0) {
366
0
    gfxDebug() << "Surface size too large (stride overflows int32_t)!";
367
0
    return false;
368
0
  }
369
0
370
0
  CheckedInt<int32_t> numBytes = stride * sz.height;
371
0
  if (!numBytes.isValid()) {
372
0
    gfxDebug() << "Surface size too large (allocation size would overflow int32_t)!";
373
0
    return false;
374
0
  }
375
0
376
0
  if (allocLimit && allocLimit < numBytes.value()) {
377
0
    gfxDebug() << "Surface size too large (exceeds allocation limit)!";
378
0
    return false;
379
0
  }
380
0
381
0
  return true;
382
0
}
383
384
already_AddRefed<DrawTarget>
385
Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat)
386
0
{
387
0
  if (!AllowedSurfaceSize(aSize)) {
388
0
    gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "Failed to allocate a surface due to invalid size (CDT) " << aSize;
389
0
    return nullptr;
390
0
  }
391
0
392
0
  RefPtr<DrawTarget> retVal;
393
0
  switch (aBackend) {
394
#ifdef WIN32
395
  case BackendType::DIRECT2D1_1:
396
    {
397
      RefPtr<DrawTargetD2D1> newTarget;
398
      newTarget = new DrawTargetD2D1();
399
      if (newTarget->Init(aSize, aFormat)) {
400
        retVal = newTarget;
401
      }
402
      break;
403
    }
404
#endif
405
#ifdef USE_SKIA
406
0
  case BackendType::SKIA:
407
0
    {
408
0
      RefPtr<DrawTargetSkia> newTarget;
409
0
      newTarget = new DrawTargetSkia();
410
0
      if (newTarget->Init(aSize, aFormat)) {
411
0
        retVal = newTarget;
412
0
      }
413
0
      break;
414
0
    }
415
0
#endif
416
0
#ifdef USE_CAIRO
417
0
  case BackendType::CAIRO:
418
0
    {
419
0
      RefPtr<DrawTargetCairo> newTarget;
420
0
      newTarget = new DrawTargetCairo();
421
0
      if (newTarget->Init(aSize, aFormat)) {
422
0
        retVal = newTarget;
423
0
      }
424
0
      break;
425
0
    }
426
0
#endif
427
0
  default:
428
0
    return nullptr;
429
0
  }
430
0
431
0
  if (mRecorder && retVal) {
432
0
    return MakeAndAddRef<DrawTargetWrapAndRecord>(mRecorder, retVal);
433
0
  }
434
0
435
0
  if (!retVal) {
436
0
    // Failed
437
0
    gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize;
438
0
  }
439
0
440
0
  return retVal.forget();
441
0
}
442
443
already_AddRefed<DrawTarget>
444
Factory::CreateWrapAndRecordDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT)
445
0
{
446
0
  return MakeAndAddRef<DrawTargetWrapAndRecord>(aRecorder, aDT);
447
0
}
448
449
already_AddRefed<DrawTarget>
450
Factory::CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT, IntSize aSize)
451
0
{
452
0
  return MakeAndAddRef<DrawTargetRecording>(aRecorder, aDT, aSize);
453
0
}
454
455
already_AddRefed<DrawTargetCapture>
456
Factory::CreateCaptureDrawTargetForTarget(gfx::DrawTarget* aTarget, size_t aFlushBytes)
457
0
{
458
0
  return MakeAndAddRef<DrawTargetCaptureImpl>(aTarget, aFlushBytes);
459
0
}
460
461
already_AddRefed<DrawTargetCapture>
462
Factory::CreateCaptureDrawTarget(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
463
0
{
464
0
  return MakeAndAddRef<DrawTargetCaptureImpl>(aBackend, aSize, aFormat);
465
0
}
466
467
already_AddRefed<DrawTargetCapture>
468
Factory::CreateCaptureDrawTargetForData(BackendType aBackend,
469
                                        const IntSize &aSize,
470
                                        SurfaceFormat aFormat,
471
                                        int32_t aStride,
472
                                        size_t aSurfaceAllocationSize)
473
0
{
474
0
  MOZ_ASSERT(aSurfaceAllocationSize && aStride);
475
0
476
0
  BackendType type = aBackend;
477
0
  if (!Factory::DoesBackendSupportDataDrawtarget(aBackend)) {
478
0
    type = BackendType::SKIA;
479
0
  }
480
0
481
0
  RefPtr<DrawTargetCaptureImpl> dt = new DrawTargetCaptureImpl(type, aSize, aFormat);
482
0
  dt->InitForData(aStride, aSurfaceAllocationSize);
483
0
  return dt.forget();
484
0
}
485
486
already_AddRefed<DrawTarget>
487
Factory::CreateDrawTargetForData(BackendType aBackend,
488
                                 unsigned char *aData,
489
                                 const IntSize &aSize,
490
                                 int32_t aStride,
491
                                 SurfaceFormat aFormat,
492
                                 bool aUninitialized)
493
0
{
494
0
  MOZ_ASSERT(aData);
495
0
  if (!AllowedSurfaceSize(aSize)) {
496
0
    gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "Failed to allocate a surface due to invalid size (DTD) " << aSize;
497
0
    return nullptr;
498
0
  }
499
0
500
0
  RefPtr<DrawTarget> retVal;
501
0
502
0
  switch (aBackend) {
503
0
#ifdef USE_SKIA
504
0
  case BackendType::SKIA:
505
0
    {
506
0
      RefPtr<DrawTargetSkia> newTarget;
507
0
      newTarget = new DrawTargetSkia();
508
0
      if (newTarget->Init(aData, aSize, aStride, aFormat, aUninitialized)) {
509
0
        retVal = newTarget;
510
0
      }
511
0
      break;
512
0
    }
513
0
#endif
514
0
#ifdef USE_CAIRO
515
0
  case BackendType::CAIRO:
516
0
    {
517
0
      RefPtr<DrawTargetCairo> newTarget;
518
0
      newTarget = new DrawTargetCairo();
519
0
      if (newTarget->Init(aData, aSize, aStride, aFormat)) {
520
0
        retVal = newTarget.forget();
521
0
      }
522
0
      break;
523
0
    }
524
0
#endif
525
0
  default:
526
0
    gfxCriticalNote << "Invalid draw target type specified: " << (int)aBackend;
527
0
    return nullptr;
528
0
  }
529
0
530
0
  if (mRecorder && retVal) {
531
0
    return MakeAndAddRef<DrawTargetWrapAndRecord>(mRecorder, retVal, true);
532
0
  }
533
0
534
0
  if (!retVal) {
535
0
    gfxCriticalNote << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize << ", Data: " << hexa((void *)aData) << ", Stride: " << aStride;
536
0
  }
537
0
538
0
  return retVal.forget();
539
0
}
540
541
already_AddRefed<DrawTarget>
542
Factory::CreateTiledDrawTarget(const TileSet& aTileSet)
543
0
{
544
0
  RefPtr<DrawTargetTiled> dt = new DrawTargetTiled();
545
0
546
0
  if (!dt->Init(aTileSet)) {
547
0
    return nullptr;
548
0
  }
549
0
550
0
  return dt.forget();
551
0
}
552
553
already_AddRefed<DrawTarget>
554
Factory::CreateOffsetDrawTarget(DrawTarget *aDrawTarget, IntPoint aTileOrigin)
555
0
{
556
0
  RefPtr<DrawTargetOffset> dt = new DrawTargetOffset();
557
0
558
0
  if (!dt->Init(aDrawTarget, aTileOrigin)) {
559
0
    return nullptr;
560
0
  }
561
0
562
0
  return dt.forget();
563
0
}
564
565
566
bool
567
Factory::DoesBackendSupportDataDrawtarget(BackendType aType)
568
0
{
569
0
  switch (aType) {
570
0
  case BackendType::DIRECT2D:
571
0
  case BackendType::DIRECT2D1_1:
572
0
  case BackendType::RECORDING:
573
0
  case BackendType::NONE:
574
0
  case BackendType::BACKEND_LAST:
575
0
  case BackendType::WEBRENDER_TEXT:
576
0
    return false;
577
0
  case BackendType::CAIRO:
578
0
  case BackendType::SKIA:
579
0
    return true;
580
0
  }
581
0
582
0
  return false;
583
0
}
584
585
uint32_t
586
Factory::GetMaxSurfaceSize(BackendType aType)
587
0
{
588
0
  switch (aType) {
589
0
  case BackendType::CAIRO:
590
0
    return DrawTargetCairo::GetMaxSurfaceSize();
591
0
#ifdef USE_SKIA
592
0
  case BackendType::SKIA:
593
0
    return DrawTargetSkia::GetMaxSurfaceSize();
594
0
#endif
595
#ifdef WIN32
596
  case BackendType::DIRECT2D1_1:
597
    return DrawTargetD2D1::GetMaxSurfaceSize();
598
#endif
599
0
  default:
600
0
    return 0;
601
0
  }
602
0
}
603
604
already_AddRefed<ScaledFont>
605
Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont,
606
                                       const RefPtr<UnscaledFont>& aUnscaledFont,
607
                                       Float aSize,
608
                                       cairo_scaled_font_t* aScaledFont)
609
0
{
610
0
  switch (aNativeFont.mType) {
611
#ifdef WIN32
612
  case NativeFontType::GDI_LOGFONT:
613
    {
614
      RefPtr<ScaledFontWin> font = MakeAndAddRef<ScaledFontWin>(static_cast<LOGFONT*>(aNativeFont.mFont), aUnscaledFont, aSize);
615
#ifdef USE_CAIRO
616
      if (aScaledFont) {
617
        font->SetCairoScaledFont(aScaledFont);
618
      } else {
619
        font->PopulateCairoScaledFont();
620
      }
621
#endif
622
      return font.forget();
623
    }
624
#elif defined(MOZ_WIDGET_GTK)
625
0
  case NativeFontType::FONTCONFIG_PATTERN:
626
0
    return MakeAndAddRef<ScaledFontFontconfig>(aScaledFont, static_cast<FcPattern*>(aNativeFont.mFont), aUnscaledFont, aSize);
627
#elif defined(MOZ_WIDGET_ANDROID)
628
  case NativeFontType::FREETYPE_FACE:
629
    return MakeAndAddRef<ScaledFontFreeType>(aScaledFont, static_cast<FT_Face>(aNativeFont.mFont), aUnscaledFont, aSize);
630
#endif
631
0
  default:
632
0
    gfxWarning() << "Invalid native font type specified.";
633
0
    return nullptr;
634
0
  }
635
0
}
636
637
already_AddRefed<NativeFontResource>
638
Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize, BackendType aBackendType, FontType aFontType, void* aFontContext)
639
0
{
640
0
  switch (aFontType) {
641
#ifdef WIN32
642
  case FontType::DWRITE:
643
    {
644
      bool needsCairo = aBackendType == BackendType::CAIRO;
645
      return NativeFontResourceDWrite::Create(aData, aSize, needsCairo);
646
    }
647
  case FontType::GDI:
648
    return NativeFontResourceGDI::Create(aData, aSize);
649
#elif defined(XP_DARWIN)
650
  case FontType::MAC:
651
    {
652
      bool needsCairo = aBackendType == BackendType::CAIRO;
653
      return NativeFontResourceMac::Create(aData, aSize, needsCairo);
654
    }
655
#elif defined(MOZ_WIDGET_GTK)
656
0
  case FontType::FONTCONFIG:
657
0
    return NativeFontResourceFontconfig::Create(aData, aSize,
658
0
                                                static_cast<FT_Library>(aFontContext));
659
#elif defined(MOZ_WIDGET_ANDROID)
660
  case FontType::FREETYPE:
661
    return NativeFontResourceFreeType::Create(aData, aSize,
662
                                              static_cast<FT_Library>(aFontContext));
663
#endif
664
0
  default:
665
0
    gfxWarning() << "Unable to create requested font resource from truetype data";
666
0
    return nullptr;
667
0
  }
668
0
}
669
670
already_AddRefed<UnscaledFont>
671
Factory::CreateUnscaledFontFromFontDescriptor(FontType aType, const uint8_t* aData, uint32_t aDataLength, uint32_t aIndex)
672
0
{
673
0
  switch (aType) {
674
#ifdef WIN32
675
  case FontType::GDI:
676
    return UnscaledFontGDI::CreateFromFontDescriptor(aData, aDataLength, aIndex);
677
#endif
678
#ifdef MOZ_WIDGET_GTK
679
0
  case FontType::FONTCONFIG:
680
0
    return UnscaledFontFontconfig::CreateFromFontDescriptor(aData, aDataLength, aIndex);
681
0
#endif
682
0
  default:
683
0
    gfxWarning() << "Invalid type specified for UnscaledFont font descriptor";
684
0
    return nullptr;
685
0
  }
686
0
}
687
688
#ifdef XP_DARWIN
689
already_AddRefed<ScaledFont>
690
Factory::CreateScaledFontForMacFont(CGFontRef aCGFont,
691
                                    const RefPtr<UnscaledFont>& aUnscaledFont,
692
                                    Float aSize,
693
                                    const Color& aFontSmoothingBackgroundColor,
694
                                    bool aUseFontSmoothing,
695
                                    bool aApplySyntheticBold)
696
{
697
  return MakeAndAddRef<ScaledFontMac>(
698
    aCGFont, aUnscaledFont, aSize, false,
699
    aFontSmoothingBackgroundColor, aUseFontSmoothing,
700
    aApplySyntheticBold);
701
}
702
#endif
703
704
already_AddRefed<DrawTarget>
705
Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB)
706
0
{
707
0
  MOZ_ASSERT(targetA && targetB);
708
0
709
0
  RefPtr<DrawTarget> newTarget =
710
0
    new DrawTargetDual(targetA, targetB);
711
0
712
0
  RefPtr<DrawTarget> retVal = newTarget;
713
0
714
0
  if (mRecorder) {
715
0
    retVal = new DrawTargetWrapAndRecord(mRecorder, retVal);
716
0
  }
717
0
718
0
  return retVal.forget();
719
0
}
720
721
already_AddRefed<SourceSurface>
722
Factory::CreateDualSourceSurface(SourceSurface *sourceA, SourceSurface *sourceB)
723
0
{
724
0
  MOZ_ASSERT(sourceA && sourceB);
725
0
726
0
  RefPtr<SourceSurface> newSource =
727
0
    new SourceSurfaceDual(sourceA, sourceB);
728
0
729
0
  return newSource.forget();
730
0
}
731
732
733
#ifdef MOZ_ENABLE_FREETYPE
734
void
735
Factory::SetFTLibrary(FT_Library aFTLibrary)
736
0
{
737
0
  mFTLibrary = aFTLibrary;
738
0
}
739
740
FT_Library
741
Factory::GetFTLibrary()
742
0
{
743
0
  MOZ_ASSERT(mFTLibrary);
744
0
  return mFTLibrary;
745
0
}
746
747
FT_Library
748
Factory::NewFTLibrary()
749
0
{
750
0
  FT_Library library;
751
0
  if (FT_Init_FreeType(&library) != FT_Err_Ok) {
752
0
    return nullptr;
753
0
  }
754
0
  return library;
755
0
}
756
757
void
758
Factory::ReleaseFTLibrary(FT_Library aFTLibrary)
759
0
{
760
0
  FT_Done_FreeType(aFTLibrary);
761
0
}
762
763
void
764
Factory::LockFTLibrary(FT_Library aFTLibrary)
765
0
{
766
0
  MOZ_ASSERT(mFTLock);
767
0
  mFTLock->Lock();
768
0
}
769
770
void
771
Factory::UnlockFTLibrary(FT_Library aFTLibrary)
772
0
{
773
0
  MOZ_ASSERT(mFTLock);
774
0
  mFTLock->Unlock();
775
0
}
776
777
FT_Face
778
Factory::NewFTFace(FT_Library aFTLibrary, const char* aFileName, int aFaceIndex)
779
0
{
780
0
  MOZ_ASSERT(mFTLock);
781
0
  MutexAutoLock lock(*mFTLock);
782
0
  if (!aFTLibrary) {
783
0
    aFTLibrary = mFTLibrary;
784
0
  }
785
0
  FT_Face face;
786
0
  if (FT_New_Face(aFTLibrary, aFileName, aFaceIndex, &face) != FT_Err_Ok) {
787
0
    return nullptr;
788
0
  }
789
0
  return face;
790
0
}
791
792
FT_Face
793
Factory::NewFTFaceFromData(FT_Library aFTLibrary, const uint8_t* aData, size_t aDataSize, int aFaceIndex)
794
0
{
795
0
  MOZ_ASSERT(mFTLock);
796
0
  MutexAutoLock lock(*mFTLock);
797
0
  if (!aFTLibrary) {
798
0
    aFTLibrary = mFTLibrary;
799
0
  }
800
0
  FT_Face face;
801
0
  if (FT_New_Memory_Face(aFTLibrary, aData, aDataSize, aFaceIndex, &face) != FT_Err_Ok) {
802
0
    return nullptr;
803
0
  }
804
0
  return face;
805
0
}
806
807
void
808
Factory::ReleaseFTFace(FT_Face aFace)
809
0
{
810
0
  // May be called during shutdown when the lock is already destroyed.
811
0
  // However, there are no other threads using the face by this point,
812
0
  // so it is safe to skip locking if the lock is not around.
813
0
  if (mFTLock) {
814
0
    mFTLock->Lock();
815
0
  }
816
0
  FT_Done_Face(aFace);
817
0
  if (mFTLock) {
818
0
    mFTLock->Unlock();
819
0
  }
820
0
}
821
822
FT_Error
823
Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags)
824
0
{
825
0
  MOZ_ASSERT(mFTLock);
826
0
  MutexAutoLock lock(*mFTLock);
827
0
  return FT_Load_Glyph(aFace, aGlyphIndex, aFlags);
828
0
}
829
#endif
830
831
#ifdef WIN32
832
already_AddRefed<DrawTarget>
833
Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceFormat aFormat)
834
{
835
  MOZ_ASSERT(aTexture);
836
837
  RefPtr<DrawTargetD2D1> newTarget;
838
839
  newTarget = new DrawTargetD2D1();
840
  if (newTarget->Init(aTexture, aFormat)) {
841
    RefPtr<DrawTarget> retVal = newTarget;
842
843
    if (mRecorder) {
844
      retVal = new DrawTargetWrapAndRecord(mRecorder, retVal, true);
845
    }
846
847
    return retVal.forget();
848
  }
849
850
  gfxWarning() << "Failed to create draw target for D3D11 texture.";
851
852
  // Failed
853
  return nullptr;
854
}
855
856
bool
857
Factory::SetDirect3D11Device(ID3D11Device *aDevice)
858
{
859
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
860
861
  // D2DFactory already takes the device lock, so we get the factory before
862
  // entering the lock scope.
863
  RefPtr<ID2D1Factory1> factory = D2DFactory();
864
865
  StaticMutexAutoLock lock(mDeviceLock);
866
867
  mD3D11Device = aDevice;
868
869
  if (mD2D1Device) {
870
    mD2D1Device = nullptr;
871
  }
872
873
  if (!aDevice) {
874
    return true;
875
  }
876
877
  RefPtr<IDXGIDevice> device;
878
  aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(device));
879
880
  RefPtr<ID2D1Device> d2dDevice;
881
  HRESULT hr = factory->CreateDevice(device, getter_AddRefs(d2dDevice));
882
  if (FAILED(hr)) {
883
    gfxCriticalError() << "[D2D1] Failed to create gfx factory's D2D1 device, code: " << hexa(hr);
884
885
    mD3D11Device = nullptr;
886
    return false;
887
  }
888
889
  mDeviceSeq++;
890
  mD2D1Device = d2dDevice;
891
  return true;
892
}
893
894
RefPtr<ID3D11Device>
895
Factory::GetDirect3D11Device()
896
{
897
  StaticMutexAutoLock lock(mDeviceLock);
898
  return mD3D11Device;
899
}
900
901
RefPtr<ID2D1Device>
902
Factory::GetD2D1Device(uint32_t* aOutSeqNo)
903
{
904
  StaticMutexAutoLock lock(mDeviceLock);
905
  if (aOutSeqNo) {
906
    *aOutSeqNo = mDeviceSeq;
907
  }
908
  return mD2D1Device.get();
909
}
910
911
bool
912
Factory::HasD2D1Device()
913
{
914
  return !!GetD2D1Device();
915
}
916
917
RefPtr<IDWriteFactory>
918
Factory::GetDWriteFactory()
919
{
920
  StaticMutexAutoLock lock(mDeviceLock);
921
  return mDWriteFactory;
922
}
923
924
RefPtr<IDWriteFactory>
925
Factory::EnsureDWriteFactory()
926
{
927
  StaticMutexAutoLock lock(mDeviceLock);
928
929
  if (mDWriteFactoryInitialized) {
930
    return mDWriteFactory;
931
  }
932
933
  mDWriteFactoryInitialized = true;
934
935
  HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
936
  decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*)
937
    GetProcAddress(dwriteModule, "DWriteCreateFactory");
938
939
  if (!createDWriteFactory) {
940
    gfxWarning() << "Failed to locate DWriteCreateFactory function.";
941
    return nullptr;
942
  }
943
944
  HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
945
                                   reinterpret_cast<IUnknown**>(&mDWriteFactory));
946
947
  if (FAILED(hr)) {
948
    gfxWarning() << "Failed to create DWrite Factory.";
949
  }
950
951
  return mDWriteFactory;
952
}
953
954
bool
955
Factory::SupportsD2D1()
956
{
957
  return !!D2DFactory();
958
}
959
960
BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
961
void
962
Factory::SetSystemTextQuality(uint8_t aQuality)
963
{
964
  sSystemTextQuality = aQuality;
965
}
966
967
uint64_t
968
Factory::GetD2DVRAMUsageDrawTarget()
969
{
970
  return DrawTargetD2D1::mVRAMUsageDT;
971
}
972
973
uint64_t
974
Factory::GetD2DVRAMUsageSourceSurface()
975
{
976
  return DrawTargetD2D1::mVRAMUsageSS;
977
}
978
979
void
980
Factory::D2DCleanup()
981
{
982
  StaticMutexAutoLock lock(mDeviceLock);
983
  if (mD2D1Device) {
984
    mD2D1Device = nullptr;
985
  }
986
  DrawTargetD2D1::CleanupD2D();
987
}
988
989
already_AddRefed<ScaledFont>
990
Factory::CreateScaledFontForDWriteFont(IDWriteFontFace* aFontFace,
991
                                       const gfxFontStyle* aStyle,
992
                                       const RefPtr<UnscaledFont>& aUnscaledFont,
993
                                       float aSize,
994
                                       bool aUseEmbeddedBitmap,
995
                                       bool aForceGDIMode,
996
                                       IDWriteRenderingParams* aParams,
997
                                       Float aGamma,
998
                                       Float aContrast)
999
{
1000
  return MakeAndAddRef<ScaledFontDWrite>(aFontFace, aUnscaledFont, aSize,
1001
                                         aUseEmbeddedBitmap, aForceGDIMode,
1002
                                         aParams, aGamma, aContrast,
1003
                                         aStyle);
1004
}
1005
1006
#endif // XP_WIN
1007
1008
#ifdef USE_SKIA_GPU
1009
already_AddRefed<DrawTarget>
1010
Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
1011
                                           const IntSize &aSize,
1012
                                           SurfaceFormat aFormat)
1013
0
{
1014
0
  RefPtr<DrawTarget> newTarget = new DrawTargetSkia();
1015
0
  if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
1016
0
    return nullptr;
1017
0
  }
1018
0
  return newTarget.forget();
1019
0
}
1020
1021
#endif // USE_SKIA_GPU
1022
1023
#ifdef USE_SKIA
1024
already_AddRefed<DrawTarget>
1025
Factory::CreateDrawTargetWithSkCanvas(SkCanvas* aCanvas)
1026
0
{
1027
0
  RefPtr<DrawTargetSkia> newTarget = new DrawTargetSkia();
1028
0
  if (!newTarget->Init(aCanvas)) {
1029
0
    return nullptr;
1030
0
  }
1031
0
  return newTarget.forget();
1032
0
}
1033
#endif
1034
1035
void
1036
Factory::PurgeAllCaches()
1037
0
{
1038
0
}
1039
1040
already_AddRefed<DrawTarget>
1041
Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
1042
0
{
1043
0
  if (!AllowedSurfaceSize(aSize)) {
1044
0
    gfxWarning() << "Allowing surface with invalid size (Cairo) " << aSize;
1045
0
  }
1046
0
1047
0
  RefPtr<DrawTarget> retVal;
1048
0
1049
0
#ifdef USE_CAIRO
1050
0
  RefPtr<DrawTargetCairo> newTarget = new DrawTargetCairo();
1051
0
1052
0
  if (newTarget->Init(aSurface, aSize, aFormat)) {
1053
0
    retVal = newTarget;
1054
0
  }
1055
0
1056
0
  if (mRecorder && retVal) {
1057
0
    return MakeAndAddRef<DrawTargetWrapAndRecord>(mRecorder, retVal, true);
1058
0
  }
1059
0
#endif
1060
0
  return retVal.forget();
1061
0
}
1062
1063
already_AddRefed<SourceSurface>
1064
Factory::CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat aFormat)
1065
0
{
1066
0
  if (aSize.width <= 0 || aSize.height <= 0) {
1067
0
    gfxWarning() << "Can't create a SourceSurface without a valid size";
1068
0
    return nullptr;
1069
0
  }
1070
0
1071
0
#ifdef USE_CAIRO
1072
0
  return MakeAndAddRef<SourceSurfaceCairo>(aSurface, aSize, aFormat);
1073
#else
1074
  return nullptr;
1075
#endif
1076
}
1077
1078
already_AddRefed<DataSourceSurface>
1079
Factory::CreateWrappingDataSourceSurface(uint8_t *aData,
1080
                                         int32_t aStride,
1081
                                         const IntSize &aSize,
1082
                                         SurfaceFormat aFormat,
1083
                                         SourceSurfaceDeallocator aDeallocator /* = nullptr */,
1084
                                         void* aClosure /* = nullptr */)
1085
0
{
1086
0
  // Just check for negative/zero size instead of the full AllowedSurfaceSize() - since
1087
0
  // the data is already allocated we do not need to check for a possible overflow - it
1088
0
  // already worked.
1089
0
  if (aSize.width <= 0 || aSize.height <= 0) {
1090
0
    return nullptr;
1091
0
  }
1092
0
  if (!aDeallocator && aClosure) {
1093
0
    return nullptr;
1094
0
  }
1095
0
1096
0
  MOZ_ASSERT(aData);
1097
0
1098
0
  RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
1099
0
  newSurf->InitWrappingData(aData, aSize, aStride, aFormat, aDeallocator, aClosure);
1100
0
1101
0
  return newSurf.forget();
1102
0
}
1103
1104
already_AddRefed<DataSourceSurface>
1105
Factory::CreateDataSourceSurface(const IntSize &aSize,
1106
                                 SurfaceFormat aFormat,
1107
                                 bool aZero)
1108
0
{
1109
0
  if (!AllowedSurfaceSize(aSize)) {
1110
0
    gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "Failed to allocate a surface due to invalid size (DSS) " << aSize;
1111
0
    return nullptr;
1112
0
  }
1113
0
1114
0
  // Skia doesn't support RGBX, so memset RGBX to 0xFF
1115
0
  bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
1116
0
  uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
1117
0
1118
0
  RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
1119
0
  if (newSurf->Init(aSize, aFormat, clearSurface, clearValue)) {
1120
0
    return newSurf.forget();
1121
0
  }
1122
0
1123
0
  gfxWarning() << "CreateDataSourceSurface failed in init";
1124
0
  return nullptr;
1125
0
}
1126
1127
already_AddRefed<DataSourceSurface>
1128
Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize,
1129
                                           SurfaceFormat aFormat,
1130
                                           int32_t aStride,
1131
                                           bool aZero)
1132
0
{
1133
0
  if (!AllowedSurfaceSize(aSize) ||
1134
0
      aStride < aSize.width * BytesPerPixel(aFormat)) {
1135
0
    gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "CreateDataSourceSurfaceWithStride failed with bad stride " << aStride << ", " << aSize << ", " << aFormat;
1136
0
    return nullptr;
1137
0
  }
1138
0
1139
0
  // Skia doesn't support RGBX, so memset RGBX to 0xFF
1140
0
  bool clearSurface = aZero || aFormat == SurfaceFormat::B8G8R8X8;
1141
0
  uint8_t clearValue = aFormat == SurfaceFormat::B8G8R8X8 ? 0xFF : 0;
1142
0
1143
0
  RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
1144
0
  if (newSurf->Init(aSize, aFormat, clearSurface, clearValue, aStride)) {
1145
0
    return newSurf.forget();
1146
0
  }
1147
0
1148
0
  gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "CreateDataSourceSurfaceWithStride failed to initialize " << aSize << ", " << aFormat << ", " << aStride << ", " << aZero;
1149
0
  return nullptr;
1150
0
}
1151
1152
void
1153
Factory::CopyDataSourceSurface(DataSourceSurface* aSource,
1154
                               DataSourceSurface* aDest)
1155
0
{
1156
0
  // Don't worry too much about speed.
1157
0
  MOZ_ASSERT(aSource->GetSize() == aDest->GetSize());
1158
0
  MOZ_ASSERT(aSource->GetFormat() == SurfaceFormat::R8G8B8A8 ||
1159
0
             aSource->GetFormat() == SurfaceFormat::R8G8B8X8 ||
1160
0
             aSource->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1161
0
             aSource->GetFormat() == SurfaceFormat::B8G8R8X8);
1162
0
  MOZ_ASSERT(aDest->GetFormat() == SurfaceFormat::R8G8B8A8 ||
1163
0
             aDest->GetFormat() == SurfaceFormat::R8G8B8X8 ||
1164
0
             aDest->GetFormat() == SurfaceFormat::B8G8R8A8 ||
1165
0
             aDest->GetFormat() == SurfaceFormat::B8G8R8X8 ||
1166
0
             aDest->GetFormat() == SurfaceFormat::R5G6B5_UINT16);
1167
0
1168
0
  DataSourceSurface::MappedSurface srcMap;
1169
0
  DataSourceSurface::MappedSurface destMap;
1170
0
  if (!aSource->Map(DataSourceSurface::MapType::READ, &srcMap) ||
1171
0
    !aDest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
1172
0
    MOZ_ASSERT(false, "CopyDataSourceSurface: Failed to map surface.");
1173
0
    return;
1174
0
  }
1175
0
1176
0
  SwizzleData(srcMap.mData, srcMap.mStride, aSource->GetFormat(),
1177
0
              destMap.mData, destMap.mStride, aDest->GetFormat(),
1178
0
              aSource->GetSize());
1179
0
1180
0
  aSource->Unmap();
1181
0
  aDest->Unmap();
1182
0
}
1183
1184
already_AddRefed<DrawEventRecorder>
1185
Factory::CreateEventRecorderForFile(const char_type* aFilename)
1186
0
{
1187
0
  return MakeAndAddRef<DrawEventRecorderFile>(aFilename);
1188
0
}
1189
1190
void
1191
Factory::SetGlobalEventRecorder(DrawEventRecorder *aRecorder)
1192
0
{
1193
0
  mRecorder = aRecorder;
1194
0
}
1195
1196
// static
1197
void
1198
CriticalLogger::OutputMessage(const std::string &aString,
1199
                              int aLevel, bool aNoNewline)
1200
0
{
1201
0
  if (Factory::GetLogForwarder()) {
1202
0
    Factory::GetLogForwarder()->Log(aString);
1203
0
  }
1204
0
1205
0
  BasicLogger::OutputMessage(aString, aLevel, aNoNewline);
1206
0
}
1207
1208
void
1209
CriticalLogger::CrashAction(LogReason aReason)
1210
0
{
1211
0
  if (Factory::GetLogForwarder()) {
1212
0
    Factory::GetLogForwarder()->CrashAction(aReason);
1213
0
  }
1214
0
}
1215
1216
} // namespace gfx
1217
} // namespace mozilla