summaryrefslogtreecommitdiffstats
path: root/dom/console/ConsoleInstance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/console/ConsoleInstance.cpp')
-rw-r--r--dom/console/ConsoleInstance.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/dom/console/ConsoleInstance.cpp b/dom/console/ConsoleInstance.cpp
new file mode 100644
index 0000000000..24477da56c
--- /dev/null
+++ b/dom/console/ConsoleInstance.cpp
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "mozilla/dom/ConsoleInstance.h"
+#include "Console.h"
+#include "mozilla/dom/ConsoleBinding.h"
+#include "mozilla/Preferences.h"
+#include "ConsoleCommon.h"
+#include "ConsoleUtils.h"
+#include "nsContentUtils.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ConsoleInstance, mConsole)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ConsoleInstance)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ConsoleInstance)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConsoleInstance)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+NS_INTERFACE_MAP_END
+
+namespace {
+
+ConsoleUtils::Level WebIDLevelToConsoleUtilsLevel(ConsoleLevel aLevel) {
+ switch (aLevel) {
+ case ConsoleLevel::Log:
+ return ConsoleUtils::eLog;
+ case ConsoleLevel::Warning:
+ return ConsoleUtils::eWarning;
+ case ConsoleLevel::Error:
+ return ConsoleUtils::eError;
+ default:
+ break;
+ }
+
+ return ConsoleUtils::eLog;
+}
+
+} // namespace
+
+ConsoleInstance::ConsoleInstance(JSContext* aCx,
+ const ConsoleInstanceOptions& aOptions)
+ : mMaxLogLevel(ConsoleLogLevel::All),
+ mConsole(new Console(aCx, nullptr, 0, 0)) {
+ mConsole->mConsoleID = aOptions.mConsoleID;
+ mConsole->mPassedInnerID = aOptions.mInnerID;
+
+ if (aOptions.mDump.WasPassed()) {
+ mConsole->mDumpFunction = &aOptions.mDump.Value();
+ }
+
+ mConsole->mPrefix = aOptions.mPrefix;
+
+ // Let's inform that this is a custom instance.
+ mConsole->mChromeInstance = true;
+
+ if (aOptions.mMaxLogLevel.WasPassed()) {
+ mMaxLogLevel = aOptions.mMaxLogLevel.Value();
+ }
+
+ if (!aOptions.mMaxLogLevelPref.IsEmpty()) {
+ if (!NS_IsMainThread()) {
+ NS_WARNING("Console.maxLogLevelPref is not supported on workers!");
+ // Set the log level based on what we have.
+ SetLogLevel();
+ return;
+ }
+
+ CopyUTF16toUTF8(aOptions.mMaxLogLevelPref, mMaxLogLevelPref);
+
+ Preferences::RegisterCallback(MaxLogLevelPrefChangedCallback,
+ mMaxLogLevelPref, this);
+ }
+ SetLogLevel();
+}
+
+ConsoleInstance::~ConsoleInstance() {
+ AssertIsOnMainThread();
+ if (!mMaxLogLevelPref.IsEmpty()) {
+ Preferences::UnregisterCallback(MaxLogLevelPrefChangedCallback,
+ mMaxLogLevelPref, this);
+ }
+};
+
+ConsoleLogLevel PrefToValue(const nsACString& aPref,
+ const ConsoleLogLevel aLevel) {
+ if (aPref.IsEmpty()) {
+ return aLevel;
+ }
+
+ nsAutoCString value;
+ nsresult rv = Preferences::GetCString(PromiseFlatCString(aPref).get(), value);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ nsString message;
+ message.AssignLiteral(
+ "Console.maxLogLevelPref used with a non-existing pref: ");
+ message.Append(NS_ConvertUTF8toUTF16(aPref));
+
+ nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
+ true /* from chrome context*/);
+ return aLevel;
+ }
+
+ int index = FindEnumStringIndexImpl(value.get(), value.Length(),
+ ConsoleLogLevelValues::strings);
+ if (NS_WARN_IF(index < 0)) {
+ nsString message;
+ message.AssignLiteral("Invalid Console.maxLogLevelPref value: ");
+ message.Append(NS_ConvertUTF8toUTF16(value));
+
+ nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
+ true /* from chrome context*/);
+ return aLevel;
+ }
+
+ MOZ_ASSERT(index < (int)ConsoleLogLevelValues::Count);
+ return static_cast<ConsoleLogLevel>(index);
+}
+
+void ConsoleInstance::SetLogLevel() {
+ mConsole->mCurrentLogLevel = mConsole->WebIDLLogLevelToInteger(
+ PrefToValue(mMaxLogLevelPref, mMaxLogLevel));
+}
+
+// static
+void ConsoleInstance::MaxLogLevelPrefChangedCallback(
+ const char* /* aPrefName */, void* aSelf) {
+ AssertIsOnMainThread();
+ auto* instance = static_cast<ConsoleInstance*>(aSelf);
+ if (MOZ_UNLIKELY(!instance->mConsole)) {
+ // We've been unlinked already but not destroyed yet. Bail.
+ return;
+ }
+ RefPtr pin{instance};
+ pin->SetLogLevel();
+}
+
+JSObject* ConsoleInstance::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return ConsoleInstance_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+#define METHOD(name, string) \
+ void ConsoleInstance::name(JSContext* aCx, \
+ const Sequence<JS::Value>& aData) { \
+ RefPtr<Console> console(mConsole); \
+ console->MethodInternal(aCx, Console::Method##name, \
+ nsLiteralString(string), aData); \
+ }
+
+METHOD(Log, u"log")
+METHOD(Info, u"info")
+METHOD(Warn, u"warn")
+METHOD(Error, u"error")
+METHOD(Exception, u"exception")
+METHOD(Debug, u"debug")
+METHOD(Table, u"table")
+METHOD(Trace, u"trace")
+METHOD(Dir, u"dir");
+METHOD(Dirxml, u"dirxml");
+METHOD(Group, u"group")
+METHOD(GroupCollapsed, u"groupCollapsed")
+
+#undef METHOD
+
+void ConsoleInstance::GroupEnd(JSContext* aCx) {
+ const Sequence<JS::Value> data;
+ RefPtr<Console> console(mConsole);
+ console->MethodInternal(aCx, Console::MethodGroupEnd, u"groupEnd"_ns, data);
+}
+
+void ConsoleInstance::Time(JSContext* aCx, const nsAString& aLabel) {
+ RefPtr<Console> console(mConsole);
+ console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+ Console::MethodTime, u"time"_ns);
+}
+
+void ConsoleInstance::TimeLog(JSContext* aCx, const nsAString& aLabel,
+ const Sequence<JS::Value>& aData) {
+ RefPtr<Console> console(mConsole);
+ console->StringMethodInternal(aCx, aLabel, aData, Console::MethodTimeLog,
+ u"timeLog"_ns);
+}
+
+void ConsoleInstance::TimeEnd(JSContext* aCx, const nsAString& aLabel) {
+ RefPtr<Console> console(mConsole);
+ console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+ Console::MethodTimeEnd, u"timeEnd"_ns);
+}
+
+void ConsoleInstance::TimeStamp(JSContext* aCx,
+ const JS::Handle<JS::Value> aData) {
+ ConsoleCommon::ClearException ce(aCx);
+
+ Sequence<JS::Value> data;
+ SequenceRooter<JS::Value> rooter(aCx, &data);
+
+ if (aData.isString() && !data.AppendElement(aData, fallible)) {
+ return;
+ }
+
+ RefPtr<Console> console(mConsole);
+ console->MethodInternal(aCx, Console::MethodTimeStamp, u"timeStamp"_ns, data);
+}
+
+void ConsoleInstance::Profile(JSContext* aCx,
+ const Sequence<JS::Value>& aData) {
+ RefPtr<Console> console(mConsole);
+ console->ProfileMethodInternal(aCx, Console::MethodProfile, u"profile"_ns,
+ aData);
+}
+
+void ConsoleInstance::ProfileEnd(JSContext* aCx,
+ const Sequence<JS::Value>& aData) {
+ RefPtr<Console> console(mConsole);
+ console->ProfileMethodInternal(aCx, Console::MethodProfileEnd,
+ u"profileEnd"_ns, aData);
+}
+
+void ConsoleInstance::Assert(JSContext* aCx, bool aCondition,
+ const Sequence<JS::Value>& aData) {
+ if (!aCondition) {
+ RefPtr<Console> console(mConsole);
+ console->MethodInternal(aCx, Console::MethodAssert, u"assert"_ns, aData);
+ }
+}
+
+void ConsoleInstance::Count(JSContext* aCx, const nsAString& aLabel) {
+ RefPtr<Console> console(mConsole);
+ console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+ Console::MethodCount, u"count"_ns);
+}
+
+void ConsoleInstance::CountReset(JSContext* aCx, const nsAString& aLabel) {
+ RefPtr<Console> console(mConsole);
+ console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+ Console::MethodCountReset, u"countReset"_ns);
+}
+
+void ConsoleInstance::Clear(JSContext* aCx) {
+ const Sequence<JS::Value> data;
+ RefPtr<Console> console(mConsole);
+ console->MethodInternal(aCx, Console::MethodClear, u"clear"_ns, data);
+}
+
+bool ConsoleInstance::ShouldLog(ConsoleLogLevel aLevel) {
+ return mConsole->mCurrentLogLevel <=
+ mConsole->WebIDLLogLevelToInteger(aLevel);
+}
+
+void ConsoleInstance::ReportForServiceWorkerScope(const nsAString& aScope,
+ const nsAString& aMessage,
+ const nsAString& aFilename,
+ uint32_t aLineNumber,
+ uint32_t aColumnNumber,
+ ConsoleLevel aLevel) {
+ if (!NS_IsMainThread()) {
+ return;
+ }
+
+ ConsoleUtils::ReportForServiceWorkerScope(
+ aScope, aMessage, aFilename, aLineNumber, aColumnNumber,
+ WebIDLevelToConsoleUtilsLevel(aLevel));
+}
+
+} // namespace mozilla::dom