void
ErrorReporter::AddToError(const nsString &aErrorText)
{
  if (!ShouldReportErrors()) return;

  if (mError.IsEmpty()) {
    mError = aErrorText;
    mErrorLineNumber = mScanner->GetLineNumber();
    mErrorColNumber = mScanner->GetColumnNumber();
    // Retrieve the error line once per line, and reuse the same nsString
    // for all errors on that line.  That causes the text of the line to
    // be shared among all the nsIScriptError objects.
    if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
      // Be careful here: the error line might be really long and OOM
      // when we try to make a copy here.  If so, just leave it empty.
      if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
        mErrorLine.Truncate();
      }
      mPrevErrorLineNumber = mErrorLineNumber;
    }
  } else {
    mError.AppendLiteral("  ");
    mError.Append(aErrorText);
  }
}
void
ErrorReporter::OutputError()
{
  if (mError.IsEmpty()) {
    return;
  }
  if (!ShouldReportErrors()) {
    ClearError();
    return;
  }

  if (mInnerWindowID == 0 && (mSheet || mLoader)) {
    if (mSheet) {
      mInnerWindowID = mSheet->FindOwningWindowInnerID();
    }
    if (mInnerWindowID == 0 && mLoader) {
      nsIDocument* doc = mLoader->GetDocument();
      if (doc) {
        mInnerWindowID = doc->InnerWindowID();
      }
    }
    // don't attempt this again, even if we failed
    mSheet = nullptr;
    mLoader = nullptr;
  }

  if (mFileName.IsEmpty()) {
    if (mURI) {
      if (!sSpecCache) {
        sSpecCache = new ShortTermURISpecCache;
        NS_ADDREF(sSpecCache);
      }
      mFileName = sSpecCache->GetSpec(mURI);
      mURI = nullptr;
    } else {
      mFileName.AssignLiteral("from DOM");
    }
  }

  nsresult rv;
  nsCOMPtr<nsIScriptError> errorObject =
    do_CreateInstance(sScriptErrorFactory, &rv);

  if (NS_SUCCEEDED(rv)) {
    rv = errorObject->InitWithWindowID(mError,
                                       mFileName,
                                       mErrorLine,
                                       mErrorLineNumber,
                                       mErrorColNumber,
                                       nsIScriptError::warningFlag,
                                       "CSS Parser",
                                       mInnerWindowID);
    if (NS_SUCCEEDED(rv)) {
      sConsoleService->LogMessage(errorObject);
    }
  }

  ClearError();
}
void
ErrorReporter::ReportUnexpected(const char *aMessage)
{
  if (!ShouldReportErrors()) return;

  nsAutoString str;
  sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
                                   getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::ReportUnexpectedEOF(PRUnichar aExpected)
{
  if (!ShouldReportErrors()) return;

  const PRUnichar expectedStr[] = {
    PRUnichar('\''), aExpected, PRUnichar('\''), PRUnichar(0)
  };
  const PRUnichar *params[1] = { expectedStr };

  nsAutoString str;
  sStringBundle->FormatStringFromName(NS_LITERAL_STRING("PEUnexpEOF2").get(),
                                      params, ArrayLength(params),
                                      getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
{
  if (!ShouldReportErrors()) return;

  nsAutoString innerStr;
  sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
                                   getter_Copies(innerStr));
  const PRUnichar *params[1] = { innerStr.get() };

  nsAutoString str;
  sStringBundle->FormatStringFromName(NS_LITERAL_STRING("PEUnexpEOF2").get(),
                                      params, ArrayLength(params),
                                      getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::ReportUnexpected(const char *aMessage,
                                const nsCSSToken &aToken)
{
  if (!ShouldReportErrors()) return;

  nsAutoString tokenString;
  aToken.AppendToString(tokenString);
  const PRUnichar *params[1] = { tokenString.get() };

  nsAutoString str;
  sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
                                      params, ArrayLength(params),
                                      getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::ReportUnexpected(const char *aMessage,
                                const nsString &aParam)
{
  if (!ShouldReportErrors()) return;

  nsAutoString qparam;
  nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
  const PRUnichar *params[1] = { qparam.get() };

  nsAutoString str;
  sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
                                      params, ArrayLength(params),
                                      getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::ReportUnexpectedEOF(char16_t aExpected)
{
  if (!ShouldReportErrors()) return;

  const char16_t expectedStr[] = {
    char16_t('\''), aExpected, char16_t('\''), char16_t(0)
  };
  const char16_t *params[1] = { expectedStr };

  nsAutoString str;
  sStringBundle->FormatStringFromName(u"PEUnexpEOF2",
                                      params, ArrayLength(params),
                                      getter_Copies(str));
  AddToError(str);
}
void
ErrorReporter::AddToError(const nsString &aErrorText)
{
  if (!ShouldReportErrors()) return;

  if (mError.IsEmpty()) {
    mError = aErrorText;
    mErrorLineNumber = mScanner->GetLineNumber();
    mErrorColNumber = mScanner->GetColumnNumber();
    // Retrieve the error line once per line, and reuse the same nsString
    // for all errors on that line.  That causes the text of the line to
    // be shared among all the nsIScriptError objects.
    if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
      mErrorLine = mScanner->GetCurrentLine();
      mPrevErrorLineNumber = mErrorLineNumber;
    }
  } else {
    mError.AppendLiteral("  ");
    mError.Append(aErrorText);
  }
}