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