Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  InternetCiter.cpp   Sprache: C

 

/* 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 "InternetCiter.h"

#include "mozilla/IntegerRange.h"
#include "mozilla/intl/Segmenter.h"
#include "HTMLEditUtils.h"
#include "nsAString.h"
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsDebug.h"
#include "nsDependentSubstring.h"
#include "nsError.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsStringIterator.h"

#include <algorithm>

namespace mozilla {

/**
 * Mail citations using the Internet style: > This is a citation.
 */


void InternetCiter::GetCiteString(const nsAString& aInString,
                                  nsAString& aOutString) {
  aOutString.Truncate();
  char16_t uch = HTMLEditUtils::kNewLine;

  // Strip trailing new lines which will otherwise turn up
  // as ugly quoted empty lines.
  nsReadingIterator<char16_t> beginIter, endIter;
  aInString.BeginReading(beginIter);
  aInString.EndReading(endIter);
  while (beginIter != endIter && (*endIter == HTMLEditUtils::kCarriageReturn ||
                                  *endIter == HTMLEditUtils::kNewLine)) {
    --endIter;
  }

  while (beginIter != endIter) {
    if (uch == HTMLEditUtils::kNewLine) {
      aOutString.Append(HTMLEditUtils::kGreaterThan);
      // Do not insert a space between adjacent > quote markers.  This keeps
      // ">>> " style quoting for RFC 2646 format=flowed compatibility.
      if (*beginIter != HTMLEditUtils::kGreaterThan) {
        aOutString.Append(HTMLEditUtils::kSpace);
      }
    }

    uch = *beginIter;
    ++beginIter;

    aOutString += uch;
  }

  if (uch != HTMLEditUtils::kNewLine) {
    aOutString += HTMLEditUtils::kNewLine;
  }
}

uint32_t InternetCiter::QuotePrefixLength(uint32_t aQuoteLevel) {
  return aQuoteLevel ? aQuoteLevel + 1 : 0;
}

void InternetCiter::AppendQuoteMarkers(nsAString& aOutString,
                                       uint32_t aQuoteLevel) {
  DebugOnly<uint32_t> oldLength = aOutString.Length();
  for ([[maybe_unused]] uint32_t i : IntegerRange(aQuoteLevel)) {
    aOutString.Append(HTMLEditUtils::kGreaterThan);
  }
  if (aQuoteLevel > 0) {
    aOutString.Append(HTMLEditUtils::kSpace);
  }
  MOZ_ASSERT(aOutString.Length() - oldLength == QuotePrefixLength(aQuoteLevel));
}

bool InternetCiter::IsSpace(char16_t aChar) {
  return nsCRT::IsAsciiSpace(aChar) || aChar == HTMLEditUtils::kNBSP;
}

bool InternetCiter::IsBodyBoundarySpace(char16_t aChar) {
  return nsCRT::IsAsciiSpace(aChar) && aChar != HTMLEditUtils::kNewLine &&
         aChar != HTMLEditUtils::kCarriageReturn;
}

struct InternetCiter::BodyRange {
  uint32_t mStart = 0;
  uint32_t mEnd = 0;

  bool IsEmpty() const { return mStart == mEnd; }
  uint32_t Length() const { return mEnd - mStart; }
};

struct InternetCiter::PhysicalLine {
  uint32_t mQuoteLevel = 0;
  uint32_t mBodyStart = 0;
  uint32_t mBodyEnd = 0;
  bool mEndedWithNewLine = false;

  bool IsQuoted() const { return mQuoteLevel > 0; }
  uint32_t NextLineStart() const {
    return mBodyEnd + (mEndedWithNewLine ? 1 : 0);
  }
  BodyRange GetTrimmedBody(const nsPromiseFlatString& aString) const;

  static PhysicalLine FromString(const nsPromiseFlatString& aString,
                                 uint32_t aLineStart);
};

InternetCiter::PhysicalLine InternetCiter::PhysicalLine::FromString(
    const nsPromiseFlatString& aString, uint32_t aLineStart) {
  const uint32_t length = aString.Length();
  PhysicalLine line;
  uint32_t offset = aLineStart;

  while (offset < length && aString[offset] == HTMLEditUtils::kGreaterThan) {
    ++line.mQuoteLevel;
    ++offset;
    while (offset < length && aString[offset] == HTMLEditUtils::kSpace) {
      ++offset;
    }
  }

  line.mBodyStart = offset;
  while (offset < length && aString[offset] != HTMLEditUtils::kNewLine) {
    ++offset;
  }
  line.mBodyEnd = offset;
  line.mEndedWithNewLine = offset < length;
  return line;
}

InternetCiter::BodyRange InternetCiter::PhysicalLine::GetTrimmedBody(
    const nsPromiseFlatString& aString) const {
  BodyRange range{mBodyStart, mBodyEnd};
  while (range.mStart < range.mEnd &&
         InternetCiter::IsBodyBoundarySpace(aString[range.mStart])) {
    ++range.mStart;
  }
  while (range.mEnd > range.mStart &&
         InternetCiter::IsBodyBoundarySpace(aString[range.mEnd - 1])) {
    --range.mEnd;
  }
  return range;
}

