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 #ifndef MOZILLA_GFX_LOGGING_H_
8 #define MOZILLA_GFX_LOGGING_H_
16 # include "mozilla/Logging.h"
19 #if defined(MOZ_WIDGET_ANDROID)
23 #include "mozilla/Atomics.h"
24 #include "mozilla/StaticPrefs_gfx.h"
28 #include "LoggingConstants.h"
30 #if defined(MOZ_LOGGING)
31 extern GFX2D_API
mozilla::LogModule
* GetGFX2DLog();
37 #if defined(MOZ_LOGGING)
38 inline mozilla::LogLevel
PRLogLevelForLevel(int aLevel
) {
41 return LogLevel::Error
;
43 return LogLevel::Warning
;
45 return LogLevel::Debug
;
47 return LogLevel::Debug
;
49 return LogLevel::Error
;
51 return LogLevel::Debug
;
55 /// Graphics logging is available in both debug and release builds and is
56 /// controlled with a gfx.logging.level preference. If not set, the default
57 /// for the preference is 5 in the debug builds, 1 in the release builds.
59 /// gfxDebug only works in the debug builds, and is used for information
60 /// level messages, helping with debugging. In addition to only working
61 /// in the debug builds, the value of the above preference of 3 or higher
64 /// gfxWarning messages are available in both debug and release builds,
65 /// on by default in the debug builds, and off by default in the release builds.
66 /// Setting the preference gfx.logging.level to a value of 2 or higher will
67 /// show the warnings.
69 /// gfxCriticalError is available in debug and release builds by default.
70 /// It is only unavailable if gfx.logging.level is set to 0 (or less.)
71 /// It outputs the message to stderr or equivalent, like gfxWarning.
72 /// In the event of a crash, the crash report is annotated with first and
73 /// the last few of these errors, under the key GraphicsCriticalError.
74 /// The total number of errors stored in the crash report is controlled
75 /// by preference gfx.logging.crash.length.
77 /// On platforms that support MOZ_LOGGING, the story is slightly more involved.
78 /// In that case, unless gfx.logging.level is set to 4 or higher, the output
79 /// is further controlled by the "gfx2d" logging module. However, in the case
80 /// where such module would disable the output, in all but gfxDebug cases,
81 /// we will still send a printf.
83 // The range is due to the values set in Histograms.json
84 enum class LogReason
: int {
85 MustBeMoreThanThis
= -1,
86 // Start. Do not insert, always add at end. If you remove items,
87 // make sure the other items retain their values.
88 D3D11InvalidCallDeviceRemoved
= 0,
98 FilterInputData
, // 10
102 FilterNodeD2D1Target
,
103 FilterNodeD2D1Backend
,
104 SourceSurfaceIncompatible
,
105 GlyphAllocFailedCairo
,
109 IncompatibleBasicTexturedEffect
,
111 PAllocTextureBackendMismatch
,
112 GetFontFileDataFailed
,
113 MessageChannelCloseFailure
,
114 MessageChannelInvalidHandle
,
115 TextureAliveAfterShutdown
,
118 AsyncTransactionTimeout
, // 30
121 AlphaWithBasicClient
,
125 NativeFontResourceNotFound
,
126 UnscaledFontNotFound
,
128 InvalidLayerType
, // 40
130 MustBeLessThanThis
= 101,
134 // For efficiency, this method exists and copies the logic of the
135 // OutputMessage below. If making any changes here, also make it
136 // in the appropriate places in that method.
137 static bool ShouldOutputMessage(int aLevel
) {
138 if (StaticPrefs::gfx_logging_level() >= aLevel
) {
139 #if defined(MOZ_WIDGET_ANDROID)
142 # if defined(MOZ_LOGGING)
143 if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel
))) {
147 if ((StaticPrefs::gfx_logging_level() >= LOG_DEBUG_PRLOG
) ||
148 (aLevel
< LOG_DEBUG
)) {
156 // Only for really critical errors.
157 static void CrashAction(LogReason aReason
) {}
159 static void OutputMessage(const std::string
& aString
, int aLevel
,
161 // This behavior (the higher the preference, the more we log)
162 // is consistent with what prlog does in general. Note that if prlog
163 // is in the build, but disabled, we will printf if the preferences
164 // requires us to log something.
166 // If making any logic changes to this method, you should probably
167 // make the corresponding change in the ShouldOutputMessage method
169 if (StaticPrefs::gfx_logging_level() >= aLevel
) {
170 #if defined(MOZ_WIDGET_ANDROID)
171 printf_stderr("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
173 # if defined(MOZ_LOGGING)
174 if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel
))) {
175 MOZ_LOG(GetGFX2DLog(), PRLogLevelForLevel(aLevel
),
176 ("%s%s", aString
.c_str(), aNoNewline
? "" : "\n"));
179 if ((StaticPrefs::gfx_logging_level() >= LOG_DEBUG_PRLOG
) ||
180 (aLevel
< LOG_DEBUG
)) {
181 printf("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
188 struct CriticalLogger
{
189 static void OutputMessage(const std::string
& aString
, int aLevel
,
191 static void CrashAction(LogReason aReason
);
194 // The int is the index of the Log call; if the number of logs exceeds some
195 // preset capacity we may not get all of them, so the indices help figure out
196 // which ones we did save. The double is expected to be the "TimeDuration",
197 // time in seconds since the process creation.
198 typedef std::tuple
<int32_t, std::string
, double> LoggingRecordEntry
;
200 // Implement this interface and init the Factory with an instance to
201 // forward critical logs.
202 typedef std::vector
<LoggingRecordEntry
> LoggingRecord
;
205 virtual ~LogForwarder() = default;
206 virtual void Log(const std::string
& aString
) = 0;
207 virtual void CrashAction(LogReason aReason
) = 0;
208 virtual bool UpdateStringsVector(const std::string
& aString
) = 0;
210 // Provide a copy of the logs to the caller.
211 virtual LoggingRecord
LoggingRecordCopy() = 0;
220 MOZ_IMPLICIT
NoLog(const NoLog
&) = default;
222 template <typename T
>
223 NoLog
& operator<<(const T
& aLogText
) {
228 enum class LogOptions
: int {
235 template <typename T
>
237 explicit Hexa(T aVal
) : mVal(aVal
) {}
240 template <typename T
>
241 Hexa
<T
> hexa(T val
) {
246 void LogWStr(const wchar_t* aStr
, std::stringstream
& aOut
);
249 template <int L
, typename Logger
= BasicLogger
>
252 // The default is to have the prefix, have the new line, and for critical
253 // logs assert on each call.
254 static int DefaultOptions(bool aWithAssert
= true) {
255 return (int(LogOptions::AutoPrefix
) |
256 (aWithAssert
? int(LogOptions::AssertOnCall
) : 0));
259 // Note that we're calling BasicLogger::ShouldOutputMessage, rather than
260 // Logger::ShouldOutputMessage. Since we currently don't have a different
261 // version of that method for different loggers, this is OK. Once we do,
262 // change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage.
263 explicit Log(int aOptions
= Log::DefaultOptions(L
== LOG_CRITICAL
),
264 LogReason aReason
= LogReason::MustBeMoreThanThis
)
265 : mOptions(0), mLogIt(false) {
266 Init(aOptions
, BasicLogger::ShouldOutputMessage(L
), aReason
);
272 if (MOZ_LIKELY(!LogIt())) return;
274 std::string str
= mMessage
.str();
281 Log
& operator<<(char aChar
) {
282 if (MOZ_UNLIKELY(LogIt())) {
287 Log
& operator<<(const std::string
& aLogText
) {
288 if (MOZ_UNLIKELY(LogIt())) {
289 mMessage
<< aLogText
;
293 Log
& operator<<(const char aStr
[]) {
294 if (MOZ_UNLIKELY(LogIt())) {
295 mMessage
<< static_cast<const char*>(aStr
);
300 Log
& operator<<(const wchar_t aWStr
[]) {
301 if (MOZ_UNLIKELY(LogIt())) {
302 LogWStr(aWStr
, mMessage
);
307 Log
& operator<<(bool aBool
) {
308 if (MOZ_UNLIKELY(LogIt())) {
309 mMessage
<< (aBool
? "true" : "false");
313 Log
& operator<<(int aInt
) {
314 if (MOZ_UNLIKELY(LogIt())) {
319 Log
& operator<<(unsigned int aInt
) {
320 if (MOZ_UNLIKELY(LogIt())) {
325 Log
& operator<<(long aLong
) {
326 if (MOZ_UNLIKELY(LogIt())) {
331 Log
& operator<<(unsigned long aLong
) {
332 if (MOZ_UNLIKELY(LogIt())) {
337 Log
& operator<<(long long aLong
) {
338 if (MOZ_UNLIKELY(LogIt())) {
343 Log
& operator<<(unsigned long long aLong
) {
344 if (MOZ_UNLIKELY(LogIt())) {
349 Log
& operator<<(Float aFloat
) {
350 if (MOZ_UNLIKELY(LogIt())) {
355 Log
& operator<<(double aDouble
) {
356 if (MOZ_UNLIKELY(LogIt())) {
361 Log
& operator<<(const sRGBColor
& aColor
) {
362 if (MOZ_UNLIKELY(LogIt())) {
363 mMessage
<< "sRGBColor(" << aColor
.r
<< ", " << aColor
.g
<< ", "
364 << aColor
.b
<< ", " << aColor
.a
<< ")";
368 Log
& operator<<(const DeviceColor
& aColor
) {
369 if (MOZ_UNLIKELY(LogIt())) {
370 mMessage
<< "DeviceColor(" << aColor
.r
<< ", " << aColor
.g
<< ", "
371 << aColor
.b
<< ", " << aColor
.a
<< ")";
375 template <typename T
, typename Sub
, typename Coord
>
376 Log
& operator<<(const BasePoint
<T
, Sub
, Coord
>& aPoint
) {
377 if (MOZ_UNLIKELY(LogIt())) {
378 mMessage
<< "Point" << aPoint
;
382 template <typename T
, typename Sub
, typename Coord
>
383 Log
& operator<<(const BaseSize
<T
, Sub
, Coord
>& aSize
) {
384 if (MOZ_UNLIKELY(LogIt())) {
385 mMessage
<< "Size(" << aSize
.width
<< "," << aSize
.height
<< ")";
389 template <typename T
, typename Sub
, typename Point
, typename SizeT
,
391 Log
& operator<<(const BaseRect
<T
, Sub
, Point
, SizeT
, Margin
>& aRect
) {
392 if (MOZ_UNLIKELY(LogIt())) {
393 mMessage
<< "Rect" << aRect
;
397 Log
& operator<<(const Matrix
& aMatrix
) {
398 if (MOZ_UNLIKELY(LogIt())) {
399 mMessage
<< "Matrix(" << aMatrix
._11
<< " " << aMatrix
._12
<< " ; "
400 << aMatrix
._21
<< " " << aMatrix
._22
<< " ; " << aMatrix
._31
401 << " " << aMatrix
._32
<< ")";
405 template <typename T
>
406 Log
& operator<<(Hexa
<T
> aHex
) {
407 if (MOZ_UNLIKELY(LogIt())) {
408 mMessage
<< std::showbase
<< std::hex
<< aHex
.mVal
<< std::noshowbase
414 Log
& operator<<(const SourceSurface
* aSurface
) {
415 if (MOZ_UNLIKELY(LogIt())) {
416 mMessage
<< "SourceSurface(" << (void*)(aSurface
) << ")";
420 Log
& operator<<(const Path
* aPath
) {
421 if (MOZ_UNLIKELY(LogIt())) {
422 mMessage
<< "Path(" << (void*)(aPath
) << ")";
426 Log
& operator<<(const Pattern
* aPattern
) {
427 if (MOZ_UNLIKELY(LogIt())) {
428 mMessage
<< "Pattern(" << (void*)(aPattern
) << ")";
432 Log
& operator<<(const ScaledFont
* aFont
) {
433 if (MOZ_UNLIKELY(LogIt())) {
434 mMessage
<< "ScaledFont(" << (void*)(aFont
) << ")";
438 Log
& operator<<(const FilterNode
* aFilter
) {
439 if (MOZ_UNLIKELY(LogIt())) {
440 mMessage
<< "FilterNode(" << (void*)(aFilter
) << ")";
444 Log
& operator<<(const DrawOptions
& aOptions
) {
445 if (MOZ_UNLIKELY(LogIt())) {
446 mMessage
<< "DrawOptions(" << aOptions
.mAlpha
<< ", ";
447 (*this) << aOptions
.mCompositionOp
;
449 (*this) << aOptions
.mAntialiasMode
;
454 Log
& operator<<(const DrawSurfaceOptions
& aOptions
) {
455 if (MOZ_UNLIKELY(LogIt())) {
456 mMessage
<< "DrawSurfaceOptions(";
457 (*this) << aOptions
.mSamplingFilter
;
459 (*this) << aOptions
.mSamplingBounds
;
465 Log
& operator<<(SamplingBounds aBounds
) {
466 if (MOZ_UNLIKELY(LogIt())) {
468 case SamplingBounds::UNBOUNDED
:
469 mMessage
<< "SamplingBounds::UNBOUNDED";
471 case SamplingBounds::BOUNDED
:
472 mMessage
<< "SamplingBounds::BOUNDED";
475 mMessage
<< "Invalid SamplingBounds (" << (int)aBounds
<< ")";
481 Log
& operator<<(SamplingFilter aFilter
) {
482 if (MOZ_UNLIKELY(LogIt())) {
484 case SamplingFilter::GOOD
:
485 mMessage
<< "SamplingFilter::GOOD";
487 case SamplingFilter::LINEAR
:
488 mMessage
<< "SamplingFilter::LINEAR";
490 case SamplingFilter::POINT
:
491 mMessage
<< "SamplingFilter::POINT";
494 mMessage
<< "Invalid SamplingFilter (" << (int)aFilter
<< ")";
500 Log
& operator<<(AntialiasMode aMode
) {
501 if (MOZ_UNLIKELY(LogIt())) {
503 case AntialiasMode::NONE
:
504 mMessage
<< "AntialiasMode::NONE";
506 case AntialiasMode::GRAY
:
507 mMessage
<< "AntialiasMode::GRAY";
509 case AntialiasMode::SUBPIXEL
:
510 mMessage
<< "AntialiasMode::SUBPIXEL";
512 case AntialiasMode::DEFAULT
:
513 mMessage
<< "AntialiasMode::DEFAULT";
516 mMessage
<< "Invalid AntialiasMode (" << (int)aMode
<< ")";
522 Log
& operator<<(CompositionOp aOp
) {
523 if (MOZ_UNLIKELY(LogIt())) {
525 case CompositionOp::OP_CLEAR
:
526 mMessage
<< "CompositionOp::OP_CLEAR";
528 case CompositionOp::OP_OVER
:
529 mMessage
<< "CompositionOp::OP_OVER";
531 case CompositionOp::OP_ADD
:
532 mMessage
<< "CompositionOp::OP_ADD";
534 case CompositionOp::OP_ATOP
:
535 mMessage
<< "CompositionOp::OP_ATOP";
537 case CompositionOp::OP_OUT
:
538 mMessage
<< "CompositionOp::OP_OUT";
540 case CompositionOp::OP_IN
:
541 mMessage
<< "CompositionOp::OP_IN";
543 case CompositionOp::OP_SOURCE
:
544 mMessage
<< "CompositionOp::OP_SOURCE";
546 case CompositionOp::OP_DEST_IN
:
547 mMessage
<< "CompositionOp::OP_DEST_IN";
549 case CompositionOp::OP_DEST_OUT
:
550 mMessage
<< "CompositionOp::OP_DEST_OUT";
552 case CompositionOp::OP_DEST_OVER
:
553 mMessage
<< "CompositionOp::OP_DEST_OVER";
555 case CompositionOp::OP_DEST_ATOP
:
556 mMessage
<< "CompositionOp::OP_DEST_ATOP";
558 case CompositionOp::OP_XOR
:
559 mMessage
<< "CompositionOp::OP_XOR";
561 case CompositionOp::OP_MULTIPLY
:
562 mMessage
<< "CompositionOp::OP_MULTIPLY";
564 case CompositionOp::OP_SCREEN
:
565 mMessage
<< "CompositionOp::OP_SCREEN";
567 case CompositionOp::OP_OVERLAY
:
568 mMessage
<< "CompositionOp::OP_OVERLAY";
570 case CompositionOp::OP_DARKEN
:
571 mMessage
<< "CompositionOp::OP_DARKEN";
573 case CompositionOp::OP_LIGHTEN
:
574 mMessage
<< "CompositionOp::OP_LIGHTEN";
576 case CompositionOp::OP_COLOR_DODGE
:
577 mMessage
<< "CompositionOp::OP_COLOR_DODGE";
579 case CompositionOp::OP_COLOR_BURN
:
580 mMessage
<< "CompositionOp::OP_COLOR_BURN";
582 case CompositionOp::OP_HARD_LIGHT
:
583 mMessage
<< "CompositionOp::OP_HARD_LIGHT";
585 case CompositionOp::OP_SOFT_LIGHT
:
586 mMessage
<< "CompositionOp::OP_SOFT_LIGHT";
588 case CompositionOp::OP_DIFFERENCE
:
589 mMessage
<< "CompositionOp::OP_DIFFERENCE";
591 case CompositionOp::OP_EXCLUSION
:
592 mMessage
<< "CompositionOp::OP_EXCLUSION";
594 case CompositionOp::OP_HUE
:
595 mMessage
<< "CompositionOp::OP_HUE";
597 case CompositionOp::OP_SATURATION
:
598 mMessage
<< "CompositionOp::OP_SATURATION";
600 case CompositionOp::OP_COLOR
:
601 mMessage
<< "CompositionOp::OP_COLOR";
603 case CompositionOp::OP_LUMINOSITY
:
604 mMessage
<< "CompositionOp::OP_LUMINOSITY";
606 case CompositionOp::OP_COUNT
:
607 mMessage
<< "CompositionOp::OP_COUNT";
610 mMessage
<< "Invalid CompositionOp (" << (int)aOp
<< ")";
616 Log
& operator<<(SurfaceFormat aFormat
) {
617 if (MOZ_UNLIKELY(LogIt())) {
619 case SurfaceFormat::B8G8R8A8
:
620 mMessage
<< "SurfaceFormat::B8G8R8A8";
622 case SurfaceFormat::B8G8R8X8
:
623 mMessage
<< "SurfaceFormat::B8G8R8X8";
625 case SurfaceFormat::R8G8B8A8
:
626 mMessage
<< "SurfaceFormat::R8G8B8A8";
628 case SurfaceFormat::R8G8B8X8
:
629 mMessage
<< "SurfaceFormat::R8G8B8X8";
631 case SurfaceFormat::R5G6B5_UINT16
:
632 mMessage
<< "SurfaceFormat::R5G6B5_UINT16";
634 case SurfaceFormat::A8
:
635 mMessage
<< "SurfaceFormat::A8";
637 case SurfaceFormat::YUV
:
638 mMessage
<< "SurfaceFormat::YUV";
640 case SurfaceFormat::UNKNOWN
:
641 mMessage
<< "SurfaceFormat::UNKNOWN";
644 mMessage
<< "Invalid SurfaceFormat (" << (int)aFormat
<< ")";
651 Log
& operator<<(SurfaceType aType
) {
652 if (MOZ_UNLIKELY(LogIt())) {
654 case SurfaceType::DATA
:
655 mMessage
<< "SurfaceType::DATA";
657 case SurfaceType::D2D1_BITMAP
:
658 mMessage
<< "SurfaceType::D2D1_BITMAP";
660 case SurfaceType::D2D1_DRAWTARGET
:
661 mMessage
<< "SurfaceType::D2D1_DRAWTARGET";
663 case SurfaceType::CAIRO
:
664 mMessage
<< "SurfaceType::CAIRO";
666 case SurfaceType::CAIRO_IMAGE
:
667 mMessage
<< "SurfaceType::CAIRO_IMAGE";
669 case SurfaceType::COREGRAPHICS_IMAGE
:
670 mMessage
<< "SurfaceType::COREGRAPHICS_IMAGE";
672 case SurfaceType::COREGRAPHICS_CGCONTEXT
:
673 mMessage
<< "SurfaceType::COREGRAPHICS_CGCONTEXT";
675 case SurfaceType::SKIA
:
676 mMessage
<< "SurfaceType::SKIA";
678 case SurfaceType::D2D1_1_IMAGE
:
679 mMessage
<< "SurfaceType::D2D1_1_IMAGE";
681 case SurfaceType::RECORDING
:
682 mMessage
<< "SurfaceType::RECORDING";
684 case SurfaceType::DATA_SHARED
:
685 mMessage
<< "SurfaceType::DATA_SHARED";
687 case SurfaceType::DATA_RECYCLING_SHARED
:
688 mMessage
<< "SurfaceType::DATA_RECYCLING_SHARED";
690 case SurfaceType::DATA_ALIGNED
:
691 mMessage
<< "SurfaceType::DATA_ALIGNED";
693 case SurfaceType::DATA_SHARED_WRAPPER
:
694 mMessage
<< "SurfaceType::DATA_SHARED_WRAPPER";
696 case SurfaceType::DATA_MAPPED
:
697 mMessage
<< "SurfaceType::DATA_MAPPED";
699 case SurfaceType::WEBGL
:
700 mMessage
<< "SurfaceType::WEBGL";
703 mMessage
<< "Invalid SurfaceType (" << (int)aType
<< ")";
710 inline bool LogIt() const { return mLogIt
; }
711 inline bool NoNewline() const {
712 return mOptions
& int(LogOptions::NoNewline
);
714 inline bool AutoPrefix() const {
715 return mOptions
& int(LogOptions::AutoPrefix
);
717 inline bool ValidReason() const {
718 return (int)mReason
> (int)LogReason::MustBeMoreThanThis
&&
719 (int)mReason
< (int)LogReason::MustBeLessThanThis
;
722 // We do not want this version to do any work, and stringstream can't be
723 // copied anyway. It does come in handy for the "Once" macro defined below.
724 MOZ_IMPLICIT
Log(const Log
& log
) { Init(log
.mOptions
, false, log
.mReason
); }
727 // Initialization common to two constructors
728 void Init(int aOptions
, bool aLogIt
, LogReason aReason
) {
734 if (mOptions
& int(LogOptions::AssertOnCall
)) {
735 mMessage
<< "[GFX" << L
;
737 mMessage
<< "[GFX" << L
<< "-";
740 if ((mOptions
& int(LogOptions::CrashAction
)) && ValidReason()) {
741 mMessage
<< " " << (int)mReason
;
749 void WriteLog(const std::string
& aString
) {
750 if (MOZ_UNLIKELY(LogIt())) {
751 Logger::OutputMessage(aString
, L
, NoNewline());
752 // Assert if required. We don't have a three parameter MOZ_ASSERT
753 // so use the underlying functions instead (see bug 1281702):
755 if (mOptions
& int(LogOptions::AssertOnCall
)) {
756 MOZ_ReportAssertionFailure(aString
.c_str(), __FILE__
, __LINE__
);
757 MOZ_CRASH("GFX: An assert from the graphics logger");
760 if ((mOptions
& int(LogOptions::CrashAction
)) && ValidReason()) {
761 Logger::CrashAction(mReason
);
766 std::stringstream mMessage
;
772 typedef Log
<LOG_DEBUG
> DebugLog
;
773 typedef Log
<LOG_WARNING
> WarningLog
;
774 typedef Log
<LOG_CRITICAL
, CriticalLogger
> CriticalLog
;
776 // Macro to glue names to get us less chance of name clashing.
777 #if defined GFX_LOGGING_GLUE1 || defined GFX_LOGGING_GLUE
778 # error "Clash of the macro GFX_LOGGING_GLUE1 or GFX_LOGGING_GLUE"
780 #define GFX_LOGGING_GLUE1(x, y) x##y
781 #define GFX_LOGGING_GLUE(x, y) GFX_LOGGING_GLUE1(x, y)
783 // This log goes into crash reports, use with care.
784 #define gfxCriticalError mozilla::gfx::CriticalLog
785 #define gfxCriticalErrorOnce \
786 static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine, __LINE__) = \
789 // This is a shortcut for errors we want logged in crash reports/about support
790 // but we do not want asserting. These are available in all builds, so it is
791 // not worth trying to do magic to avoid matching the syntax of
793 // So, this one is used as
794 // gfxCriticalNote << "Something to report and not assert";
795 // while the critical error is
796 // gfxCriticalError() << "Something to report and assert";
797 #define gfxCriticalNote \
798 gfxCriticalError(gfxCriticalError::DefaultOptions(false))
799 #define gfxCriticalNoteOnce \
800 static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine, __LINE__) = \
803 // The "once" versions will only trigger the first time through. You can do
804 // this: gfxCriticalErrorOnce() << "This message only shows up once; instead of
805 // the usual: static bool firstTime = true; if (firstTime) {
806 // firstTime = false;
807 // gfxCriticalError() << "This message only shows up once;
810 # define gfxDebug mozilla::gfx::DebugLog
811 # define gfxDebugOnce \
812 static gfxDebug GFX_LOGGING_GLUE(sOnceAtLine, __LINE__) = gfxDebug
819 # define gfxDebugOnce \
826 // Have gfxWarning available (behind a runtime preference)
827 #define gfxWarning mozilla::gfx::WarningLog
828 #define gfxWarningOnce \
829 static gfxWarning GFX_LOGGING_GLUE(sOnceAtLine, __LINE__) = gfxWarning
831 // In the debug build, this is equivalent to the default gfxCriticalError.
832 // In the non-debug build, on nightly and dev edition, it will MOZ_CRASH.
833 // On beta and release versions, it will telemetry count, but proceed.
835 // You should create a (new) enum in the LogReason and use it for the reason
836 // parameter to ensure uniqueness.
837 #define gfxDevCrash(reason) \
838 gfxCriticalError(int(gfx::LogOptions::AutoPrefix) | \
839 int(gfx::LogOptions::AssertOnCall) | \
840 int(gfx::LogOptions::CrashAction), \
843 // See nsDebug.h and the NS_WARN_IF macro
846 // For now, have MOZ2D_ERROR_IF available in debug and non-debug builds
847 inline bool MOZ2D_error_if_impl(bool aCondition
, const char* aExpr
,
848 const char* aFile
, int32_t aLine
) {
849 if (MOZ_UNLIKELY(aCondition
)) {
850 gfxCriticalError() << aExpr
<< " at " << aFile
<< ":" << aLine
;
854 # define MOZ2D_ERROR_IF(condition) \
855 MOZ2D_error_if_impl(condition, #condition, __FILE__, __LINE__)
858 inline bool MOZ2D_warn_if_impl(bool aCondition
, const char* aExpr
,
859 const char* aFile
, int32_t aLine
) {
860 if (MOZ_UNLIKELY(aCondition
)) {
861 gfxWarning() << aExpr
<< " at " << aFile
<< ":" << aLine
;
865 # define MOZ2D_WARN_IF(condition) \
866 MOZ2D_warn_if_impl(condition, #condition, __FILE__, __LINE__)
868 # define MOZ2D_WARN_IF(condition) (bool)(condition)
872 const int INDENT_PER_LEVEL
= 2;
874 template <int Level
= LOG_DEBUG
>
877 explicit TreeLog(const std::string
& aPrefix
= "")
878 : mLog(int(LogOptions::NoNewline
)),
882 mConditionedOnPref(false),
883 mPrefFunction(nullptr) {}
885 template <typename T
>
886 TreeLog
& operator<<(const T
& aObject
) {
887 if (mConditionedOnPref
&& !mPrefFunction()) {
891 if (!mPrefix
.empty()) {
892 mLog
<< '[' << mPrefix
<< "] ";
894 mLog
<< std::string(mDepth
* INDENT_PER_LEVEL
, ' ');
895 mStartOfLine
= false;
898 if (EndsInNewline(aObject
)) {
899 // Don't indent right here as the user may change the indent
900 // between now and the first output to the next line.
907 void IncreaseIndent() { ++mDepth
; }
908 void DecreaseIndent() {
909 MOZ_ASSERT(mDepth
> 0);
913 void ConditionOnPrefFunction(bool (*aPrefFunction
)()) {
914 mConditionedOnPref
= true;
915 mPrefFunction
= aPrefFunction
;
923 bool mConditionedOnPref
;
924 bool (*mPrefFunction
)();
926 template <typename T
>
927 static bool EndsInNewline(const T
& aObject
) {
931 static bool EndsInNewline(const std::string
& aString
) {
932 return !aString
.empty() && aString
[aString
.length() - 1] == '\n';
935 static bool EndsInNewline(char aChar
) { return aChar
== '\n'; }
937 static bool EndsInNewline(const char* aString
) {
938 return EndsInNewline(std::string(aString
));
942 template <int Level
= LOG_DEBUG
>
943 class TreeAutoIndent final
{
945 explicit TreeAutoIndent(TreeLog
<Level
>& aTreeLog
) : mTreeLog(aTreeLog
) {
946 mTreeLog
.IncreaseIndent();
949 TreeAutoIndent(const TreeAutoIndent
& aTreeAutoIndent
)
950 : mTreeLog(aTreeAutoIndent
.mTreeLog
) {
951 mTreeLog
.IncreaseIndent();
954 TreeAutoIndent
& operator=(const TreeAutoIndent
& aTreeAutoIndent
) = delete;
956 ~TreeAutoIndent() { mTreeLog
.DecreaseIndent(); }
959 TreeLog
<Level
>& mTreeLog
;
963 } // namespace mozilla
965 #endif /* MOZILLA_GFX_LOGGING_H_ */