зеркало из https://github.com/mozilla/gecko-dev.git
297 строки
8.0 KiB
C++
297 строки
8.0 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef MOZILLA_GFX_LOGGING_H_
|
|
#define MOZILLA_GFX_LOGGING_H_
|
|
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <stdio.h>
|
|
|
|
#ifdef MOZ_LOGGING
|
|
#include <prlog.h>
|
|
#endif
|
|
|
|
#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
|
|
#include "nsDebug.h"
|
|
#endif
|
|
#include "Point.h"
|
|
#include "BaseRect.h"
|
|
#include "Matrix.h"
|
|
#include "mozilla/TypedEnum.h"
|
|
|
|
#ifdef WIN32
|
|
// This file gets included from nsGlobalWindow.cpp, which doesn't like
|
|
// having windows.h included in it. Since OutputDebugStringA is the only
|
|
// thing we need from windows.h, we just declare it here directly.
|
|
// Note: the function's documented signature is
|
|
// WINBASEAPI void WINAPI OutputDebugStringA(LPCSTR lpOutputString)
|
|
// but if we don't include windows.h, the macros WINBASEAPI, WINAPI, and
|
|
// LPCSTR are not defined, so we need to replace them with their expansions.
|
|
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
|
|
#endif
|
|
|
|
#if defined(PR_LOGGING)
|
|
extern GFX2D_API PRLogModuleInfo *GetGFX2DLog();
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
|
|
const int LOG_DEBUG = 1;
|
|
const int LOG_WARNING = 2;
|
|
const int LOG_CRITICAL = 3;
|
|
|
|
#if defined(PR_LOGGING)
|
|
|
|
inline PRLogModuleLevel PRLogLevelForLevel(int aLevel) {
|
|
switch (aLevel) {
|
|
case LOG_DEBUG:
|
|
return PR_LOG_DEBUG;
|
|
case LOG_WARNING:
|
|
return PR_LOG_WARNING;
|
|
}
|
|
return PR_LOG_DEBUG;
|
|
}
|
|
|
|
#endif
|
|
|
|
extern GFX2D_API int sGfxLogLevel;
|
|
|
|
struct BasicLogger
|
|
{
|
|
static void OutputMessage(const std::string &aString, int aLevel) {
|
|
#if defined(WIN32) && !defined(PR_LOGGING)
|
|
if (aLevel >= sGfxLogLevel) {
|
|
::OutputDebugStringA(aString.c_str());
|
|
}
|
|
#elif defined(PR_LOGGING) && !(defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID))
|
|
if (PR_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) {
|
|
PR_LogPrint(aString.c_str());
|
|
}
|
|
#else
|
|
if (aLevel >= sGfxLogLevel) {
|
|
#if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
|
|
printf_stderr("%s", aString.c_str());
|
|
#else
|
|
printf("%s", aString.c_str());
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
};
|
|
|
|
struct CriticalLogger {
|
|
static void OutputMessage(const std::string &aString, int aLevel);
|
|
};
|
|
|
|
// Implement this interface and init the Factory with an instance to
|
|
// forward critical logs.
|
|
class LogForwarder {
|
|
public:
|
|
virtual ~LogForwarder() {}
|
|
virtual void Log(const std::string &aString) = 0;
|
|
};
|
|
|
|
class NoLog
|
|
{
|
|
public:
|
|
NoLog() {}
|
|
~NoLog() {}
|
|
|
|
template<typename T>
|
|
NoLog &operator <<(const T &aLogText) { return *this; }
|
|
};
|
|
|
|
MOZ_BEGIN_ENUM_CLASS(LogOptions, int)
|
|
NoNewline = 0x01
|
|
MOZ_END_ENUM_CLASS(LogOptions)
|
|
|
|
template<typename T>
|
|
struct Hexa {
|
|
explicit Hexa(T aVal) : mVal(aVal) {}
|
|
T mVal;
|
|
};
|
|
template<typename T>
|
|
Hexa<T> hexa(T val) { return Hexa<T>(val); }
|
|
|
|
template<int L, typename Logger = BasicLogger>
|
|
class Log
|
|
{
|
|
public:
|
|
explicit Log(LogOptions aOptions = LogOptions(0)) : mOptions(aOptions) {}
|
|
~Log() {
|
|
Flush();
|
|
}
|
|
|
|
void Flush() {
|
|
if (!(int(mOptions) & int(LogOptions::NoNewline))) {
|
|
mMessage << '\n';
|
|
}
|
|
std::string str = mMessage.str();
|
|
if (!str.empty()) {
|
|
WriteLog(str);
|
|
}
|
|
mMessage.str("");
|
|
mMessage.clear();
|
|
}
|
|
|
|
Log &operator <<(char aChar) { mMessage << aChar; return *this; }
|
|
Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; }
|
|
Log &operator <<(const char aStr[]) { mMessage << static_cast<const char*>(aStr); return *this; }
|
|
Log &operator <<(bool aBool) { mMessage << (aBool ? "true" : "false"); return *this; }
|
|
Log &operator <<(int aInt) { mMessage << aInt; return *this; }
|
|
Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; }
|
|
Log &operator <<(long aLong) { mMessage << aLong; return *this; }
|
|
Log &operator <<(unsigned long aLong) { mMessage << aLong; return *this; }
|
|
Log &operator <<(long long aLong) { mMessage << aLong; return *this; }
|
|
Log &operator <<(unsigned long long aLong) { mMessage << aLong; return *this; }
|
|
Log &operator <<(Float aFloat) { mMessage << aFloat; return *this; }
|
|
Log &operator <<(double aDouble) { mMessage << aDouble; return *this; }
|
|
template <typename T, typename Sub, typename Coord>
|
|
Log &operator <<(const BasePoint<T, Sub, Coord>& aPoint)
|
|
{ mMessage << "Point" << aPoint; return *this; }
|
|
template <typename T, typename Sub>
|
|
Log &operator <<(const BaseSize<T, Sub>& aSize)
|
|
{ mMessage << "Size(" << aSize.width << "," << aSize.height << ")"; return *this; }
|
|
template <typename T, typename Sub, typename Point, typename SizeT, typename Margin>
|
|
Log &operator <<(const BaseRect<T, Sub, Point, SizeT, Margin>& aRect)
|
|
{ mMessage << "Rect" << aRect; return *this; }
|
|
Log &operator<<(const Matrix& aMatrix)
|
|
{ mMessage << "Matrix(" << aMatrix._11 << " " << aMatrix._12 << " ; " << aMatrix._21 << " " << aMatrix._22 << " ; " << aMatrix._31 << " " << aMatrix._32 << ")"; return *this; }
|
|
template<typename T>
|
|
Log &operator<<(Hexa<T> aHex)
|
|
{ mMessage << "0x" << std::hex << aHex.mVal << std::dec; return *this; }
|
|
|
|
private:
|
|
|
|
void WriteLog(const std::string &aString) {
|
|
Logger::OutputMessage(aString, L);
|
|
}
|
|
|
|
std::stringstream mMessage;
|
|
LogOptions mOptions;
|
|
};
|
|
|
|
typedef Log<LOG_DEBUG> DebugLog;
|
|
typedef Log<LOG_WARNING> WarningLog;
|
|
typedef Log<LOG_CRITICAL, CriticalLogger> CriticalLog;
|
|
|
|
#ifdef GFX_LOG_DEBUG
|
|
#define gfxDebug DebugLog
|
|
#else
|
|
#define gfxDebug if (1) ; else NoLog
|
|
#endif
|
|
#ifdef GFX_LOG_WARNING
|
|
#define gfxWarning WarningLog
|
|
#else
|
|
#define gfxWarning if (1) ; else NoLog
|
|
#endif
|
|
|
|
// This log goes into crash reports, use with care.
|
|
#define gfxCriticalError CriticalLog
|
|
|
|
// See nsDebug.h and the NS_WARN_IF macro
|
|
|
|
#ifdef __cplusplus
|
|
#ifdef DEBUG
|
|
inline bool MOZ2D_warn_if_impl(bool aCondition, const char* aExpr,
|
|
const char* aFile, int32_t aLine)
|
|
{
|
|
if (MOZ_UNLIKELY(aCondition)) {
|
|
gfxWarning() << aExpr << " at " << aFile << ":" << aLine;
|
|
}
|
|
return aCondition;
|
|
}
|
|
#define MOZ2D_WARN_IF(condition) \
|
|
MOZ2D_warn_if_impl(condition, #condition, __FILE__, __LINE__)
|
|
#else
|
|
#define MOZ2D_WARN_IF(condition) (bool)(condition)
|
|
#endif
|
|
#endif
|
|
|
|
const int INDENT_PER_LEVEL = 2;
|
|
|
|
class TreeLog
|
|
{
|
|
public:
|
|
explicit TreeLog(const std::string& aPrefix = "")
|
|
: mLog(LogOptions::NoNewline),
|
|
mPrefix(aPrefix),
|
|
mDepth(0),
|
|
mStartOfLine(true),
|
|
mConditionedOnPref(false),
|
|
mPrefFunction(nullptr) {}
|
|
|
|
template <typename T>
|
|
TreeLog& operator<<(const T& aObject) {
|
|
if (mConditionedOnPref && !mPrefFunction()) {
|
|
return *this;
|
|
}
|
|
if (mStartOfLine) {
|
|
mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' ');
|
|
mStartOfLine = false;
|
|
}
|
|
mLog << aObject;
|
|
if (EndsInNewline(aObject)) {
|
|
// Don't indent right here as the user may change the indent
|
|
// between now and the first output to the next line.
|
|
mLog.Flush();
|
|
mStartOfLine = true;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void IncreaseIndent() { ++mDepth; }
|
|
void DecreaseIndent() { --mDepth; }
|
|
|
|
void ConditionOnPrefFunction(bool(*aPrefFunction)()) {
|
|
mConditionedOnPref = true;
|
|
mPrefFunction = aPrefFunction;
|
|
}
|
|
private:
|
|
Log<LOG_DEBUG> mLog;
|
|
std::string mPrefix;
|
|
uint32_t mDepth;
|
|
bool mStartOfLine;
|
|
bool mConditionedOnPref;
|
|
bool (*mPrefFunction)();
|
|
|
|
template <typename T>
|
|
static bool EndsInNewline(const T& aObject) {
|
|
return false;
|
|
}
|
|
|
|
static bool EndsInNewline(const std::string& aString) {
|
|
return !aString.empty() && aString[aString.length() - 1] == '\n';
|
|
}
|
|
|
|
static bool EndsInNewline(char aChar) {
|
|
return aChar == '\n';
|
|
}
|
|
|
|
static bool EndsInNewline(const char* aString) {
|
|
return EndsInNewline(std::string(aString));
|
|
}
|
|
};
|
|
|
|
class TreeAutoIndent
|
|
{
|
|
public:
|
|
explicit TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) {
|
|
mTreeLog.IncreaseIndent();
|
|
}
|
|
~TreeAutoIndent() {
|
|
mTreeLog.DecreaseIndent();
|
|
}
|
|
private:
|
|
TreeLog& mTreeLog;
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#endif /* MOZILLA_GFX_LOGGING_H_ */
|