void InternetCiter::EnsureEndsWithLineBreak(nsAString& aOutString) {
  if (!aOutString.IsEmpty() && aOutString.Last() != HTMLEditUtils::kNewLine) {
    aOutString.Append(HTMLEditUtils::kNewLine);
  }
}

void InternetCiter::StartOutputLine(nsAString& aOutString,
                                    uint32_t aQuoteLevel) {
  EnsureEndsWithLineBreak(aOutString);
  AppendQuoteMarkers(aOutString, aQuoteLevel);
}

struct InternetCiter::QuotedParagraph {
  uint32_t mQuoteLevel = 0;
  uint32_t mBodyColumn = 0;
  bool mHasOpenLine = false;

  void StartLine(nsAString& aOutString, uint32_t aQuoteLevel);
  void FinishLine(nsAString& aOutString);
  void Reset();
  void AppendBodySeparator(nsAString& aOutString, uint32_t aBodyWrapColumn);
  void AppendBodyRange(nsAString& aOutString,
                       const nsPromiseFlatString& aString, uint32_t aQuoteLevel,
                       const BodyRange& aRange, uint32_t aWrapCol);
};

void InternetCiter::QuotedParagraph::StartLine(nsAString& aOutString,
                                               uint32_t aQuoteLevel) {
  if (mHasOpenLine && mQuoteLevel == aQuoteLevel) {
    return;
  }
  InternetCiter::StartOutputLine(aOutString, aQuoteLevel);
  mQuoteLevel = aQuoteLevel;
  mBodyColumn = 0;
  mHasOpenLine = true;
}

void InternetCiter::QuotedParagraph::FinishLine(nsAString& aOutString) {
  if (mHasOpenLine) {
    InternetCiter::EnsureEndsWithLineBreak(aOutString);
    mBodyColumn = 0;
    mHasOpenLine = false;
  }
}

void InternetCiter::QuotedParagraph::Reset() {
  mQuoteLevel = 0;
  mBodyColumn = 0;
  mHasOpenLine = false;
}

uint32_t InternetCiter::ShortestUsefulQuotedBodyColumn(uint32_t aWrapCol) {
  // Require each quoted line to carry at least this many body columns.  With
  // the default 72-column wrap, that minimum is 24 columns.
  constexpr uint32_t kShortestUsefulQuotedBodyColumn = 16;
  constexpr uint32_t kShortestUsefulBodyFractionDenominator = 3;
  return std::max(kShortestUsefulQuotedBodyColumn,
                  aWrapCol / kShortestUsefulBodyFractionDenominator);
}

uint32_t InternetCiter::BodyWrapColumn(uint32_t aQuoteLevel,
                                       uint32_t aWrapCol) {
  const uint32_t quotePrefixLength = QuotePrefixLength(aQuoteLevel);
  const uint32_t bodyColumnsWithinWrapColumn =
      quotePrefixLength < aWrapCol ? aWrapCol - quotePrefixLength : 0;
  // Do not wrap quoted bodies narrower than the minimum useful body column.
  return std::max(bodyColumnsWithinWrapColumn,
                  ShortestUsefulQuotedBodyColumn(aWrapCol));
}

uint32_t InternetCiter::FindBodyLineBreak(const nsPromiseFlatString& aString,
                                          const BodyRange& aRange,
                                          uint32_t aBodyWrapColumn) {
  MOZ_ASSERT(!aRange.IsEmpty());
  MOZ_ASSERT(aBodyWrapColumn);

  uint32_t breakLength = 0;
  Maybe<uint32_t> nextBreakLength;
  intl::LineBreakIteratorUtf16 lineBreakIter(
      Span<const char16_t>(aString.get() + aRange.mStart, aRange.Length()));
  while (true) {
    nextBreakLength = lineBreakIter.Next();
    if (!nextBreakLength || *nextBreakLength > aBodyWrapColumn) {
      break;
    }
    breakLength = *nextBreakLength;
  }

  if (breakLength) {
    return breakLength;
  }

  if (nextBreakLength && *nextBreakLength) {
    return *nextBreakLength;
  }

  // Fallback to always return a positive length.
  return std::min(aRange.Length(), std::max(1u, aBodyWrapColumn));
}

uint32_t InternetCiter::AppendBodySlice(nsAString& aOutString,
                                        const nsPromiseFlatString& aString,
                                        uint32_t aBodyStart, uint32_t aLength) {
  while (aLength && IsSpace(aString[aBodyStart + aLength - 1])) {
    --aLength;
  }
  aOutString.Append(Substring(aString, aBodyStart, aLength));
  return aLength;
}

void InternetCiter::QuotedParagraph::AppendBodySeparator(
    nsAString& aOutString, uint32_t aBodyWrapColumn) {
  if (!mHasOpenLine || !mBodyColumn) {
    return;
  }

  if (mBodyColumn + 1 > aBodyWrapColumn) {
    FinishLine(aOutString);
    return;
  }

  aOutString.Append(HTMLEditUtils::kSpace);
  ++mBodyColumn;
}

