void
DecoderDoctorDocumentWatcher::ReportAnalysis(
  const NotificationAndReportStringId& aNotification,
  bool aIsSolved,
  const nsAString& aParams)
{
  MOZ_ASSERT(NS_IsMainThread());

  if (!mDocument) {
    return;
  }

  // Report non-solved issues to console.
  if (!aIsSolved) {
    // 'params' will only be forwarded for non-empty strings.
    const char16_t* params[1] = { aParams.Data() };
    DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::ReportAnalysis() ReportToConsole - aMsg='%s' params[0]='%s'",
             this, mDocument, aNotification.mReportStringId,
             aParams.IsEmpty() ? "<no params>" : NS_ConvertUTF16toUTF8(params[0]).get());
    nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                    NS_LITERAL_CSTRING("Media"),
                                    mDocument,
                                    nsContentUtils::eDOM_PROPERTIES,
                                    aNotification.mReportStringId,
                                    aParams.IsEmpty() ? nullptr : params,
                                    aParams.IsEmpty() ? 0 : 1);
  }

  // "media.decoder-doctor.notifications-allowed" controls which notifications
  // may be dispatched to the front-end. It either contains:
  // - '*' -> Allow everything.
  // - Comma-separater list of ids -> Allow if aReportStringId (from
  //                                  dom.properties) is one of them.
  // - Nothing (missing or empty) -> Disable everything.
  nsAdoptingCString filter =
    Preferences::GetCString("media.decoder-doctor.notifications-allowed");
  filter.StripWhitespace();
  if (filter.EqualsLiteral("*")
      || StringListContains(filter, aNotification.mReportStringId)) {
    DispatchNotification(
      mDocument->GetInnerWindow(), aNotification, aIsSolved, aParams);
  }
}
static void
ReportAnalysis(nsIDocument* aDocument,
               const NotificationAndReportStringId& aNotification,
               bool aIsSolved,
               const nsAString& aFormats = NS_LITERAL_STRING(""),
               const MediaResult& aDecodeIssue = NS_OK,
               bool aDecodeIssueIsError = true,
               const nsACString& aDocURL = NS_LITERAL_CSTRING(""),
               const nsAString& aResourceURL = NS_LITERAL_STRING(""))
{
  MOZ_ASSERT(NS_IsMainThread());

  if (!aDocument) {
    return;
  }

  nsString decodeIssueDescription;
  if (aDecodeIssue != NS_OK) {
    decodeIssueDescription.Assign(MediaResultDescription(aDecodeIssue,
                                                         aDecodeIssueIsError));
  }

  // Report non-solved issues to console.
  if (!aIsSolved) {
    // Build parameter array needed by console message.
    AutoTArray<const char16_t*,
               NotificationAndReportStringId::maxReportParams> params;
    for (int i = 0; i < NotificationAndReportStringId::maxReportParams; ++i) {
      if (aNotification.mReportParams[i] == ReportParam::None) {
        break;
      }
      switch (aNotification.mReportParams[i]) {
      case ReportParam::Formats:
        params.AppendElement(aFormats.Data());
        break;
      case ReportParam::DecodeIssue:
        params.AppendElement(decodeIssueDescription.Data());
        break;
      case ReportParam::DocURL:
        params.AppendElement(NS_ConvertUTF8toUTF16(aDocURL).Data());
        break;
      case ReportParam::ResourceURL:
        params.AppendElement(aResourceURL.Data());
        break;
      default:
        MOZ_ASSERT_UNREACHABLE("Bad notification parameter choice");
        break;
      }
    }
    ReportToConsole(aDocument, aNotification.mReportStringId, params);
  }

  if (AllowNotification(aNotification) &&
      AllowDecodeIssue(aDecodeIssue, aDecodeIssueIsError)) {
    DispatchNotification(
      aDocument->GetInnerWindow(), aNotification, aIsSolved,
      aFormats,
      decodeIssueDescription,
      aDocURL,
      aResourceURL);
  }
}