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/. */
6 #ifndef MOZILLA_GFX_LOGGING_H_
7 #define MOZILLA_GFX_LOGGING_H_
17 #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
23 #include "mozilla/TypedEnum.h"
26 // This file gets included from nsGlobalWindow.cpp, which doesn't like
27 // having windows.h included in it. Since OutputDebugStringA is the only
28 // thing we need from windows.h, we just declare it here directly.
29 // Note: the function's documented signature is
30 // WINBASEAPI void WINAPI OutputDebugStringA(LPCSTR lpOutputString)
31 // but if we don't include windows.h, the macros WINBASEAPI, WINAPI, and
32 // LPCSTR are not defined, so we need to replace them with their expansions.
33 extern "C" __declspec(dllimport
) void __stdcall
OutputDebugStringA(const char* lpOutputString
);
36 #if defined(PR_LOGGING)
37 extern GFX2D_API PRLogModuleInfo
*GetGFX2DLog();
43 // Attempting to be consistent with prlog values, but that isn't critical
44 // (and note that 5 has a special meaning - see the description
46 const int LOG_CRITICAL
= 1;
47 const int LOG_WARNING
= 2;
48 const int LOG_DEBUG
= 3;
49 const int LOG_DEBUG_PRLOG
= 4;
50 const int LOG_EVERYTHING
= 5; // This needs to be the highest value
53 const int LOG_DEFAULT
= LOG_EVERYTHING
;
55 const int LOG_DEFAULT
= LOG_CRITICAL
;
58 #if defined(PR_LOGGING)
60 inline PRLogModuleLevel
PRLogLevelForLevel(int aLevel
) {
65 return PR_LOG_WARNING
;
78 class PreferenceAccess
81 virtual ~PreferenceAccess();
83 // This should connect the variable aVar to be updated whenever a preference
84 // aName is modified. aDefault would be used if the preference is undefined,
85 // so that we always get the valid value for aVar.
86 virtual void LivePref(const char* aName
, int32_t* aVar
, int32_t aDefault
);
89 static void SetAccess(PreferenceAccess
* aAccess
);
92 // For each preference that needs to be accessed in Moz2D, add a variable
93 // to hold it, as well as the call to LivePref in the RegisterAll() method
96 // Used to choose the level of logging we get. The higher the number,
97 // the more logging we get. Value of zero will give you no logging,
98 // 1 just errors, 2 adds warnings and 3 adds logging/debug. 4 is used to
99 // selectively enable logging on the configurations that
100 // support prlog (on other systems, 3 and 4 are the same.) For prlog,
101 // in addition to setting the value to 4, you will need to set an
102 // environment variable NSPR_LOG_MODULES to gfx:4. See prlog.h for details.
103 static int32_t sGfxLogLevel
;
106 static void RegisterAll() {
107 // The default values (last parameter) should match the initialization
108 // values in Factory.cpp, otherwise the standalone Moz2D will get different
110 sAccess
->LivePref("gfx.logging.level", &sGfxLogLevel
, LOG_DEFAULT
);
112 static PreferenceAccess
* sAccess
;
115 /// Graphics logging is available in both debug and release builds and is
116 /// controlled with a gfx.logging.level preference. If not set, the default
117 /// for the preference is 5 in the debug builds, 1 in the release builds.
119 /// gfxDebug only works in the debug builds, and is used for information
120 /// level messages, helping with debugging. In addition to only working
121 /// in the debug builds, the value of the above preference of 3 or higher
124 /// gfxWarning messages are available in both debug and release builds,
125 /// on by default in the debug builds, and off by default in the release builds.
126 /// Setting the preference gfx.logging.level to a value of 2 or higher will
127 /// show the warnings.
129 /// gfxCriticalError is available in debug and release builds by default.
130 /// It is only unavailable if gfx.logging.level is set to 0 (or less.)
131 /// It outputs the message to stderr or equivalent, like gfxWarning.
132 /// In the event of a crash, the crash report is annotated with first and
133 /// the last few of these errors, under the key GraphicsCriticalError.
134 /// The total number of errors stored in the crash report is controlled
135 /// by preference gfx.logging.crash.length (default is six, so by default,
136 /// the first as well as the last five would show up in the crash log.)
138 /// On platforms that support PR_LOGGING, the story is slightly more involved.
139 /// In that case, unless gfx.logging.level is set to 4 or higher, the output
140 /// is further controlled by "gfx2d" PR logging module. However, in the case
141 /// where such module would disable the output, in all but gfxDebug cases,
142 /// we will still send a printf.
145 // For efficiency, this method exists and copies the logic of the
146 // OutputMessage below. If making any changes here, also make it
147 // in the appropriate places in that method.
148 static bool ShouldOutputMessage(int aLevel
) {
149 if (PreferenceAccess::sGfxLogLevel
>= aLevel
) {
150 #if defined(WIN32) && !defined(PR_LOGGING)
152 #elif defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
154 #elif defined(PR_LOGGING)
155 if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel
))) {
157 } else if ((PreferenceAccess::sGfxLogLevel
>= LOG_DEBUG_PRLOG
) ||
158 (aLevel
< LOG_DEBUG
)) {
168 static void OutputMessage(const std::string
&aString
,
171 // This behavior (the higher the preference, the more we log)
172 // is consistent with what prlog does in general. Note that if prlog
173 // is in the build, but disabled, we will printf if the preferences
174 // requires us to log something (see sGfxLogLevel for the special
175 // treatment of LOG_DEBUG and LOG_DEBUG_PRLOG)
177 // If making any logic changes to this method, you should probably
178 // make the corresponding change in the ShouldOutputMessage method
180 if (PreferenceAccess::sGfxLogLevel
>= aLevel
) {
181 #if defined(WIN32) && !defined(PR_LOGGING)
182 ::OutputDebugStringA((aNoNewline
? aString
: aString
+"\n").c_str());
183 #elif defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
184 printf_stderr("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
185 #elif defined(PR_LOGGING)
186 if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel
))) {
187 PR_LogPrint("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
188 } else if ((PreferenceAccess::sGfxLogLevel
>= LOG_DEBUG_PRLOG
) ||
189 (aLevel
< LOG_DEBUG
)) {
190 printf("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
193 printf("%s%s", aString
.c_str(), aNoNewline
? "" : "\n");
199 struct CriticalLogger
{
200 static void OutputMessage(const std::string
&aString
, int aLevel
, bool aNoNewline
);
203 // Implement this interface and init the Factory with an instance to
204 // forward critical logs.
207 virtual ~LogForwarder() {}
208 virtual void Log(const std::string
&aString
) = 0;
218 NoLog
&operator <<(const T
&aLogText
) { return *this; }
221 MOZ_BEGIN_ENUM_CLASS(LogOptions
, int)
225 MOZ_END_ENUM_CLASS(LogOptions
)
229 explicit Hexa(T aVal
) : mVal(aVal
) {}
233 Hexa
<T
> hexa(T val
) { return Hexa
<T
>(val
); }
235 template<int L
, typename Logger
= BasicLogger
>
239 // The default is to have the prefix, have the new line, and for critical
240 // logs assert on each call.
241 static int DefaultOptions(bool aWithAssert
= true) {
242 return (int(LogOptions::AutoPrefix
) |
243 (aWithAssert
? int(LogOptions::AssertOnCall
) : 0));
246 // Note that we're calling BasicLogger::ShouldOutputMessage, rather than
247 // Logger::ShouldOutputMessage. Since we currently don't have a different
248 // version of that method for different loggers, this is OK. Once we do,
249 // change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage.
250 explicit Log(int aOptions
= Log::DefaultOptions(L
== LOG_CRITICAL
))
252 , mLogIt(BasicLogger::ShouldOutputMessage(L
))
254 if (mLogIt
&& AutoPrefix()) {
255 if (mOptions
& int(LogOptions::AssertOnCall
)) {
256 mMessage
<< "[GFX" << L
<< "]: ";
258 mMessage
<< "[GFX" << L
<< "-]: ";
267 if (MOZ_LIKELY(!LogIt())) return;
269 std::string str
= mMessage
.str();
274 mMessage
.str("[GFX");
275 mMessage
<< L
<< "]: ";
282 Log
&operator <<(char aChar
) {
283 if (MOZ_UNLIKELY(LogIt())) {
288 Log
&operator <<(const std::string
&aLogText
) {
289 if (MOZ_UNLIKELY(LogIt())) {
290 mMessage
<< aLogText
;
294 Log
&operator <<(const char aStr
[]) {
295 if (MOZ_UNLIKELY(LogIt())) {
296 mMessage
<< static_cast<const char*>(aStr
);
300 Log
&operator <<(bool aBool
) {
301 if (MOZ_UNLIKELY(LogIt())) {
302 mMessage
<< (aBool
? "true" : "false");
306 Log
&operator <<(int aInt
) {
307 if (MOZ_UNLIKELY(LogIt())) {
312 Log
&operator <<(unsigned int aInt
) {
313 if (MOZ_UNLIKELY(LogIt())) {
318 Log
&operator <<(long aLong
) {
319 if (MOZ_UNLIKELY(LogIt())) {
324 Log
&operator <<(unsigned long aLong
) {
325 if (MOZ_UNLIKELY(LogIt())) {
330 Log
&operator <<(long long aLong
) {
331 if (MOZ_UNLIKELY(LogIt())) {
336 Log
&operator <<(unsigned long long aLong
) {
337 if (MOZ_UNLIKELY(LogIt())) {
342 Log
&operator <<(Float aFloat
) {
343 if (MOZ_UNLIKELY(LogIt())) {
348 Log
&operator <<(double aDouble
) {
349 if (MOZ_UNLIKELY(LogIt())) {
354 template <typename T
, typename Sub
, typename Coord
>
355 Log
&operator <<(const BasePoint
<T
, Sub
, Coord
>& aPoint
) {
356 if (MOZ_UNLIKELY(LogIt())) {
357 mMessage
<< "Point" << aPoint
;
361 template <typename T
, typename Sub
>
362 Log
&operator <<(const BaseSize
<T
, Sub
>& aSize
) {
363 if (MOZ_UNLIKELY(LogIt())) {
364 mMessage
<< "Size(" << aSize
.width
<< "," << aSize
.height
<< ")";
368 template <typename T
, typename Sub
, typename Point
, typename SizeT
, typename Margin
>
369 Log
&operator <<(const BaseRect
<T
, Sub
, Point
, SizeT
, Margin
>& aRect
) {
370 if (MOZ_UNLIKELY(LogIt())) {
371 mMessage
<< "Rect" << aRect
;
375 Log
&operator<<(const Matrix
& aMatrix
) {
376 if (MOZ_UNLIKELY(LogIt())) {
377 mMessage
<< "Matrix(" << aMatrix
._11
<< " " << aMatrix
._12
<< " ; " << aMatrix
._21
<< " " << aMatrix
._22
<< " ; " << aMatrix
._31
<< " " << aMatrix
._32
<< ")";
382 Log
&operator<<(Hexa
<T
> aHex
) {
383 if (MOZ_UNLIKELY(LogIt())) {
384 mMessage
<< "0x" << std::hex
<< aHex
.mVal
<< std::dec
;
389 Log
& operator<<(SurfaceFormat aFormat
) {
390 if (MOZ_UNLIKELY(LogIt())) {
392 case SurfaceFormat::B8G8R8A8
:
393 mMessage
<< "SurfaceFormat::B8G8R8A8";
395 case SurfaceFormat::B8G8R8X8
:
396 mMessage
<< "SurfaceFormat::B8G8R8X8";
398 case SurfaceFormat::R8G8B8A8
:
399 mMessage
<< "SurfaceFormat::R8G8B8A8";
401 case SurfaceFormat::R8G8B8X8
:
402 mMessage
<< "SurfaceFormat::R8G8B8X8";
404 case SurfaceFormat::R5G6B5
:
405 mMessage
<< "SurfaceFormat::R5G6B5";
407 case SurfaceFormat::A8
:
408 mMessage
<< "SurfaceFormat::A8";
410 case SurfaceFormat::YUV
:
411 mMessage
<< "SurfaceFormat::YUV";
413 case SurfaceFormat::UNKNOWN
:
414 mMessage
<< "SurfaceFormat::UNKNOWN";
417 mMessage
<< "Invalid SurfaceFormat (" << (int)aFormat
<< ")";
424 Log
& operator<<(SurfaceType aType
) {
425 if (MOZ_UNLIKELY(LogIt())) {
427 case SurfaceType::DATA
:
428 mMessage
<< "SurfaceType::DATA";
430 case SurfaceType::D2D1_BITMAP
:
431 mMessage
<< "SurfaceType::D2D1_BITMAP";
433 case SurfaceType::D2D1_DRAWTARGET
:
434 mMessage
<< "SurfaceType::D2D1_DRAWTARGET";
436 case SurfaceType::CAIRO
:
437 mMessage
<< "SurfaceType::CAIRO";
439 case SurfaceType::CAIRO_IMAGE
:
440 mMessage
<< "SurfaceType::CAIRO_IMAGE";
442 case SurfaceType::COREGRAPHICS_IMAGE
:
443 mMessage
<< "SurfaceType::COREGRAPHICS_IMAGE";
445 case SurfaceType::COREGRAPHICS_CGCONTEXT
:
446 mMessage
<< "SurfaceType::COREGRAPHICS_CGCONTEXT";
448 case SurfaceType::SKIA
:
449 mMessage
<< "SurfaceType::SKIA";
451 case SurfaceType::DUAL_DT
:
452 mMessage
<< "SurfaceType::DUAL_DT";
454 case SurfaceType::D2D1_1_IMAGE
:
455 mMessage
<< "SurfaceType::D2D1_1_IMAGE";
457 case SurfaceType::RECORDING
:
458 mMessage
<< "SurfaceType::RECORDING";
460 case SurfaceType::TILED
:
461 mMessage
<< "SurfaceType::TILED";
464 mMessage
<< "Invalid SurfaceType (" << (int)aType
<< ")";
471 inline bool LogIt() const { return mLogIt
; }
472 inline bool NoNewline() const { return mOptions
& int(LogOptions::NoNewline
); }
473 inline bool AutoPrefix() const { return mOptions
& int(LogOptions::AutoPrefix
); }
477 void WriteLog(const std::string
&aString
) {
478 if (MOZ_UNLIKELY(LogIt())) {
479 Logger::OutputMessage(aString
, L
, NoNewline());
480 if (mOptions
& int(LogOptions::AssertOnCall
)) {
481 MOZ_ASSERT(false, "An assert from the graphics logger");
486 std::stringstream mMessage
;
491 typedef Log
<LOG_DEBUG
> DebugLog
;
492 typedef Log
<LOG_WARNING
> WarningLog
;
493 typedef Log
<LOG_CRITICAL
, CriticalLogger
> CriticalLog
;
496 #define gfxDebug mozilla::gfx::DebugLog
498 #define gfxDebug if (1) ; else mozilla::gfx::NoLog
500 #ifdef GFX_LOG_WARNING
501 #define gfxWarning mozilla::gfx::WarningLog
503 #define gfxWarning if (1) ; else mozilla::gfx::NoLog
506 // This log goes into crash reports, use with care.
507 #define gfxCriticalError mozilla::gfx::CriticalLog
509 // See nsDebug.h and the NS_WARN_IF macro
512 // For now, have MOZ2D_ERROR_IF available in debug and non-debug builds
513 inline bool MOZ2D_error_if_impl(bool aCondition
, const char* aExpr
,
514 const char* aFile
, int32_t aLine
)
516 if (MOZ_UNLIKELY(aCondition
)) {
517 gfxCriticalError() << aExpr
<< " at " << aFile
<< ":" << aLine
;
521 #define MOZ2D_ERROR_IF(condition) \
522 MOZ2D_error_if_impl(condition, #condition, __FILE__, __LINE__)
525 inline bool MOZ2D_warn_if_impl(bool aCondition
, const char* aExpr
,
526 const char* aFile
, int32_t aLine
)
528 if (MOZ_UNLIKELY(aCondition
)) {
529 gfxWarning() << aExpr
<< " at " << aFile
<< ":" << aLine
;
533 #define MOZ2D_WARN_IF(condition) \
534 MOZ2D_warn_if_impl(condition, #condition, __FILE__, __LINE__)
536 #define MOZ2D_WARN_IF(condition) (bool)(condition)
540 const int INDENT_PER_LEVEL
= 2;
545 explicit TreeLog(const std::string
& aPrefix
= "")
546 : mLog(int(LogOptions::NoNewline
)),
550 mConditionedOnPref(false),
551 mPrefFunction(nullptr) {}
553 template <typename T
>
554 TreeLog
& operator<<(const T
& aObject
) {
555 if (mConditionedOnPref
&& !mPrefFunction()) {
559 mLog
<< '[' << mPrefix
<< "] " << std::string(mDepth
* INDENT_PER_LEVEL
, ' ');
560 mStartOfLine
= false;
563 if (EndsInNewline(aObject
)) {
564 // Don't indent right here as the user may change the indent
565 // between now and the first output to the next line.
572 void IncreaseIndent() { ++mDepth
; }
573 void DecreaseIndent() { --mDepth
; }
575 void ConditionOnPrefFunction(bool(*aPrefFunction
)()) {
576 mConditionedOnPref
= true;
577 mPrefFunction
= aPrefFunction
;
584 bool mConditionedOnPref
;
585 bool (*mPrefFunction
)();
587 template <typename T
>
588 static bool EndsInNewline(const T
& aObject
) {
592 static bool EndsInNewline(const std::string
& aString
) {
593 return !aString
.empty() && aString
[aString
.length() - 1] == '\n';
596 static bool EndsInNewline(char aChar
) {
597 return aChar
== '\n';
600 static bool EndsInNewline(const char* aString
) {
601 return EndsInNewline(std::string(aString
));
608 explicit TreeAutoIndent(TreeLog
& aTreeLog
) : mTreeLog(aTreeLog
) {
609 mTreeLog
.IncreaseIndent();
612 mTreeLog
.DecreaseIndent();
621 #endif /* MOZILLA_GFX_LOGGING_H_ */