gfx/2d/Factory.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:f734e87bd659
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
8 #ifdef USE_CAIRO
9 #include "DrawTargetCairo.h"
10 #include "ScaledFontCairo.h"
11 #endif
12
13 #ifdef USE_SKIA
14 #include "DrawTargetSkia.h"
15 #include "ScaledFontBase.h"
16 #ifdef MOZ_ENABLE_FREETYPE
17 #define USE_SKIA_FREETYPE
18 #include "ScaledFontCairo.h"
19 #endif
20 #endif
21
22 #if defined(WIN32) && defined(USE_SKIA)
23 #include "ScaledFontWin.h"
24 #endif
25
26 #ifdef XP_MACOSX
27 #include "ScaledFontMac.h"
28 #endif
29
30
31 #ifdef XP_MACOSX
32 #include "DrawTargetCG.h"
33 #endif
34
35 #ifdef WIN32
36 #include "DrawTargetD2D.h"
37 #ifdef USE_D2D1_1
38 #include "DrawTargetD2D1.h"
39 #endif
40 #include "ScaledFontDWrite.h"
41 #include <d3d10_1.h>
42 #include "HelpersD2D.h"
43 #endif
44
45 #include "DrawTargetDual.h"
46 #include "DrawTargetRecording.h"
47
48 #include "SourceSurfaceRawData.h"
49
50 #include "DrawEventRecorder.h"
51
52 #include "Logging.h"
53
54 #include "mozilla/CheckedInt.h"
55
56 #if defined(DEBUG) || defined(PR_LOGGING)
57 GFX2D_API PRLogModuleInfo *
58 GetGFX2DLog()
59 {
60 static PRLogModuleInfo *sLog;
61 if (!sLog)
62 sLog = PR_NewLogModule("gfx2d");
63 return sLog;
64 }
65 #endif
66
67 // The following code was largely taken from xpcom/glue/SSE.cpp and
68 // made a little simpler.
69 enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
70
71 #ifdef HAVE_CPUID_H
72
73 #if !(defined(__SSE2__) || defined(_M_X64) || \
74 (defined(_M_IX86_FP) && _M_IX86_FP >= 2))
75 // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
76 #include <cpuid.h>
77
78 static inline bool
79 HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
80 {
81 unsigned int regs[4];
82 return __get_cpuid(level, &regs[0], &regs[1], &regs[2], &regs[3]) &&
83 (regs[reg] & bit);
84 }
85 #endif
86
87 #define HAVE_CPU_DETECTION
88 #else
89
90 #if defined(_MSC_VER) && _MSC_VER >= 1600 && (defined(_M_IX86) || defined(_M_AMD64))
91 // MSVC 2005 or later supports __cpuid by intrin.h
92 // But it does't work on MSVC 2005 with SDK 7.1 (Bug 753772)
93 #include <intrin.h>
94
95 #define HAVE_CPU_DETECTION
96 #elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
97
98 // Define a function identical to MSVC function.
99 #ifdef __i386
100 static void
101 __cpuid(int CPUInfo[4], int InfoType)
102 {
103 asm (
104 "xchg %esi, %ebx\n"
105 "cpuid\n"
106 "movl %eax, (%edi)\n"
107 "movl %ebx, 4(%edi)\n"
108 "movl %ecx, 8(%edi)\n"
109 "movl %edx, 12(%edi)\n"
110 "xchg %esi, %ebx\n"
111 :
112 : "a"(InfoType), // %eax
113 "D"(CPUInfo) // %edi
114 : "%ecx", "%edx", "%esi"
115 );
116 }
117 #else
118 static void
119 __cpuid(int CPUInfo[4], int InfoType)
120 {
121 asm (
122 "xchg %rsi, %rbx\n"
123 "cpuid\n"
124 "movl %eax, (%rdi)\n"
125 "movl %ebx, 4(%rdi)\n"
126 "movl %ecx, 8(%rdi)\n"
127 "movl %edx, 12(%rdi)\n"
128 "xchg %rsi, %rbx\n"
129 :
130 : "a"(InfoType), // %eax
131 "D"(CPUInfo) // %rdi
132 : "%ecx", "%edx", "%rsi"
133 );
134 }
135
136 #define HAVE_CPU_DETECTION
137 #endif
138 #endif
139
140 #ifdef HAVE_CPU_DETECTION
141 static inline bool
142 HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit)
143 {
144 // Check that the level in question is supported.
145 volatile int regs[4];
146 __cpuid((int *)regs, level & 0x80000000u);
147 if (unsigned(regs[0]) < level)
148 return false;
149 __cpuid((int *)regs, level);
150 return !!(unsigned(regs[reg]) & bit);
151 }
152 #endif
153 #endif
154
155 namespace mozilla {
156 namespace gfx {
157
158 // XXX - Need to define an API to set this.
159 GFX2D_API int sGfxLogLevel = LOG_DEBUG;
160
161 #ifdef WIN32
162 ID3D10Device1 *Factory::mD3D10Device;
163 #ifdef USE_D2D1_1
164 ID3D11Device *Factory::mD3D11Device;
165 ID2D1Device *Factory::mD2D1Device;
166 #endif
167 #endif
168
169 DrawEventRecorder *Factory::mRecorder;
170
171 bool
172 Factory::HasSSE2()
173 {
174 #if defined(__SSE2__) || defined(_M_X64) || \
175 (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
176 // gcc with -msse2 (default on OSX and x86-64)
177 // cl.exe with -arch:SSE2 (default on x64 compiler)
178 return true;
179 #elif defined(HAVE_CPU_DETECTION)
180 return HasCPUIDBit(1u, edx, (1u<<26));
181 #else
182 return false;
183 #endif
184 }
185
186 bool
187 Factory::CheckSurfaceSize(const IntSize &sz, int32_t limit)
188 {
189 if (sz.width < 0 || sz.height < 0) {
190 gfxDebug() << "Surface width or height < 0!";
191 return false;
192 }
193
194 // reject images with sides bigger than limit
195 if (limit && (sz.width > limit || sz.height > limit)) {
196 gfxDebug() << "Surface size too large (exceeds caller's limit)!";
197 return false;
198 }
199
200 // make sure the surface area doesn't overflow a int32_t
201 CheckedInt<int32_t> tmp = sz.width;
202 tmp *= sz.height;
203 if (!tmp.isValid()) {
204 gfxDebug() << "Surface size too large (would overflow)!";
205 return false;
206 }
207
208 // assuming 4 bytes per pixel, make sure the allocation size
209 // doesn't overflow a int32_t either
210 CheckedInt<int32_t> stride = sz.width;
211 stride *= 4;
212
213 // When aligning the stride to 16 bytes, it can grow by up to 15 bytes.
214 stride += 16 - 1;
215
216 if (!stride.isValid()) {
217 gfxDebug() << "Surface size too large (stride overflows int32_t)!";
218 return false;
219 }
220
221 CheckedInt<int32_t> numBytes = GetAlignedStride<16>(sz.width * 4);
222 numBytes *= sz.height;
223 if (!numBytes.isValid()) {
224 gfxDebug() << "Surface size too large (allocation size would overflow int32_t)!";
225 return false;
226 }
227
228 return true;
229 }
230
231 TemporaryRef<DrawTarget>
232 Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat)
233 {
234 if (!CheckSurfaceSize(aSize)) {
235 return nullptr;
236 }
237
238 RefPtr<DrawTarget> retVal;
239 switch (aBackend) {
240 #ifdef WIN32
241 case BackendType::DIRECT2D:
242 {
243 RefPtr<DrawTargetD2D> newTarget;
244 newTarget = new DrawTargetD2D();
245 if (newTarget->Init(aSize, aFormat)) {
246 retVal = newTarget;
247 }
248 break;
249 }
250 #ifdef USE_D2D1_1
251 case BackendType::DIRECT2D1_1:
252 {
253 RefPtr<DrawTargetD2D1> newTarget;
254 newTarget = new DrawTargetD2D1();
255 if (newTarget->Init(aSize, aFormat)) {
256 retVal = newTarget;
257 }
258 break;
259 }
260 #endif
261 #elif defined XP_MACOSX
262 case BackendType::COREGRAPHICS:
263 case BackendType::COREGRAPHICS_ACCELERATED:
264 {
265 RefPtr<DrawTargetCG> newTarget;
266 newTarget = new DrawTargetCG();
267 if (newTarget->Init(aBackend, aSize, aFormat)) {
268 retVal = newTarget;
269 }
270 break;
271 }
272 #endif
273 #ifdef USE_SKIA
274 case BackendType::SKIA:
275 {
276 RefPtr<DrawTargetSkia> newTarget;
277 newTarget = new DrawTargetSkia();
278 if (newTarget->Init(aSize, aFormat)) {
279 retVal = newTarget;
280 }
281 break;
282 }
283 #endif
284 #ifdef USE_CAIRO
285 case BackendType::CAIRO:
286 {
287 RefPtr<DrawTargetCairo> newTarget;
288 newTarget = new DrawTargetCairo();
289 if (newTarget->Init(aSize, aFormat)) {
290 retVal = newTarget;
291 }
292 break;
293 }
294 #endif
295 default:
296 gfxDebug() << "Invalid draw target type specified.";
297 return nullptr;
298 }
299
300 if (mRecorder && retVal) {
301 RefPtr<DrawTarget> recordDT;
302 recordDT = new DrawTargetRecording(mRecorder, retVal);
303 return recordDT;
304 }
305
306 if (!retVal) {
307 // Failed
308 gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize;
309 }
310
311 return retVal;
312 }
313
314 TemporaryRef<DrawTarget>
315 Factory::CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT)
316 {
317 return new DrawTargetRecording(aRecorder, aDT);
318 }
319
320 TemporaryRef<DrawTarget>
321 Factory::CreateDrawTargetForData(BackendType aBackend,
322 unsigned char *aData,
323 const IntSize &aSize,
324 int32_t aStride,
325 SurfaceFormat aFormat)
326 {
327 if (!CheckSurfaceSize(aSize)) {
328 return nullptr;
329 }
330
331 RefPtr<DrawTarget> retVal;
332
333 switch (aBackend) {
334 #ifdef USE_SKIA
335 case BackendType::SKIA:
336 {
337 RefPtr<DrawTargetSkia> newTarget;
338 newTarget = new DrawTargetSkia();
339 newTarget->Init(aData, aSize, aStride, aFormat);
340 retVal = newTarget;
341 break;
342 }
343 #endif
344 #ifdef XP_MACOSX
345 case BackendType::COREGRAPHICS:
346 {
347 RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
348 if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat))
349 return newTarget;
350 break;
351 }
352 #endif
353 #ifdef USE_CAIRO
354 case BackendType::CAIRO:
355 {
356 RefPtr<DrawTargetCairo> newTarget;
357 newTarget = new DrawTargetCairo();
358 if (newTarget->Init(aData, aSize, aStride, aFormat)) {
359 retVal = newTarget;
360 }
361 break;
362 }
363 #endif
364 default:
365 gfxDebug() << "Invalid draw target type specified.";
366 return nullptr;
367 }
368
369 if (mRecorder && retVal) {
370 RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal, true);
371 return recordDT;
372 }
373
374 if (!retVal) {
375 gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize;
376 }
377
378 return retVal;
379 }
380
381 TemporaryRef<ScaledFont>
382 Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize)
383 {
384 switch (aNativeFont.mType) {
385 #ifdef WIN32
386 case NativeFontType::DWRITE_FONT_FACE:
387 {
388 return new ScaledFontDWrite(static_cast<IDWriteFontFace*>(aNativeFont.mFont), aSize);
389 }
390 #if defined(USE_CAIRO) || defined(USE_SKIA)
391 case NativeFontType::GDI_FONT_FACE:
392 {
393 return new ScaledFontWin(static_cast<LOGFONT*>(aNativeFont.mFont), aSize);
394 }
395 #endif
396 #endif
397 #ifdef XP_MACOSX
398 case NativeFontType::MAC_FONT_FACE:
399 {
400 return new ScaledFontMac(static_cast<CGFontRef>(aNativeFont.mFont), aSize);
401 }
402 #endif
403 #if defined(USE_CAIRO) || defined(USE_SKIA_FREETYPE)
404 case NativeFontType::CAIRO_FONT_FACE:
405 {
406 return new ScaledFontCairo(static_cast<cairo_scaled_font_t*>(aNativeFont.mFont), aSize);
407 }
408 #endif
409 default:
410 gfxWarning() << "Invalid native font type specified.";
411 return nullptr;
412 }
413 }
414
415 TemporaryRef<ScaledFont>
416 Factory::CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize,
417 uint32_t aFaceIndex, Float aGlyphSize,
418 FontType aType)
419 {
420 switch (aType) {
421 #ifdef WIN32
422 case FontType::DWRITE:
423 {
424 return new ScaledFontDWrite(aData, aSize, aFaceIndex, aGlyphSize);
425 }
426 #endif
427 default:
428 gfxWarning() << "Unable to create requested font type from truetype data";
429 return nullptr;
430 }
431 }
432
433 TemporaryRef<ScaledFont>
434 Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, cairo_scaled_font_t* aScaledFont)
435 {
436 #ifdef USE_CAIRO
437 // In theory, we could pull the NativeFont out of the cairo_scaled_font_t*,
438 // but that would require a lot of code that would be otherwise repeated in
439 // various backends.
440 // Therefore, we just reuse CreateScaledFontForNativeFont's implementation.
441 RefPtr<ScaledFont> font = CreateScaledFontForNativeFont(aNativeFont, aSize);
442 static_cast<ScaledFontBase*>(font.get())->SetCairoScaledFont(aScaledFont);
443 return font;
444 #else
445 return nullptr;
446 #endif
447 }
448
449 TemporaryRef<DrawTarget>
450 Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB)
451 {
452 RefPtr<DrawTarget> newTarget =
453 new DrawTargetDual(targetA, targetB);
454
455 RefPtr<DrawTarget> retVal = newTarget;
456
457 if (mRecorder) {
458 retVal = new DrawTargetRecording(mRecorder, retVal);
459 }
460
461 return retVal;
462 }
463
464
465 #ifdef WIN32
466 TemporaryRef<DrawTarget>
467 Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
468 {
469 RefPtr<DrawTargetD2D> newTarget;
470
471 newTarget = new DrawTargetD2D();
472 if (newTarget->Init(aTexture, aFormat)) {
473 RefPtr<DrawTarget> retVal = newTarget;
474
475 if (mRecorder) {
476 retVal = new DrawTargetRecording(mRecorder, retVal, true);
477 }
478
479 return retVal;
480 }
481
482 gfxWarning() << "Failed to create draw target for D3D10 texture.";
483
484 // Failed
485 return nullptr;
486 }
487
488 TemporaryRef<DrawTarget>
489 Factory::CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA,
490 ID3D10Texture2D *aTextureB,
491 SurfaceFormat aFormat)
492 {
493 RefPtr<DrawTargetD2D> newTargetA;
494 RefPtr<DrawTargetD2D> newTargetB;
495
496 newTargetA = new DrawTargetD2D();
497 if (!newTargetA->Init(aTextureA, aFormat)) {
498 gfxWarning() << "Failed to create draw target for D3D10 texture.";
499 return nullptr;
500 }
501
502 newTargetB = new DrawTargetD2D();
503 if (!newTargetB->Init(aTextureB, aFormat)) {
504 gfxWarning() << "Failed to create draw target for D3D10 texture.";
505 return nullptr;
506 }
507
508 RefPtr<DrawTarget> newTarget =
509 new DrawTargetDual(newTargetA, newTargetB);
510
511 RefPtr<DrawTarget> retVal = newTarget;
512
513 if (mRecorder) {
514 retVal = new DrawTargetRecording(mRecorder, retVal);
515 }
516
517 return retVal;
518 }
519
520 void
521 Factory::SetDirect3D10Device(ID3D10Device1 *aDevice)
522 {
523 // do not throw on failure; return error codes and disconnect the device
524 // On Windows 8 error codes are the default, but on Windows 7 the
525 // default is to throw (or perhaps only with some drivers?)
526 aDevice->SetExceptionMode(0);
527 mD3D10Device = aDevice;
528 }
529
530 ID3D10Device1*
531 Factory::GetDirect3D10Device()
532 {
533 #ifdef DEBUG
534 UINT mode = mD3D10Device->GetExceptionMode();
535 MOZ_ASSERT(0 == mode);
536 #endif
537 return mD3D10Device;
538 }
539
540 #ifdef USE_D2D1_1
541 void
542 Factory::SetDirect3D11Device(ID3D11Device *aDevice)
543 {
544 mD3D11Device = aDevice;
545
546 RefPtr<ID2D1Factory1> factory = D2DFactory1();
547
548 RefPtr<IDXGIDevice> device;
549 aDevice->QueryInterface((IDXGIDevice**)byRef(device));
550 factory->CreateDevice(device, &mD2D1Device);
551 }
552
553 ID3D11Device*
554 Factory::GetDirect3D11Device()
555 {
556 return mD3D11Device;
557 }
558
559 ID2D1Device*
560 Factory::GetD2D1Device()
561 {
562 return mD2D1Device;
563 }
564 #endif
565
566 TemporaryRef<GlyphRenderingOptions>
567 Factory::CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams)
568 {
569 RefPtr<GlyphRenderingOptions> options =
570 new GlyphRenderingOptionsDWrite(aParams);
571
572 return options;
573 }
574
575 uint64_t
576 Factory::GetD2DVRAMUsageDrawTarget()
577 {
578 return DrawTargetD2D::mVRAMUsageDT;
579 }
580
581 uint64_t
582 Factory::GetD2DVRAMUsageSourceSurface()
583 {
584 return DrawTargetD2D::mVRAMUsageSS;
585 }
586
587 void
588 Factory::D2DCleanup()
589 {
590 DrawTargetD2D::CleanupD2D();
591 }
592
593 #endif // XP_WIN
594
595 #ifdef USE_SKIA_GPU
596 TemporaryRef<DrawTarget>
597 Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
598 const IntSize &aSize,
599 SurfaceFormat aFormat)
600 {
601 RefPtr<DrawTarget> newTarget = new DrawTargetSkia();
602 if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
603 return nullptr;
604 }
605 return newTarget;
606 }
607
608 #endif // USE_SKIA_GPU
609
610 void
611 Factory::PurgeAllCaches()
612 {
613 }
614
615 #ifdef USE_SKIA_FREETYPE
616 TemporaryRef<GlyphRenderingOptions>
617 Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting)
618 {
619 RefPtr<GlyphRenderingOptionsCairo> options =
620 new GlyphRenderingOptionsCairo();
621
622 options->SetHinting(aHinting);
623 options->SetAutoHinting(aAutoHinting);
624 return options;
625 }
626 #endif
627
628 TemporaryRef<DrawTarget>
629 Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
630 {
631 RefPtr<DrawTarget> retVal;
632
633 #ifdef USE_CAIRO
634 RefPtr<DrawTargetCairo> newTarget = new DrawTargetCairo();
635
636 if (newTarget->Init(aSurface, aSize, aFormat)) {
637 retVal = newTarget;
638 }
639
640 if (mRecorder && retVal) {
641 RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal, true);
642 return recordDT;
643 }
644 #endif
645 return retVal;
646 }
647
648 #ifdef XP_MACOSX
649 TemporaryRef<DrawTarget>
650 Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize)
651 {
652 RefPtr<DrawTarget> retVal;
653
654 RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
655
656 if (newTarget->Init(cg, aSize)) {
657 retVal = newTarget;
658 }
659
660 if (mRecorder && retVal) {
661 RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal);
662 return recordDT;
663 }
664 return retVal;
665 }
666 #endif
667
668 TemporaryRef<DataSourceSurface>
669 Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride,
670 const IntSize &aSize,
671 SurfaceFormat aFormat)
672 {
673 if (aSize.width <= 0 || aSize.height <= 0) {
674 return nullptr;
675 }
676
677 RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
678
679 if (newSurf->InitWrappingData(aData, aSize, aStride, aFormat, false)) {
680 return newSurf;
681 }
682
683 return nullptr;
684 }
685
686 TemporaryRef<DataSourceSurface>
687 Factory::CreateDataSourceSurface(const IntSize &aSize,
688 SurfaceFormat aFormat)
689 {
690 if (!CheckSurfaceSize(aSize)) {
691 return nullptr;
692 }
693
694 RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
695 if (newSurf->Init(aSize, aFormat)) {
696 return newSurf;
697 }
698
699 return nullptr;
700 }
701
702 TemporaryRef<DataSourceSurface>
703 Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize,
704 SurfaceFormat aFormat,
705 int32_t aStride)
706 {
707 if (aStride < aSize.width * BytesPerPixel(aFormat)) {
708 return nullptr;
709 }
710
711 RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
712 if (newSurf->InitWithStride(aSize, aFormat, aStride)) {
713 return newSurf;
714 }
715
716 return nullptr;
717 }
718
719 TemporaryRef<DrawEventRecorder>
720 Factory::CreateEventRecorderForFile(const char *aFilename)
721 {
722 return new DrawEventRecorderFile(aFilename);
723 }
724
725 void
726 Factory::SetGlobalEventRecorder(DrawEventRecorder *aRecorder)
727 {
728 mRecorder = aRecorder;
729 }
730
731 }
732 }

mercurial