michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_GFX_LOGGING_H_ michael@0: #define MOZILLA_GFX_LOGGING_H_ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsDebug.h" michael@0: #include "Point.h" michael@0: #include "BaseRect.h" michael@0: #include "Matrix.h" michael@0: #include "mozilla/TypedEnum.h" michael@0: michael@0: #ifdef WIN32 michael@0: // This file gets included from nsGlobalWindow.cpp, which doesn't like michael@0: // having windows.h included in it. Since OutputDebugStringA is the only michael@0: // thing we need from windows.h, we just declare it here directly. michael@0: // Note: the function's documented signature is michael@0: // WINBASEAPI void WINAPI OutputDebugStringA(LPCSTR lpOutputString) michael@0: // but if we don't include windows.h, the macros WINBASEAPI, WINAPI, and michael@0: // LPCSTR are not defined, so we need to replace them with their expansions. michael@0: extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString); michael@0: #endif michael@0: michael@0: #if defined(DEBUG) || defined(PR_LOGGING) michael@0: #include michael@0: michael@0: extern GFX2D_API PRLogModuleInfo *GetGFX2DLog(); michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: michael@0: const int LOG_DEBUG = 1; michael@0: const int LOG_WARNING = 2; michael@0: michael@0: #if defined(DEBUG) || defined(PR_LOGGING) michael@0: michael@0: inline PRLogModuleLevel PRLogLevelForLevel(int aLevel) { michael@0: switch (aLevel) { michael@0: case LOG_DEBUG: michael@0: return PR_LOG_DEBUG; michael@0: case LOG_WARNING: michael@0: return PR_LOG_WARNING; michael@0: } michael@0: return PR_LOG_DEBUG; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: extern GFX2D_API int sGfxLogLevel; michael@0: michael@0: static inline void OutputMessage(const std::string &aString, int aLevel) { michael@0: #if defined(WIN32) && !defined(PR_LOGGING) michael@0: if (aLevel >= sGfxLogLevel) { michael@0: ::OutputDebugStringA(aString.c_str()); michael@0: } michael@0: #elif defined(PR_LOGGING) && !(defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)) michael@0: if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) { michael@0: PR_LogPrint(aString.c_str()); michael@0: } michael@0: #else michael@0: if (aLevel >= sGfxLogLevel) { michael@0: printf_stderr("%s", aString.c_str()); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: class NoLog michael@0: { michael@0: public: michael@0: NoLog() {} michael@0: ~NoLog() {} michael@0: michael@0: template michael@0: NoLog &operator <<(const T &aLogText) { return *this; } michael@0: }; michael@0: michael@0: MOZ_BEGIN_ENUM_CLASS(LogOptions, int) michael@0: NoNewline = 0x01 michael@0: MOZ_END_ENUM_CLASS(LogOptions) michael@0: michael@0: template michael@0: class Log michael@0: { michael@0: public: michael@0: Log(LogOptions aOptions = LogOptions(0)) : mOptions(aOptions) {} michael@0: ~Log() { michael@0: Flush(); michael@0: } michael@0: michael@0: void Flush() { michael@0: if (!(int(mOptions) & int(LogOptions::NoNewline))) { michael@0: mMessage << '\n'; michael@0: } michael@0: std::string str = mMessage.str(); michael@0: if (!str.empty()) { michael@0: WriteLog(str); michael@0: } michael@0: mMessage.str(""); michael@0: mMessage.clear(); michael@0: } michael@0: michael@0: Log &operator <<(char aChar) { mMessage << aChar; return *this; } michael@0: Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; } michael@0: Log &operator <<(const char aStr[]) { mMessage << static_cast(aStr); return *this; } michael@0: Log &operator <<(bool aBool) { mMessage << (aBool ? "true" : "false"); return *this; } michael@0: Log &operator <<(int aInt) { mMessage << aInt; return *this; } michael@0: Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; } michael@0: Log &operator <<(long aLong) { mMessage << aLong; return *this; } michael@0: Log &operator <<(unsigned long aLong) { mMessage << aLong; return *this; } michael@0: Log &operator <<(long long aLong) { mMessage << aLong; return *this; } michael@0: Log &operator <<(unsigned long long aLong) { mMessage << aLong; return *this; } michael@0: Log &operator <<(Float aFloat) { mMessage << aFloat; return *this; } michael@0: Log &operator <<(double aDouble) { mMessage << aDouble; return *this; } michael@0: template michael@0: Log &operator <<(const BasePoint& aPoint) michael@0: { mMessage << "Point(" << aPoint.x << "," << aPoint.y << ")"; return *this; } michael@0: template michael@0: Log &operator <<(const BaseSize& aSize) michael@0: { mMessage << "Size(" << aSize.width << "," << aSize.height << ")"; return *this; } michael@0: template michael@0: Log &operator <<(const BaseRect& aRect) michael@0: { mMessage << "Rect(" << aRect.x << "," << aRect.y << "," << aRect.width << "," << aRect.height << ")"; return *this; } michael@0: Log &operator<<(const Matrix& aMatrix) michael@0: { mMessage << "Matrix(" << aMatrix._11 << " " << aMatrix._12 << " ; " << aMatrix._21 << " " << aMatrix._22 << " ; " << aMatrix._31 << " " << aMatrix._32 << ")"; return *this; } michael@0: michael@0: michael@0: private: michael@0: michael@0: void WriteLog(const std::string &aString) { michael@0: OutputMessage(aString, L); michael@0: } michael@0: michael@0: std::stringstream mMessage; michael@0: LogOptions mOptions; michael@0: }; michael@0: michael@0: typedef Log DebugLog; michael@0: typedef Log WarningLog; michael@0: michael@0: #ifdef GFX_LOG_DEBUG michael@0: #define gfxDebug DebugLog michael@0: #else michael@0: #define gfxDebug if (1) ; else NoLog michael@0: #endif michael@0: #ifdef GFX_LOG_WARNING michael@0: #define gfxWarning WarningLog michael@0: #else michael@0: #define gfxWarning if (1) ; else NoLog michael@0: #endif michael@0: michael@0: const int INDENT_PER_LEVEL = 2; michael@0: michael@0: class TreeLog michael@0: { michael@0: public: michael@0: TreeLog(const std::string& aPrefix = "") michael@0: : mLog(LogOptions::NoNewline), michael@0: mPrefix(aPrefix), michael@0: mDepth(0), michael@0: mStartOfLine(true), michael@0: mConditionedOnPref(false), michael@0: mPref(nullptr) {} michael@0: michael@0: template michael@0: TreeLog& operator<<(const T& aObject) { michael@0: if (mConditionedOnPref && !*mPref) { michael@0: return *this; michael@0: } michael@0: if (mStartOfLine) { michael@0: mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' '); michael@0: mStartOfLine = false; michael@0: } michael@0: mLog << aObject; michael@0: if (EndsInNewline(aObject)) { michael@0: // Don't indent right here as the user may change the indent michael@0: // between now and the first output to the next line. michael@0: mLog.Flush(); michael@0: mStartOfLine = true; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: void IncreaseIndent() { ++mDepth; } michael@0: void DecreaseIndent() { --mDepth; } michael@0: michael@0: void ConditionOnPref(bool* aPref) { michael@0: mConditionedOnPref = true; michael@0: mPref = aPref; michael@0: } michael@0: private: michael@0: Log mLog; michael@0: std::string mPrefix; michael@0: uint32_t mDepth; michael@0: bool mStartOfLine; michael@0: bool mConditionedOnPref; michael@0: bool* mPref; michael@0: michael@0: template michael@0: static bool EndsInNewline(const T& aObject) { michael@0: return false; michael@0: } michael@0: michael@0: static bool EndsInNewline(const std::string& aString) { michael@0: return !aString.empty() && aString[aString.length() - 1] == '\n'; michael@0: } michael@0: michael@0: static bool EndsInNewline(char aChar) { michael@0: return aChar == '\n'; michael@0: } michael@0: michael@0: static bool EndsInNewline(const char* aString) { michael@0: return EndsInNewline(std::string(aString)); michael@0: } michael@0: }; michael@0: michael@0: class TreeAutoIndent michael@0: { michael@0: public: michael@0: TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) { michael@0: mTreeLog.IncreaseIndent(); michael@0: } michael@0: ~TreeAutoIndent() { michael@0: mTreeLog.DecreaseIndent(); michael@0: } michael@0: private: michael@0: TreeLog& mTreeLog; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif /* MOZILLA_GFX_LOGGING_H_ */