LCOV - code coverage report
Current view: top level - gfx/2d - Logging.h (source / functions) Hit Total Coverage
Test: output.info Lines: 48 186 25.8 %
Date: 2017-07-14 16:53:18 Functions: 23 128 18.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #ifndef MOZILLA_GFX_LOGGING_H_
       7             : #define MOZILLA_GFX_LOGGING_H_
       8             : 
       9             : #include <string>
      10             : #include <sstream>
      11             : #include <stdio.h>
      12             : #include <vector>
      13             : 
      14             : #ifdef MOZ_LOGGING
      15             : #include "mozilla/Logging.h"
      16             : #endif
      17             : #include "mozilla/Tuple.h"
      18             : 
      19             : #if defined(MOZ_WIDGET_ANDROID)
      20             : #include "nsDebug.h"
      21             : #endif
      22             : #include "Point.h"
      23             : #include "BaseRect.h"
      24             : #include "Matrix.h"
      25             : #include "LoggingConstants.h"
      26             : 
      27             : #if defined(MOZ_LOGGING)
      28             : extern GFX2D_API mozilla::LogModule* GetGFX2DLog();
      29             : #endif
      30             : 
      31             : namespace mozilla {
      32             : namespace gfx {
      33             : 
      34             : #if defined(MOZ_LOGGING)
      35           1 : inline mozilla::LogLevel PRLogLevelForLevel(int aLevel) {
      36           1 :   switch (aLevel) {
      37             :   case LOG_CRITICAL:
      38           0 :     return LogLevel::Error;
      39             :   case LOG_WARNING:
      40           0 :     return LogLevel::Warning;
      41             :   case LOG_DEBUG:
      42           1 :     return LogLevel::Debug;
      43             :   case LOG_DEBUG_PRLOG:
      44           0 :     return LogLevel::Debug;
      45             :   case LOG_EVERYTHING:
      46           0 :     return LogLevel::Error;
      47             :   }
      48           0 :   return LogLevel::Debug;
      49             : }
      50             : #endif
      51             : 
      52             : class LoggingPrefs
      53             : {
      54             : public:
      55             :   // Used to choose the level of logging we get.  The higher the number,
      56             :   // the more logging we get.  Value of zero will give you no logging,
      57             :   // 1 just errors, 2 adds warnings and 3 or 4 add debug logging.
      58             :   // In addition to setting the value to 4, you will need to set the
      59             :   // environment variable MOZ_LOG to gfx:4. See mozilla/Logging.h for details.
      60             :   static int32_t sGfxLogLevel;
      61             : };
      62             : 
      63             : /// Graphics logging is available in both debug and release builds and is
      64             : /// controlled with a gfx.logging.level preference. If not set, the default
      65             : /// for the preference is 5 in the debug builds, 1 in the release builds.
      66             : ///
      67             : /// gfxDebug only works in the debug builds, and is used for information
      68             : /// level messages, helping with debugging.  In addition to only working
      69             : /// in the debug builds, the value of the above preference of 3 or higher
      70             : /// is required.
      71             : ///
      72             : /// gfxWarning messages are available in both debug and release builds,
      73             : /// on by default in the debug builds, and off by default in the release builds.
      74             : /// Setting the preference gfx.logging.level to a value of 2 or higher will
      75             : /// show the warnings.
      76             : ///
      77             : /// gfxCriticalError is available in debug and release builds by default.
      78             : /// It is only unavailable if gfx.logging.level is set to 0 (or less.)
      79             : /// It outputs the message to stderr or equivalent, like gfxWarning.
      80             : /// In the event of a crash, the crash report is annotated with first and
      81             : /// the last few of these errors, under the key GraphicsCriticalError.
      82             : /// The total number of errors stored in the crash report is controlled
      83             : /// by preference gfx.logging.crash.length.
      84             : ///
      85             : /// On platforms that support MOZ_LOGGING, the story is slightly more involved.
      86             : /// In that case, unless gfx.logging.level is set to 4 or higher, the output
      87             : /// is further controlled by the "gfx2d" logging module.  However, in the case
      88             : /// where such module would disable the output, in all but gfxDebug cases,
      89             : /// we will still send a printf.
      90             : 
      91             : // The range is due to the values set in Histograms.json
      92             : enum class LogReason : int {
      93             :   MustBeMoreThanThis = -1,
      94             :   // Start.  Do not insert, always add at end.  If you remove items,
      95             :   // make sure the other items retain their values.
      96             :   D3D11InvalidCallDeviceRemoved = 0,
      97             :   D3D11InvalidCall,
      98             :   D3DLockTimeout,
      99             :   D3D10FinalizeFrame,
     100             :   D3D11FinalizeFrame,
     101             :   D3D10SyncLock,
     102             :   D3D11SyncLock,
     103             :   D2D1NoWriteMap,
     104             :   JobStatusError,
     105             :   FilterInputError,
     106             :   FilterInputData, // 10
     107             :   FilterInputRect,
     108             :   FilterInputSet,
     109             :   FilterInputFormat,
     110             :   FilterNodeD2D1Target,
     111             :   FilterNodeD2D1Backend,
     112             :   SourceSurfaceIncompatible,
     113             :   GlyphAllocFailedCairo,
     114             :   GlyphAllocFailedCG,
     115             :   InvalidRect,
     116             :   CannotDraw3D, // 20
     117             :   IncompatibleBasicTexturedEffect,
     118             :   InvalidFont,
     119             :   PAllocTextureBackendMismatch,
     120             :   GetFontFileDataFailed,
     121             :   MessageChannelCloseFailure,
     122             :   MessageChannelInvalidHandle,
     123             :   TextureAliveAfterShutdown,
     124             :   InvalidContext,
     125             :   InvalidCommandList,
     126             :   AsyncTransactionTimeout, // 30
     127             :   TextureCreation,
     128             :   InvalidCacheSurface,
     129             :   AlphaWithBasicClient,
     130             :   UnbalancedClipStack,
     131             :   ProcessingError,
     132             :   InvalidDrawTarget,
     133             :   NativeFontResourceNotFound,
     134             :   UnscaledFontNotFound,
     135             :   // End
     136             :   MustBeLessThanThis = 101,
     137             : };
     138             : 
     139             : struct BasicLogger
     140             : {
     141             :   // For efficiency, this method exists and copies the logic of the
     142             :   // OutputMessage below.  If making any changes here, also make it
     143             :   // in the appropriate places in that method.
     144           1 :   static bool ShouldOutputMessage(int aLevel) {
     145           1 :     if (LoggingPrefs::sGfxLogLevel >= aLevel) {
     146             : #if defined(MOZ_WIDGET_ANDROID)
     147             :       return true;
     148             : #else
     149             : #if defined(MOZ_LOGGING)
     150           1 :       if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) {
     151           0 :         return true;
     152             :       } else
     153             : #endif
     154           1 :       if ((LoggingPrefs::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
     155             :                  (aLevel < LOG_DEBUG)) {
     156           1 :         return true;
     157             :       }
     158             : #endif
     159             :     }
     160           0 :     return false;
     161             :   }
     162             : 
     163             :   // Only for really critical errors.
     164           0 :   static void CrashAction(LogReason aReason) {}
     165             : 
     166           0 :   static void OutputMessage(const std::string &aString,
     167             :                             int aLevel,
     168             :                             bool aNoNewline) {
     169             :     // This behavior (the higher the preference, the more we log)
     170             :     // is consistent with what prlog does in general.  Note that if prlog
     171             :     // is in the build, but disabled, we will printf if the preferences
     172             :     // requires us to log something (see sGfxLogLevel for the special
     173             :     // treatment of LOG_DEBUG and LOG_DEBUG_PRLOG)
     174             :     //
     175             :     // If making any logic changes to this method, you should probably
     176             :     // make the corresponding change in the ShouldOutputMessage method
     177             :     // above.
     178           0 :     if (LoggingPrefs::sGfxLogLevel >= aLevel) {
     179             : #if defined(MOZ_WIDGET_ANDROID)
     180             :       printf_stderr("%s%s", aString.c_str(), aNoNewline ? "" : "\n");
     181             : #else
     182             : #if defined(MOZ_LOGGING)
     183           0 :       if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) {
     184           0 :         MOZ_LOG(GetGFX2DLog(), PRLogLevelForLevel(aLevel), ("%s%s", aString.c_str(), aNoNewline ? "" : "\n"));
     185             :       } else
     186             : #endif
     187           0 :       if ((LoggingPrefs::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
     188             :                  (aLevel < LOG_DEBUG)) {
     189           0 :         printf("%s%s", aString.c_str(), aNoNewline ? "" : "\n");
     190             :       }
     191             : #endif
     192             :     }
     193           0 :   }
     194             : };
     195             : 
     196             : struct CriticalLogger {
     197             :   static void OutputMessage(const std::string &aString, int aLevel, bool aNoNewline);
     198             :   static void CrashAction(LogReason aReason);
     199             : };
     200             : 
     201             : // The int is the index of the Log call; if the number of logs exceeds some preset
     202             : // capacity we may not get all of them, so the indices help figure out which
     203             : // ones we did save.  The double is expected to be the "TimeDuration", 
     204             : // time in seconds since the process creation.
     205             : typedef mozilla::Tuple<int32_t,std::string,double> LoggingRecordEntry;
     206             : 
     207             : // Implement this interface and init the Factory with an instance to
     208             : // forward critical logs.
     209             : typedef std::vector<LoggingRecordEntry> LoggingRecord;
     210           3 : class LogForwarder {
     211             : public:
     212           0 :   virtual ~LogForwarder() {}
     213             :   virtual void Log(const std::string &aString) = 0;
     214             :   virtual void CrashAction(LogReason aReason) = 0;
     215             :   virtual bool UpdateStringsVector(const std::string& aString) = 0;
     216             : 
     217             :   // Provide a copy of the logs to the caller.
     218             :   virtual LoggingRecord LoggingRecordCopy() = 0;
     219             : };
     220             : 
     221             : class NoLog
     222             : {
     223             : public:
     224             :   NoLog() {}
     225             :   ~NoLog() {}
     226             : 
     227             :   // No-op
     228             :   MOZ_IMPLICIT NoLog(const NoLog&) {}
     229             : 
     230             :   template<typename T>
     231             :   NoLog &operator <<(const T &aLogText) { return *this; }
     232             : };
     233             : 
     234             : enum class LogOptions : int {
     235             :   NoNewline = 0x01,
     236             :   AutoPrefix = 0x02,
     237             :   AssertOnCall = 0x04,
     238             :   CrashAction = 0x08,
     239             : };
     240             : 
     241             : template<typename T>
     242           0 : struct Hexa {
     243           0 :   explicit Hexa(T aVal) : mVal(aVal) {}
     244             :   T mVal;
     245             : };
     246             : template<typename T>
     247           0 : Hexa<T> hexa(T val) { return Hexa<T>(val); }
     248             : 
     249             : template<int L, typename Logger = BasicLogger>
     250             : class Log
     251             : {
     252             : public:
     253             :   // The default is to have the prefix, have the new line, and for critical
     254             :   // logs assert on each call.
     255           0 :   static int DefaultOptions(bool aWithAssert = true) {
     256           0 :     return (int(LogOptions::AutoPrefix) |
     257           0 :             (aWithAssert ? int(LogOptions::AssertOnCall) : 0));
     258             :   }
     259             : 
     260             :   // Note that we're calling BasicLogger::ShouldOutputMessage, rather than
     261             :   // Logger::ShouldOutputMessage.  Since we currently don't have a different
     262             :   // version of that method for different loggers, this is OK. Once we do,
     263             :   // change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage.
     264           1 :   explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL),
     265             :                LogReason aReason = LogReason::MustBeMoreThanThis)
     266             :   : mOptions(0)
     267           1 :   , mLogIt(false)
     268             :   {
     269           1 :     Init(aOptions, BasicLogger::ShouldOutputMessage(L), aReason);
     270           1 :   }
     271             : 
     272           0 :   ~Log() {
     273           0 :     Flush();
     274           0 :   }
     275             : 
     276           0 :   void Flush() {
     277           0 :     if (MOZ_LIKELY(!LogIt())) return;
     278             : 
     279           0 :     std::string str = mMessage.str();
     280           0 :     if (!str.empty()) {
     281           0 :       WriteLog(str);
     282             :     }
     283           0 :     mMessage.str("");
     284             :   }
     285             : 
     286           0 :   Log &operator <<(char aChar) {
     287           0 :     if (MOZ_UNLIKELY(LogIt())) {
     288           0 :       mMessage << aChar;
     289             :     }
     290           0 :     return *this;
     291             :   }
     292           0 :   Log &operator <<(const std::string &aLogText) { 
     293           0 :     if (MOZ_UNLIKELY(LogIt())) {
     294           0 :       mMessage << aLogText;
     295             :     }
     296           0 :     return *this;
     297             :   }
     298           0 :   Log &operator <<(const char aStr[]) {
     299           0 :     if (MOZ_UNLIKELY(LogIt())) {
     300           0 :       mMessage << static_cast<const char*>(aStr);
     301             :     }
     302           0 :     return *this;
     303             :   }
     304           0 :   Log &operator <<(bool aBool) {
     305           0 :     if (MOZ_UNLIKELY(LogIt())) {
     306           0 :       mMessage << (aBool ? "true" : "false");
     307             :     }
     308           0 :     return *this;
     309             :   }
     310           0 :   Log &operator <<(int aInt) {
     311           0 :     if (MOZ_UNLIKELY(LogIt())) {
     312           0 :       mMessage << aInt;
     313             :     }
     314           0 :     return *this;
     315             :   }
     316           0 :   Log &operator <<(unsigned int aInt) {
     317           0 :     if (MOZ_UNLIKELY(LogIt())) {
     318           0 :       mMessage << aInt;
     319             :     }
     320           0 :     return *this;
     321             :   }
     322             :   Log &operator <<(long aLong) {
     323             :     if (MOZ_UNLIKELY(LogIt())) {
     324             :       mMessage << aLong;
     325             :     }
     326             :     return *this;
     327             :   }
     328           0 :   Log &operator <<(unsigned long aLong) {
     329           0 :     if (MOZ_UNLIKELY(LogIt())) {
     330           0 :       mMessage << aLong;
     331             :     }
     332           0 :     return *this;
     333             :   }
     334             :   Log &operator <<(long long aLong) {
     335             :     if (MOZ_UNLIKELY(LogIt())) {
     336             :       mMessage << aLong;
     337             :     }
     338             :     return *this;
     339             :   }
     340             :   Log &operator <<(unsigned long long aLong) {
     341             :     if (MOZ_UNLIKELY(LogIt())) {
     342             :       mMessage << aLong;
     343             :     }
     344             :     return *this;
     345             :   }
     346           0 :   Log &operator <<(Float aFloat) {
     347           0 :     if (MOZ_UNLIKELY(LogIt())) {
     348           0 :       mMessage << aFloat;
     349             :     }
     350           0 :     return *this;
     351             :   }
     352             :   Log &operator <<(double aDouble) {
     353             :     if (MOZ_UNLIKELY(LogIt())) {
     354             :       mMessage << aDouble;
     355             :     }
     356             :     return *this;
     357             :   }
     358             :   template <typename T, typename Sub, typename Coord>
     359             :   Log &operator <<(const BasePoint<T, Sub, Coord>& aPoint) {
     360             :     if (MOZ_UNLIKELY(LogIt())) {
     361             :       mMessage << "Point" << aPoint;
     362             :     }
     363             :     return *this;
     364             :   }
     365             :   template <typename T, typename Sub>
     366           0 :   Log &operator <<(const BaseSize<T, Sub>& aSize) {
     367           0 :     if (MOZ_UNLIKELY(LogIt())) {
     368           0 :       mMessage << "Size(" << aSize.width << "," << aSize.height << ")";
     369             :     }
     370           0 :     return *this;
     371             :   }
     372             :   template <typename T, typename Sub, typename Point, typename SizeT, typename Margin>
     373           0 :   Log &operator <<(const BaseRect<T, Sub, Point, SizeT, Margin>& aRect) {
     374           0 :     if (MOZ_UNLIKELY(LogIt())) {
     375           0 :       mMessage << "Rect" << aRect;
     376             :     }
     377           0 :     return *this;
     378             :   }
     379             :   Log &operator<<(const Matrix& aMatrix) {
     380             :     if (MOZ_UNLIKELY(LogIt())) {
     381             :       mMessage << "Matrix(" << aMatrix._11 << " " << aMatrix._12 << " ; " << aMatrix._21 << " " << aMatrix._22 << " ; " << aMatrix._31 << " " << aMatrix._32 << ")";
     382             :     }
     383             :     return *this;
     384             :   }
     385             :   template<typename T>
     386           0 :   Log &operator<<(Hexa<T> aHex) {
     387           0 :     if (MOZ_UNLIKELY(LogIt())) {
     388           0 :       mMessage << std::showbase << std::hex
     389           0 :                << aHex.mVal
     390           0 :                << std::noshowbase << std::dec;
     391             :     }
     392           0 :     return *this;
     393             :   }
     394             : 
     395           0 :   Log& operator<<(SurfaceFormat aFormat) {
     396           0 :     if (MOZ_UNLIKELY(LogIt())) {
     397           0 :       switch(aFormat) {
     398             :         case SurfaceFormat::B8G8R8A8:
     399           0 :           mMessage << "SurfaceFormat::B8G8R8A8";
     400           0 :           break;
     401             :         case SurfaceFormat::B8G8R8X8:
     402           0 :           mMessage << "SurfaceFormat::B8G8R8X8";
     403           0 :           break;
     404             :         case SurfaceFormat::R8G8B8A8:
     405           0 :           mMessage << "SurfaceFormat::R8G8B8A8";
     406           0 :           break;
     407             :         case SurfaceFormat::R8G8B8X8:
     408           0 :           mMessage << "SurfaceFormat::R8G8B8X8";
     409           0 :           break;
     410             :         case SurfaceFormat::R5G6B5_UINT16:
     411           0 :           mMessage << "SurfaceFormat::R5G6B5_UINT16";
     412           0 :           break;
     413             :         case SurfaceFormat::A8:
     414           0 :           mMessage << "SurfaceFormat::A8";
     415           0 :           break;
     416             :         case SurfaceFormat::YUV:
     417           0 :           mMessage << "SurfaceFormat::YUV";
     418           0 :           break;
     419             :         case SurfaceFormat::UNKNOWN:
     420           0 :           mMessage << "SurfaceFormat::UNKNOWN";
     421           0 :           break;
     422             :         default:
     423           0 :           mMessage << "Invalid SurfaceFormat (" << (int)aFormat << ")";
     424           0 :           break;
     425             :       }
     426             :     }
     427           0 :     return *this;
     428             :   }
     429             : 
     430             :   Log& operator<<(SurfaceType aType) {
     431             :     if (MOZ_UNLIKELY(LogIt())) {
     432             :       switch(aType) {
     433             :         case SurfaceType::DATA:
     434             :           mMessage << "SurfaceType::DATA";
     435             :           break;
     436             :         case SurfaceType::D2D1_BITMAP:
     437             :           mMessage << "SurfaceType::D2D1_BITMAP";
     438             :           break;
     439             :         case SurfaceType::D2D1_DRAWTARGET:
     440             :           mMessage << "SurfaceType::D2D1_DRAWTARGET";
     441             :           break;
     442             :         case SurfaceType::CAIRO:
     443             :           mMessage << "SurfaceType::CAIRO";
     444             :           break;
     445             :         case SurfaceType::CAIRO_IMAGE:
     446             :           mMessage << "SurfaceType::CAIRO_IMAGE";
     447             :           break;
     448             :         case SurfaceType::COREGRAPHICS_IMAGE:
     449             :           mMessage << "SurfaceType::COREGRAPHICS_IMAGE";
     450             :           break;
     451             :         case SurfaceType::COREGRAPHICS_CGCONTEXT:
     452             :           mMessage << "SurfaceType::COREGRAPHICS_CGCONTEXT";
     453             :           break;
     454             :         case SurfaceType::SKIA:
     455             :           mMessage << "SurfaceType::SKIA";
     456             :           break;
     457             :         case SurfaceType::DUAL_DT:
     458             :           mMessage << "SurfaceType::DUAL_DT";
     459             :           break;
     460             :         case SurfaceType::D2D1_1_IMAGE:
     461             :           mMessage << "SurfaceType::D2D1_1_IMAGE";
     462             :           break;
     463             :         case SurfaceType::RECORDING:
     464             :           mMessage << "SurfaceType::RECORDING";
     465             :           break;
     466             :         case SurfaceType::TILED:
     467             :           mMessage << "SurfaceType::TILED";
     468             :           break;
     469             :         case SurfaceType::DATA_SHARED:
     470             :           mMessage << "SurfaceType::DATA_SHARED";
     471             :           break;
     472             :         default:
     473             :           mMessage << "Invalid SurfaceType (" << (int)aType << ")";
     474             :           break;
     475             :       }
     476             :     }
     477             :     return *this;
     478             :   }
     479             : 
     480           0 :   inline bool LogIt() const { return mLogIt; }
     481           0 :   inline bool NoNewline() const { return mOptions & int(LogOptions::NoNewline); }
     482           2 :   inline bool AutoPrefix() const { return mOptions & int(LogOptions::AutoPrefix); }
     483           0 :   inline bool ValidReason() const { return (int)mReason > (int)LogReason::MustBeMoreThanThis && (int)mReason < (int)LogReason::MustBeLessThanThis; }
     484             : 
     485             :   // We do not want this version to do any work, and stringstream can't be
     486             :   // copied anyway.  It does come in handy for the "Once" macro defined below.
     487           0 :   MOZ_IMPLICIT Log(const Log& log) { Init(log.mOptions, false, log.mReason); }
     488             : 
     489             : private:
     490             :   // Initialization common to two constructors
     491           1 :   void Init(int aOptions, bool aLogIt, LogReason aReason) {
     492           1 :     mOptions = aOptions;
     493           1 :     mReason = aReason;
     494           1 :     mLogIt = aLogIt;
     495           1 :     if (mLogIt) {
     496           1 :       if (AutoPrefix()) {
     497           0 :         if (mOptions & int(LogOptions::AssertOnCall)) {
     498           0 :           mMessage << "[GFX" << L;
     499             :         } else {
     500           0 :           mMessage << "[GFX" << L << "-";
     501             :         }
     502             :       }
     503           1 :       if ((mOptions & int(LogOptions::CrashAction)) && ValidReason()) {
     504           0 :         mMessage << " " << (int)mReason;
     505             :       }
     506           1 :       if (AutoPrefix()) {
     507           0 :         mMessage << "]: ";
     508             :       }
     509             :     }
     510           1 :   }
     511             : 
     512           0 :   void WriteLog(const std::string &aString) {
     513           0 :     if (MOZ_UNLIKELY(LogIt())) {
     514           0 :       Logger::OutputMessage(aString, L, NoNewline());
     515             :       // Assert if required.  We don't have a three parameter MOZ_ASSERT
     516             :       // so use the underlying functions instead (see bug 1281702):
     517             : #ifdef DEBUG
     518           0 :       if (mOptions & int(LogOptions::AssertOnCall)) {
     519           0 :         MOZ_ReportAssertionFailure(aString.c_str(), __FILE__, __LINE__);
     520           0 :         MOZ_CRASH("GFX: An assert from the graphics logger");
     521             :       }
     522             : #endif
     523           0 :       if ((mOptions & int(LogOptions::CrashAction)) && ValidReason()) {
     524           0 :         Logger::CrashAction(mReason);
     525             :       }
     526             :     }
     527           0 :   }
     528             : 
     529             :   std::stringstream mMessage;
     530             :   int mOptions;
     531             :   LogReason mReason;
     532             :   bool mLogIt;
     533             : };
     534             : 
     535             : typedef Log<LOG_DEBUG> DebugLog;
     536             : typedef Log<LOG_WARNING> WarningLog;
     537             : typedef Log<LOG_CRITICAL, CriticalLogger> CriticalLog;
     538             : 
     539             : // Macro to glue names to get us less chance of name clashing.
     540             : #if defined GFX_LOGGING_GLUE1 || defined GFX_LOGGING_GLUE
     541             : #error "Clash of the macro GFX_LOGGING_GLUE1 or GFX_LOGGING_GLUE"
     542             : #endif
     543             : #define GFX_LOGGING_GLUE1(x, y)  x##y
     544             : #define GFX_LOGGING_GLUE(x, y)   GFX_LOGGING_GLUE1(x, y)
     545             : 
     546             : // This log goes into crash reports, use with care.
     547             : #define gfxCriticalError mozilla::gfx::CriticalLog
     548             : #define gfxCriticalErrorOnce static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxCriticalError
     549             : 
     550             : // This is a shortcut for errors we want logged in crash reports/about support
     551             : // but we do not want asserting.  These are available in all builds, so it is
     552             : // not worth trying to do magic to avoid matching the syntax of gfxCriticalError.
     553             : // So, this one is used as
     554             : // gfxCriticalNote << "Something to report and not assert";
     555             : // while the critical error is
     556             : // gfxCriticalError() << "Something to report and assert";
     557             : #define gfxCriticalNote gfxCriticalError(gfxCriticalError::DefaultOptions(false))
     558             : #define gfxCriticalNoteOnce static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxCriticalNote
     559             : 
     560             : // The "once" versions will only trigger the first time through. You can do this:
     561             : // gfxCriticalErrorOnce() << "This message only shows up once;
     562             : // instead of the usual:
     563             : // static bool firstTime = true;
     564             : // if (firstTime) {
     565             : //   firstTime = false;
     566             : //   gfxCriticalError() << "This message only shows up once;
     567             : // }
     568             : #if defined(DEBUG)
     569             : #define gfxDebug mozilla::gfx::DebugLog
     570             : #define gfxDebugOnce static gfxDebug GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxDebug
     571             : #else
     572             : #define gfxDebug if (1) ; else mozilla::gfx::NoLog
     573             : #define gfxDebugOnce if (1) ; else mozilla::gfx::NoLog
     574             : #endif
     575             : 
     576             : // Have gfxWarning available (behind a runtime preference)
     577             : #define gfxWarning mozilla::gfx::WarningLog
     578             : #define gfxWarningOnce static gfxWarning GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxWarning
     579             : 
     580             : // In the debug build, this is equivalent to the default gfxCriticalError.
     581             : // In the non-debug build, on nightly and dev edition, it will MOZ_CRASH.
     582             : // On beta and release versions, it will telemetry count, but proceed.
     583             : //
     584             : // You should create a (new) enum in the LogReason and use it for the reason
     585             : // parameter to ensure uniqueness.
     586             : #define gfxDevCrash(reason) gfxCriticalError(int(gfx::LogOptions::AutoPrefix) | int(gfx::LogOptions::AssertOnCall) | int(gfx::LogOptions::CrashAction), (reason))
     587             : 
     588             : // See nsDebug.h and the NS_WARN_IF macro
     589             : 
     590             : #ifdef __cplusplus
     591             :  // For now, have MOZ2D_ERROR_IF available in debug and non-debug builds
     592             : inline bool MOZ2D_error_if_impl(bool aCondition, const char* aExpr,
     593             :                                 const char* aFile, int32_t aLine)
     594             : {
     595             :   if (MOZ_UNLIKELY(aCondition)) {
     596             :     gfxCriticalError() << aExpr << " at " << aFile << ":" << aLine;
     597             :   }
     598             :   return aCondition;
     599             : }
     600             : #define MOZ2D_ERROR_IF(condition) \
     601             :   MOZ2D_error_if_impl(condition, #condition, __FILE__, __LINE__)
     602             : 
     603             : #ifdef DEBUG
     604           0 : inline bool MOZ2D_warn_if_impl(bool aCondition, const char* aExpr,
     605             :                                const char* aFile, int32_t aLine)
     606             : {
     607           0 :   if (MOZ_UNLIKELY(aCondition)) {
     608           0 :     gfxWarning() << aExpr << " at " << aFile << ":" << aLine;
     609             :   }
     610           0 :   return aCondition;
     611             : }
     612             : #define MOZ2D_WARN_IF(condition) \
     613             :   MOZ2D_warn_if_impl(condition, #condition, __FILE__, __LINE__)
     614             : #else
     615             : #define MOZ2D_WARN_IF(condition) (bool)(condition)
     616             : #endif
     617             : #endif
     618             : 
     619             : const int INDENT_PER_LEVEL = 2;
     620             : 
     621           0 : class TreeLog
     622             : {
     623             : public:
     624           1 :   explicit TreeLog(const std::string& aPrefix = "")
     625           1 :         : mLog(int(LogOptions::NoNewline)),
     626             :           mPrefix(aPrefix),
     627             :           mDepth(0),
     628             :           mStartOfLine(true),
     629             :           mConditionedOnPref(false),
     630           1 :           mPrefFunction(nullptr) {}
     631             : 
     632             :   template <typename T>
     633        1079 :   TreeLog& operator<<(const T& aObject) {
     634        1079 :     if (mConditionedOnPref && !mPrefFunction()) {
     635        1079 :       return *this;
     636             :     }
     637           0 :     if (mStartOfLine) {
     638           0 :       mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' ');
     639           0 :       mStartOfLine = false;
     640             :     }
     641           0 :     mLog << aObject;
     642           0 :     if (EndsInNewline(aObject)) {
     643             :       // Don't indent right here as the user may change the indent
     644             :       // between now and the first output to the next line.
     645           0 :       mLog.Flush();
     646           0 :       mStartOfLine = true;
     647             :     }
     648           0 :     return *this;
     649             :   }
     650             : 
     651         422 :   void IncreaseIndent() { ++mDepth; }
     652         422 :   void DecreaseIndent() {
     653         422 :     MOZ_ASSERT(mDepth > 0);
     654         422 :     --mDepth;
     655         422 :   }
     656             : 
     657           1 :   void ConditionOnPrefFunction(bool(*aPrefFunction)()) {
     658           1 :     mConditionedOnPref = true;
     659           1 :     mPrefFunction = aPrefFunction;
     660           1 :   }
     661             : private:
     662             :   Log<LOG_DEBUG> mLog;
     663             :   std::string mPrefix;
     664             :   uint32_t mDepth;
     665             :   bool mStartOfLine;
     666             :   bool mConditionedOnPref;
     667             :   bool (*mPrefFunction)();
     668             : 
     669             :   template <typename T>
     670           0 :   static bool EndsInNewline(const T& aObject) {
     671           0 :     return false;
     672             :   }
     673             : 
     674           0 :   static bool EndsInNewline(const std::string& aString) {
     675           0 :     return !aString.empty() && aString[aString.length() - 1] == '\n';
     676             :   }
     677             : 
     678           0 :   static bool EndsInNewline(char aChar) {
     679           0 :     return aChar == '\n';
     680             :   }
     681             : 
     682           0 :   static bool EndsInNewline(const char* aString) {
     683           0 :     return EndsInNewline(std::string(aString));
     684             :   }
     685             : };
     686             : 
     687             : class TreeAutoIndent
     688             : {
     689             : public:
     690         211 :   explicit TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) {
     691         211 :     mTreeLog.IncreaseIndent();
     692         211 :   }
     693             : 
     694         211 :   TreeAutoIndent(const TreeAutoIndent& aTreeAutoIndent) :
     695         211 :       mTreeLog(aTreeAutoIndent.mTreeLog) {
     696         211 :     mTreeLog.IncreaseIndent();
     697         211 :   }
     698             : 
     699             :   TreeAutoIndent& operator=(const TreeAutoIndent& aTreeAutoIndent) = delete;
     700             : 
     701         844 :   ~TreeAutoIndent() {
     702         422 :     mTreeLog.DecreaseIndent();
     703         422 :   }
     704             : private:
     705             :   TreeLog& mTreeLog;
     706             : };
     707             : 
     708             : } // namespace gfx
     709             : } // namespace mozilla
     710             : 
     711             : #endif /* MOZILLA_GFX_LOGGING_H_ */

Generated by: LCOV version 1.13