void InternetCiter::QuotedParagraph::AppendBodyRange(
    nsAString& aOutString, const nsPromiseFlatString& aString,
    uint32_t aQuoteLevel, const BodyRange& aRange, uint32_t aWrapCol) {
  if (aRange.IsEmpty()) {
    return;
  }
  BodyRange range = aRange;

  const uint32_t bodyWrapColumn =
      InternetCiter::BodyWrapColumn(aQuoteLevel, aWrapCol);
  AppendBodySeparator(aOutString, bodyWrapColumn);

  while (!range.IsEmpty()) {
    StartLine(aOutString, aQuoteLevel);

    const uint32_t availableBodyColumns =
        bodyWrapColumn > mBodyColumn ? bodyWrapColumn - mBodyColumn : 0;
    if (!availableBodyColumns) {
      FinishLine(aOutString);
      continue;
    }

    if (range.Length() <= availableBodyColumns) {
      aOutString.Append(Substring(aString, range.mStart, range.Length()));
      mBodyColumn += range.Length();
      return;
    }

    const uint32_t breakLength =
        InternetCiter::FindBodyLineBreak(aString, range, availableBodyColumns);
    constexpr uint32_t kLongWordOverflowTolerance = 6;
    // Allow words to slightly exceed the break limit to keep lines readable.
    if (breakLength > availableBodyColumns && mBodyColumn &&
        breakLength - availableBodyColumns > kLongWordOverflowTolerance) {
      // Do not split URLs at the beginning of lines, so they remain clickable.
      FinishLine(aOutString);
      continue;
    }

    mBodyColumn += InternetCiter::AppendBodySlice(aOutString, aString,
                                                  range.mStart, breakLength);
    range.mStart += breakLength;
    while (range.mStart < range.mEnd &&
           InternetCiter::IsSpace(aString[range.mStart])) {
      ++range.mStart;
    }
    if (!range.IsEmpty()) {
      FinishLine(aOutString);
    }
  }
}

void InternetCiter::EmitBlankQuotedLine(nsAString& aOutString,
                                        uint32_t aQuoteLevel,
                                        bool aEndedWithNewLine,
                                        QuotedParagraph& aParagraph) {
  aParagraph.FinishLine(aOutString);
  StartOutputLine(aOutString, aQuoteLevel);
  if (aEndedWithNewLine) {
    aOutString.Append(HTMLEditUtils::kNewLine);
  }
  aParagraph.Reset();
}

void InternetCiter::EmitUnquotedLine(nsAString& aOutString,
                                     const nsPromiseFlatString& aString,
                                     const PhysicalLine& aLine,
                                     QuotedParagraph& aParagraph) {
  aParagraph.FinishLine(aOutString);
  aParagraph.Reset();
  StartOutputLine(aOutString, 0);
  aOutString.Append(
      Substring(aString, aLine.mBodyStart, aLine.mBodyEnd - aLine.mBodyStart));
  if (aLine.mEndedWithNewLine) {
    aOutString.Append(HTMLEditUtils::kNewLine);
  }
}

void InternetCiter::Rewrap(const nsAString& aInString, uint32_t aWrapCol,
                           uint32_t aFirstLineOffset, bool aRespectNewlines,
                           nsAString& aOutString) {
  // Rewrap operates on DOM newlines.
#ifdef DEBUG
  int32_t crPosition = aInString.FindChar(HTMLEditUtils::kCarriageReturn);
  NS_ASSERTION(crPosition < 0, "Rewrap: CR in string gotten from DOM!\n");
#endif /* DEBUG */

  aOutString.Truncate();

  const nsPromiseFlatString& tString = PromiseFlatString(aInString);
  const uint32_t length = tString.Length();
  QuotedParagraph quotedParagraph;

  // Rewrap quoted mail as a sequence of physical lines:
  //   1. Parse the quote prefix and body range.
  //   2. Join adjacent quoted body lines with the same quote level.
  //   3. Wrap only body text, then re-emit the quote prefix.
  for (uint32_t nextLineStart = 0; nextLineStart < length;) {
    const PhysicalLine line = PhysicalLine::FromString(tString, nextLineStart);
    nextLineStart = line.NextLineStart();

    if (!line.IsQuoted()) {
      EmitUnquotedLine(aOutString, tString, line, quotedParagraph);
      continue;
    }

    if (quotedParagraph.mHasOpenLine &&
        quotedParagraph.mQuoteLevel != line.mQuoteLevel) {
      quotedParagraph.FinishLine(aOutString);
    }

    const BodyRange body = line.GetTrimmedBody(tString);
    if (body.IsEmpty()) {
      EmitBlankQuotedLine(aOutString, line.mQuoteLevel, line.mEndedWithNewLine,
                          quotedParagraph);
      continue;
    }

    quotedParagraph.AppendBodyRange(aOutString, tString, line.mQuoteLevel, body,
                                    aWrapCol);
  }
}

}  // namespace mozilla

Messung V0.5 in Prozent
C=96 H=80 G=88

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-09-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126864
#Domains=2039723