editor/libeditor/text/nsInternetCiter.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsAString.h"
     8 #include "nsCOMPtr.h"
     9 #include "nsCRT.h"
    10 #include "nsDebug.h"
    11 #include "nsDependentSubstring.h"
    12 #include "nsError.h"
    13 #include "nsILineBreaker.h"
    14 #include "nsInternetCiter.h"
    15 #include "nsLWBrkCIID.h"
    16 #include "nsServiceManagerUtils.h"
    17 #include "nsString.h"
    18 #include "nsStringIterator.h"
    20 const char16_t gt ('>');
    21 const char16_t space (' ');
    22 const char16_t nbsp (0xa0);
    23 const char16_t nl ('\n');
    24 const char16_t cr('\r');
    26 /** Mail citations using the Internet style: > This is a citation
    27   */
    29 nsresult
    30 nsInternetCiter::GetCiteString(const nsAString& aInString, nsAString& aOutString)
    31 {
    32   aOutString.Truncate();
    33   char16_t uch = nl;
    35   // Strip trailing new lines which will otherwise turn up
    36   // as ugly quoted empty lines.
    37   nsReadingIterator <char16_t> beginIter,endIter;
    38   aInString.BeginReading(beginIter);
    39   aInString.EndReading(endIter);
    40   while(beginIter!= endIter &&
    41         (*endIter == cr ||
    42          *endIter == nl))
    43   {
    44     --endIter;
    45   }
    47   // Loop over the string:
    48   while (beginIter != endIter)
    49   {
    50     if (uch == nl)
    51     {
    52       aOutString.Append(gt);
    53       // No space between >: this is ">>> " style quoting, for
    54       // compatibility with RFC 2646 and format=flowed.
    55       if (*beginIter != gt)
    56         aOutString.Append(space);
    57     }
    59     uch = *beginIter;
    60     ++beginIter;
    62     aOutString += uch;
    63   }
    65   if (uch != nl)
    66     aOutString += nl;
    68   return NS_OK;
    69 }
    71 nsresult
    72 nsInternetCiter::StripCitesAndLinebreaks(const nsAString& aInString,
    73                                          nsAString& aOutString,
    74                                          bool aLinebreaksToo,
    75                                          int32_t* aCiteLevel)
    76 {
    77   if (aCiteLevel)
    78     *aCiteLevel = 0;
    80   aOutString.Truncate();
    81   nsReadingIterator <char16_t> beginIter,endIter;
    82   aInString.BeginReading(beginIter);
    83   aInString.EndReading(endIter);
    84   while (beginIter!= endIter)  // loop over lines
    85   {
    86     // Clear out cites first, at the beginning of the line:
    87     int32_t thisLineCiteLevel = 0;
    88     while (beginIter!= endIter && (*beginIter == gt || nsCRT::IsAsciiSpace(*beginIter)))
    89     {
    90       if (*beginIter == gt) ++thisLineCiteLevel;
    91       ++beginIter;
    92     }
    94     // Now copy characters until line end:
    95     while (beginIter != endIter && (*beginIter != '\r' && *beginIter != '\n'))
    96     {
    97       aOutString.Append(*beginIter);
    98       ++beginIter;
    99     }
   100     if (aLinebreaksToo)
   101       aOutString.Append(char16_t(' '));
   102     else
   103       aOutString.Append(char16_t('\n'));    // DOM linebreaks, not NS_LINEBREAK
   104       // Skip over any more consecutive linebreak-like characters:
   105     while (beginIter != endIter && (*beginIter == '\r' || *beginIter == '\n'))
   106       ++beginIter;
   108     // Done with this line -- update cite level
   109     if (aCiteLevel && (thisLineCiteLevel > *aCiteLevel))
   110       *aCiteLevel = thisLineCiteLevel;
   111   }
   112   return NS_OK;
   113 }
   115 nsresult
   116 nsInternetCiter::StripCites(const nsAString& aInString, nsAString& aOutString)
   117 {
   118   return StripCitesAndLinebreaks(aInString, aOutString, false, 0);
   119 }
   121 static void AddCite(nsAString& aOutString, int32_t citeLevel)
   122 {
   123   for (int32_t i = 0; i < citeLevel; ++i)
   124     aOutString.Append(gt);
   125   if (citeLevel > 0)
   126     aOutString.Append(space);
   127 }
   129 static inline void
   130 BreakLine(nsAString& aOutString, uint32_t& outStringCol,
   131           uint32_t citeLevel)
   132 {
   133   aOutString.Append(nl);
   134   if (citeLevel > 0)
   135   {
   136     AddCite(aOutString, citeLevel);
   137     outStringCol = citeLevel + 1;
   138   }
   139   else
   140     outStringCol = 0;
   141 }
   143 static inline bool IsSpace(char16_t c)
   144 {
   145   return (nsCRT::IsAsciiSpace(c) || (c == nl) || (c == cr) || (c == nbsp));
   146 }
   148 nsresult
   149 nsInternetCiter::Rewrap(const nsAString& aInString,
   150                         uint32_t aWrapCol, uint32_t aFirstLineOffset,
   151                         bool aRespectNewlines,
   152                         nsAString& aOutString)
   153 {
   154   // There shouldn't be returns in this string, only dom newlines.
   155   // Check to make sure:
   156 #ifdef DEBUG
   157   int32_t cr = aInString.FindChar(char16_t('\r'));
   158   NS_ASSERTION((cr < 0), "Rewrap: CR in string gotten from DOM!\n");
   159 #endif /* DEBUG */
   161   aOutString.Truncate();
   163   nsresult rv;
   164   nsCOMPtr<nsILineBreaker> lineBreaker = do_GetService(NS_LBRK_CONTRACTID, &rv);
   165   NS_ENSURE_SUCCESS(rv, rv);
   167   // Loop over lines in the input string, rewrapping each one.
   168   uint32_t length;
   169   uint32_t posInString = 0;
   170   uint32_t outStringCol = 0;
   171   uint32_t citeLevel = 0;
   172   const nsPromiseFlatString &tString = PromiseFlatString(aInString);
   173   length = tString.Length();
   174 #ifdef DEBUG_wrapping
   175   int loopcount = 0;
   176 #endif
   177   while (posInString < length)
   178   {
   179 #ifdef DEBUG_wrapping
   180     printf("Outer loop: '%s'\n",
   181            NS_LossyConvertUTF16toASCII(Substring(tString, posInString,
   182                                                 length-posInString)).get());
   183     printf("out string is now: '%s'\n",
   184            NS_LossyConvertUTF16toASCII(aOutString).get());
   186 #endif
   188     // Get the new cite level here since we're at the beginning of a line
   189     uint32_t newCiteLevel = 0;
   190     while (posInString < length && tString[posInString] == gt)
   191     {
   192       ++newCiteLevel;
   193       ++posInString;
   194       while (posInString < length && tString[posInString] == space)
   195         ++posInString;
   196     }
   197     if (posInString >= length)
   198       break;
   200     // Special case: if this is a blank line, maintain a blank line
   201     // (retain the original paragraph breaks)
   202     if (tString[posInString] == nl && !aOutString.IsEmpty())
   203     {
   204       if (aOutString.Last() != nl)
   205         aOutString.Append(nl);
   206       AddCite(aOutString, newCiteLevel);
   207       aOutString.Append(nl);
   209       ++posInString;
   210       outStringCol = 0;
   211       continue;
   212     }
   214     // If the cite level has changed, then start a new line with the
   215     // new cite level (but if we're at the beginning of the string,
   216     // don't bother).
   217     if (newCiteLevel != citeLevel && posInString > newCiteLevel+1
   218         && outStringCol != 0)
   219     {
   220       BreakLine(aOutString, outStringCol, 0);
   221     }
   222     citeLevel = newCiteLevel;
   224     // Prepend the quote level to the out string if appropriate
   225     if (outStringCol == 0)
   226     {
   227       AddCite(aOutString, citeLevel);
   228       outStringCol = citeLevel + (citeLevel ? 1 : 0);
   229     }
   230     // If it's not a cite, and we're not at the beginning of a line in
   231     // the output string, add a space to separate new text from the
   232     // previous text.
   233     else if (outStringCol > citeLevel)
   234     {
   235       aOutString.Append(space);
   236       ++outStringCol;
   237     }
   239     // find the next newline -- don't want to go farther than that
   240     int32_t nextNewline = tString.FindChar(nl, posInString);
   241     if (nextNewline < 0) nextNewline = length;
   243     // For now, don't wrap unquoted lines at all.
   244     // This is because the plaintext edit window has already wrapped them
   245     // by the time we get them for rewrap, yet when we call the line
   246     // breaker, it will refuse to break backwards, and we'll end up
   247     // with a line that's too long and gets displayed as a lone word
   248     // on a line by itself.  Need special logic to detect this case
   249     // and break it ourselves without resorting to the line breaker.
   250     if (citeLevel == 0)
   251     {
   252       aOutString.Append(Substring(tString, posInString,
   253                                   nextNewline-posInString));
   254       outStringCol += nextNewline - posInString;
   255       if (nextNewline != (int32_t)length)
   256       {
   257         aOutString.Append(nl);
   258         outStringCol = 0;
   259       }
   260       posInString = nextNewline+1;
   261       continue;
   262     }
   264     // Otherwise we have to use the line breaker and loop
   265     // over this line of the input string to get all of it:
   266     while ((int32_t)posInString < nextNewline)
   267     {
   268 #ifdef DEBUG_wrapping
   269       if (++loopcount > 1000)
   270         NS_ASSERTION(false, "possible infinite loop in nsInternetCiter\n");
   272       printf("Inner loop: '%s'\n",
   273              NS_LossyConvertUTF16toASCII(Substring(tString, posInString,
   274                                               nextNewline-posInString)).get());
   275 #endif
   277       // Skip over initial spaces:
   278       while ((int32_t)posInString < nextNewline
   279              && nsCRT::IsAsciiSpace(tString[posInString]))
   280         ++posInString;
   282       // If this is a short line, just append it and continue:
   283       if (outStringCol + nextNewline - posInString <= aWrapCol-citeLevel-1)
   284       {
   285         // If this short line is the final one in the in string,
   286         // then we need to include the final newline, if any:
   287         if (nextNewline+1 == (int32_t)length && tString[nextNewline-1] == nl)
   288           ++nextNewline;
   290         // Trim trailing spaces:
   291         int32_t lastRealChar = nextNewline;
   292         while ((uint32_t)lastRealChar > posInString
   293                && nsCRT::IsAsciiSpace(tString[lastRealChar-1]))
   294           --lastRealChar;
   296         aOutString += Substring(tString,
   297                                 posInString, lastRealChar - posInString);
   298         outStringCol += lastRealChar - posInString;
   299         posInString = nextNewline + 1;
   300         continue;
   301       }
   303       int32_t eol = posInString + aWrapCol - citeLevel - outStringCol;
   304       // eol is the prospective end of line.
   305       // We'll first look backwards from there for a place to break.
   306       // If it's already less than our current position,
   307       // then our line is already too long, so break now.
   308       if (eol <= (int32_t)posInString)
   309       {
   310         BreakLine(aOutString, outStringCol, citeLevel);
   311         continue;    // continue inner loop, with outStringCol now at bol
   312       }
   314       int32_t breakPt = 0;
   315       rv = NS_ERROR_BASE;
   316       if (lineBreaker)
   317       {
   318         breakPt = lineBreaker->Prev(tString.get() + posInString,
   319                                  length - posInString, eol + 1 - posInString);
   320         if (breakPt == NS_LINEBREAKER_NEED_MORE_TEXT)
   321         {
   322           // if we couldn't find a breakpoint looking backwards,
   323           // and we're not starting a new line, then end this line
   324           // and loop around again:
   325           if (outStringCol > citeLevel + 1)
   326           {
   327             BreakLine(aOutString, outStringCol, citeLevel);
   328             continue;    // continue inner loop, with outStringCol now at bol
   329           }
   331           // Else try looking forwards:
   332           breakPt = lineBreaker->Next(tString.get() + posInString,
   333                                       length - posInString, eol - posInString);
   334           if (breakPt == NS_LINEBREAKER_NEED_MORE_TEXT) rv = NS_ERROR_BASE;
   335           else rv = NS_OK;
   336         }
   337         else rv = NS_OK;
   338       }
   339       // If rv is okay, then breakPt is the place to break.
   340       // If we get out here and rv is set, something went wrong with line
   341       // breaker.  Just break the line, hard.
   342       if (NS_FAILED(rv))
   343       {
   344 #ifdef DEBUG_akkana
   345         printf("nsInternetCiter: LineBreaker not working -- breaking hard\n");
   346 #endif
   347         breakPt = eol;
   348       }
   350       // Special case: maybe we should have wrapped last time.
   351       // If the first breakpoint here makes the current line too long,
   352       // then if we already have text on the current line,
   353       // break and loop around again.
   354       // If we're at the beginning of the current line, though,
   355       // don't force a break since the long word might be a url
   356       // and breaking it would make it unclickable on the other end.
   357       const int SLOP = 6;
   358       if (outStringCol + breakPt > aWrapCol + SLOP
   359           && outStringCol > citeLevel+1)
   360       {
   361         BreakLine(aOutString, outStringCol, citeLevel);
   362         continue;
   363       }
   365       nsAutoString sub (Substring(tString, posInString, breakPt));
   366       // skip newlines or whitespace at the end of the string
   367       int32_t subend = sub.Length();
   368       while (subend > 0 && IsSpace(sub[subend-1]))
   369         --subend;
   370       sub.Left(sub, subend);
   371       aOutString += sub;
   372       outStringCol += sub.Length();
   373       // Advance past the whitespace which caused the wrap:
   374       posInString += breakPt;
   375       while (posInString < length && IsSpace(tString[posInString]))
   376         ++posInString;
   378       // Add a newline and the quote level to the out string
   379       if (posInString < length)    // not for the last line, though
   380         BreakLine(aOutString, outStringCol, citeLevel);
   382     } // end inner loop within one line of aInString
   383 #ifdef DEBUG_wrapping
   384     printf("---------\nEnd inner loop: out string is now '%s'\n-----------\n",
   385            NS_LossyConvertUTF16toASCII(aOutString).get());
   386 #endif
   387   } // end outer loop over lines of aInString
   389 #ifdef DEBUG_wrapping
   390   printf("Final out string is now: '%s'\n",
   391          NS_LossyConvertUTF16toASCII(aOutString).get());
   393 #endif
   394   return NS_OK;
   395 }

mercurial