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 #include "mozilla/dom/ConsoleInstance.h"
9 #include "mozilla/dom/ConsoleBinding.h"
10 #include "mozilla/Preferences.h"
11 #include "ConsoleCommon.h"
12 #include "ConsoleUtils.h"
13 #include "nsContentUtils.h"
15 namespace mozilla::dom
{
17 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ConsoleInstance
, mConsole
)
19 NS_IMPL_CYCLE_COLLECTING_ADDREF(ConsoleInstance
)
20 NS_IMPL_CYCLE_COLLECTING_RELEASE(ConsoleInstance
)
22 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConsoleInstance
)
23 NS_INTERFACE_MAP_ENTRY(nsISupports
)
24 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
29 ConsoleUtils::Level
WebIDLevelToConsoleUtilsLevel(ConsoleLevel aLevel
) {
31 case ConsoleLevel::Log
:
32 return ConsoleUtils::eLog
;
33 case ConsoleLevel::Warning
:
34 return ConsoleUtils::eWarning
;
35 case ConsoleLevel::Error
:
36 return ConsoleUtils::eError
;
41 return ConsoleUtils::eLog
;
46 ConsoleInstance::ConsoleInstance(JSContext
* aCx
,
47 const ConsoleInstanceOptions
& aOptions
)
48 : mMaxLogLevel(ConsoleLogLevel::All
),
49 mConsole(new Console(aCx
, nullptr, 0, 0, aOptions
.mPrefix
)) {
50 mConsole
->mConsoleID
= aOptions
.mConsoleID
;
51 mConsole
->mPassedInnerID
= aOptions
.mInnerID
;
53 if (aOptions
.mDump
.WasPassed()) {
54 mConsole
->mDumpFunction
= &aOptions
.mDump
.Value();
57 // Let's inform that this is a custom instance.
58 mConsole
->mChromeInstance
= true;
60 if (aOptions
.mMaxLogLevel
.WasPassed()) {
61 mMaxLogLevel
= aOptions
.mMaxLogLevel
.Value();
64 if (!aOptions
.mMaxLogLevelPref
.IsEmpty()) {
65 if (!NS_IsMainThread()) {
66 // Set the log level based on what we have.
69 // Flag an error to the console.
70 JS::Rooted
<JS::Value
> msg(aCx
);
74 "Console.maxLogLevelPref is not supported within workers!"),
76 JS_ClearPendingException(aCx
);
80 AutoTArray
<JS::Value
, 1> sequence
;
81 SequenceRooter
rootedSequence(aCx
, &sequence
);
82 sequence
.AppendElement(std::move(msg
));
83 this->Error(aCx
, std::move(sequence
));
87 mMaxLogLevelPref
= aOptions
.mMaxLogLevelPref
;
89 Preferences::RegisterCallback(MaxLogLevelPrefChangedCallback
,
90 mMaxLogLevelPref
, this);
95 ConsoleInstance::~ConsoleInstance() {
96 // We should only ever have set `mMaxLogLevelPref` when on the main thread,
97 // but check it here to be safe.
98 if (!mMaxLogLevelPref
.IsEmpty() && NS_IsMainThread()) {
99 Preferences::UnregisterCallback(MaxLogLevelPrefChangedCallback
,
100 mMaxLogLevelPref
, this);
104 ConsoleLogLevel
PrefToValue(const nsACString
& aPref
,
105 const ConsoleLogLevel aLevel
) {
106 if (aPref
.IsEmpty()) {
111 nsresult rv
= Preferences::GetCString(PromiseFlatCString(aPref
).get(), value
);
112 if (NS_WARN_IF(NS_FAILED(rv
))) {
114 message
.AssignLiteral(
115 "Console.maxLogLevelPref used with a non-existing pref: ");
116 message
.Append(NS_ConvertUTF8toUTF16(aPref
));
118 nsContentUtils::LogSimpleConsoleError(message
, "chrome"_ns
, false,
119 true /* from chrome context*/);
123 Maybe
<ConsoleLogLevel
> level
= StringToEnum
<ConsoleLogLevel
>(value
);
124 if (NS_WARN_IF(level
.isNothing())) {
126 message
.AssignLiteral("Invalid Console.maxLogLevelPref value: ");
127 message
.Append(NS_ConvertUTF8toUTF16(value
));
129 nsContentUtils::LogSimpleConsoleError(message
, "chrome"_ns
, false,
130 true /* from chrome context*/);
134 return level
.value();
137 void ConsoleInstance::SetLogLevel() {
138 mConsole
->mCurrentLogLevel
= mConsole
->WebIDLLogLevelToInteger(
139 PrefToValue(mMaxLogLevelPref
, mMaxLogLevel
));
143 void ConsoleInstance::MaxLogLevelPrefChangedCallback(
144 const char* /* aPrefName */, void* aSelf
) {
145 auto* instance
= static_cast<ConsoleInstance
*>(aSelf
);
146 if (MOZ_UNLIKELY(!instance
->mConsole
)) {
147 // We've been unlinked already but not destroyed yet. Bail.
150 RefPtr pin
{instance
};
154 JSObject
* ConsoleInstance::WrapObject(JSContext
* aCx
,
155 JS::Handle
<JSObject
*> aGivenProto
) {
156 return ConsoleInstance_Binding::Wrap(aCx
, this, aGivenProto
);
159 #define METHOD(name, string) \
160 void ConsoleInstance::name(JSContext* aCx, \
161 const Sequence<JS::Value>& aData) { \
162 RefPtr<Console> console(mConsole); \
163 console->MethodInternal(aCx, Console::Method##name, \
164 nsLiteralString(string), aData); \
168 METHOD(Info
, u
"info")
169 METHOD(Warn
, u
"warn")
170 METHOD(Error
, u
"error")
171 METHOD(Exception
, u
"exception")
172 METHOD(Debug
, u
"debug")
173 METHOD(Table
, u
"table")
174 METHOD(Trace
, u
"trace")
176 METHOD(Dirxml
, u
"dirxml");
177 METHOD(Group
, u
"group")
178 METHOD(GroupCollapsed
, u
"groupCollapsed")
182 void ConsoleInstance::GroupEnd(JSContext
* aCx
) {
183 const Sequence
<JS::Value
> data
;
184 RefPtr
<Console
> console(mConsole
);
185 console
->MethodInternal(aCx
, Console::MethodGroupEnd
, u
"groupEnd"_ns
, data
);
188 void ConsoleInstance::Time(JSContext
* aCx
, const nsAString
& aLabel
) {
189 RefPtr
<Console
> console(mConsole
);
190 console
->StringMethodInternal(aCx
, aLabel
, Sequence
<JS::Value
>(),
191 Console::MethodTime
, u
"time"_ns
);
194 void ConsoleInstance::TimeLog(JSContext
* aCx
, const nsAString
& aLabel
,
195 const Sequence
<JS::Value
>& aData
) {
196 RefPtr
<Console
> console(mConsole
);
197 console
->StringMethodInternal(aCx
, aLabel
, aData
, Console::MethodTimeLog
,
201 void ConsoleInstance::TimeEnd(JSContext
* aCx
, const nsAString
& aLabel
) {
202 RefPtr
<Console
> console(mConsole
);
203 console
->StringMethodInternal(aCx
, aLabel
, Sequence
<JS::Value
>(),
204 Console::MethodTimeEnd
, u
"timeEnd"_ns
);
207 void ConsoleInstance::TimeStamp(JSContext
* aCx
,
208 const JS::Handle
<JS::Value
> aData
) {
209 ConsoleCommon::ClearException
ce(aCx
);
211 Sequence
<JS::Value
> data
;
212 SequenceRooter
<JS::Value
> rooter(aCx
, &data
);
214 if (aData
.isString() && !data
.AppendElement(aData
, fallible
)) {
218 RefPtr
<Console
> console(mConsole
);
219 console
->MethodInternal(aCx
, Console::MethodTimeStamp
, u
"timeStamp"_ns
, data
);
222 void ConsoleInstance::Profile(JSContext
* aCx
,
223 const Sequence
<JS::Value
>& aData
) {
224 RefPtr
<Console
> console(mConsole
);
225 console
->ProfileMethodInternal(aCx
, Console::MethodProfile
, u
"profile"_ns
,
229 void ConsoleInstance::ProfileEnd(JSContext
* aCx
,
230 const Sequence
<JS::Value
>& aData
) {
231 RefPtr
<Console
> console(mConsole
);
232 console
->ProfileMethodInternal(aCx
, Console::MethodProfileEnd
,
233 u
"profileEnd"_ns
, aData
);
236 void ConsoleInstance::Assert(JSContext
* aCx
, bool aCondition
,
237 const Sequence
<JS::Value
>& aData
) {
239 RefPtr
<Console
> console(mConsole
);
240 console
->MethodInternal(aCx
, Console::MethodAssert
, u
"assert"_ns
, aData
);
244 void ConsoleInstance::Count(JSContext
* aCx
, const nsAString
& aLabel
) {
245 RefPtr
<Console
> console(mConsole
);
246 console
->StringMethodInternal(aCx
, aLabel
, Sequence
<JS::Value
>(),
247 Console::MethodCount
, u
"count"_ns
);
250 void ConsoleInstance::CountReset(JSContext
* aCx
, const nsAString
& aLabel
) {
251 RefPtr
<Console
> console(mConsole
);
252 console
->StringMethodInternal(aCx
, aLabel
, Sequence
<JS::Value
>(),
253 Console::MethodCountReset
, u
"countReset"_ns
);
256 void ConsoleInstance::Clear(JSContext
* aCx
) {
257 const Sequence
<JS::Value
> data
;
258 RefPtr
<Console
> console(mConsole
);
259 console
->MethodInternal(aCx
, Console::MethodClear
, u
"clear"_ns
, data
);
262 bool ConsoleInstance::ShouldLog(ConsoleLogLevel aLevel
) {
263 return mConsole
->mCurrentLogLevel
<=
264 mConsole
->WebIDLLogLevelToInteger(aLevel
);
267 void ConsoleInstance::ReportForServiceWorkerScope(const nsAString
& aScope
,
268 const nsAString
& aMessage
,
269 const nsACString
& aFilename
,
270 uint32_t aLineNumber
,
271 uint32_t aColumnNumber
,
272 ConsoleLevel aLevel
) {
273 if (!NS_IsMainThread()) {
277 ConsoleUtils::ReportForServiceWorkerScope(
278 aScope
, aMessage
, aFilename
, aLineNumber
, aColumnNumber
,
279 WebIDLevelToConsoleUtilsLevel(aLevel
));
282 } // namespace mozilla::dom