forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			208 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			208 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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/. */
 | |
| 
 | |
| #ifndef nsBidi_h__
 | |
| #define nsBidi_h__
 | |
| 
 | |
| #include "unicode/ubidi.h"
 | |
| #include "ICUUtils.h"
 | |
| #include "nsIFrame.h"  // for nsBidiLevel/nsBidiDirection declarations
 | |
| 
 | |
| // nsBidi implemented as a simple wrapper around the bidi reordering engine
 | |
| // from ICU.
 | |
| // We could eliminate this and let callers use the ICU functions directly
 | |
| // once we no longer care about building without ICU available.
 | |
| 
 | |
| class nsBidi {
 | |
|  public:
 | |
|   /** @brief Default constructor.
 | |
|    *
 | |
|    * The nsBidi object is initially empty. It is assigned
 | |
|    * the Bidi properties of a paragraph by <code>SetPara()</code>.
 | |
|    */
 | |
|   nsBidi() { mBiDi = ubidi_open(); }
 | |
| 
 | |
|   /** @brief Destructor. */
 | |
|   ~nsBidi() { ubidi_close(mBiDi); }
 | |
| 
 | |
|   /**
 | |
|    * Perform the Unicode Bidi algorithm.
 | |
|    *
 | |
|    * @param aText is a pointer to the single-paragraph text that the
 | |
|    *      Bidi algorithm will be performed on
 | |
|    *      (step (P1) of the algorithm is performed externally).
 | |
|    *      <strong>The text must be (at least) <code>aLength</code> long.
 | |
|    *      </strong>
 | |
|    *
 | |
|    * @param aLength is the length of the text; if <code>aLength==-1</code> then
 | |
|    *      the text must be zero-terminated.
 | |
|    *
 | |
|    * @param aParaLevel specifies the default level for the paragraph;
 | |
|    *      it is typically 0 (LTR) or 1 (RTL).
 | |
|    *      If the function shall determine the paragraph level from the text,
 | |
|    *      then <code>aParaLevel</code> can be set to
 | |
|    *      either <code>NSBIDI_DEFAULT_LTR</code>
 | |
|    *      or <code>NSBIDI_DEFAULT_RTL</code>;
 | |
|    *      if there is no strongly typed character, then
 | |
|    *      the desired default is used (0 for LTR or 1 for RTL).
 | |
|    *      Any other value between 0 and <code>NSBIDI_MAX_EXPLICIT_LEVEL</code>
 | |
|    *      is also valid, with odd levels indicating RTL.
 | |
|    */
 | |
|   nsresult SetPara(const char16_t* aText, int32_t aLength,
 | |
|                    nsBidiLevel aParaLevel) {
 | |
|     UErrorCode error = U_ZERO_ERROR;
 | |
|     ubidi_setPara(mBiDi, reinterpret_cast<const UChar*>(aText), aLength,
 | |
|                   aParaLevel, nullptr, &error);
 | |
|     return ICUUtils::UErrorToNsResult(error);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the directionality of the text.
 | |
|    *
 | |
|    * @param aDirection receives a <code>NSBIDI_XXX</code> value that indicates
 | |
|    *       if the entire text represented by this object is unidirectional,
 | |
|    *       and which direction, or if it is mixed-directional.
 | |
|    *
 | |
|    * @see nsBidiDirection
 | |
|    */
 | |
|   nsBidiDirection GetDirection() {
 | |
|     return nsBidiDirection(ubidi_getDirection(mBiDi));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Get the paragraph level of the text.
 | |
|    *
 | |
|    * @param aParaLevel receives a <code>NSBIDI_XXX</code> value indicating
 | |
|    *                   the paragraph level
 | |
|    *
 | |
|    * @see nsBidiLevel
 | |
|    */
 | |
|   nsBidiLevel GetParaLevel() { return ubidi_getParaLevel(mBiDi); }
 | |
| 
 | |
|   /**
 | |
|    * Get a logical run.
 | |
|    * This function returns information about a run and is used
 | |
|    * to retrieve runs in logical order.<p>
 | |
|    * This is especially useful for line-breaking on a paragraph.
 | |
|    * <code>CountRuns</code> should be called before this.
 | |
|    * before the runs are retrieved.
 | |
|    *
 | |
|    * @param aLogicalStart is the first character of the run.
 | |
|    *
 | |
|    * @param aLogicalLimit will receive the limit of the run.
 | |
|    *      The l-value that you point to here may be the
 | |
|    *      same expression (variable) as the one for
 | |
|    *      <code>aLogicalStart</code>.
 | |
|    *      This pointer cannot be <code>nullptr</code>.
 | |
|    *
 | |
|    * @param aLevel will receive the level of the run.
 | |
|    *      This pointer cannot be <code>nullptr</code>.
 | |
|    */
 | |
|   void GetLogicalRun(int32_t aLogicalStart, int32_t* aLogicalLimit,
 | |
|                      nsBidiLevel* aLevel);
 | |
| 
 | |
|   /**
 | |
|    * Get the number of runs.
 | |
|    * This function may invoke the actual reordering on the
 | |
|    * <code>nsBidi</code> object, after <code>SetPara</code>
 | |
|    * may have resolved only the levels of the text. Therefore,
 | |
|    * <code>CountRuns</code> may have to allocate memory,
 | |
|    * and may fail doing so.
 | |
|    *
 | |
|    * @param aRunCount will receive the number of runs.
 | |
|    */
 | |
|   nsresult CountRuns(int32_t* aRunCount);
 | |
| 
 | |
|   /**
 | |
|    * Get one run's logical start, length, and directionality,
 | |
|    * which can be 0 for LTR or 1 for RTL.
 | |
|    * In an RTL run, the character at the logical start is
 | |
|    * visually on the right of the displayed run.
 | |
|    * The length is the number of characters in the run.<p>
 | |
|    * <code>CountRuns</code> should be called
 | |
|    * before the runs are retrieved.
 | |
|    *
 | |
|    * @param aRunIndex is the number of the run in visual order, in the
 | |
|    *      range <code>[0..CountRuns-1]</code>.
 | |
|    *
 | |
|    * @param aLogicalStart is the first logical character index in the text.
 | |
|    *      The pointer may be <code>nullptr</code> if this index is not needed.
 | |
|    *
 | |
|    * @param aLength is the number of characters (at least one) in the run.
 | |
|    *      The pointer may be <code>nullptr</code> if this is not needed.
 | |
|    *
 | |
|    * @returns the directionality of the run,
 | |
|    *       <code>NSBIDI_LTR==0</code> or <code>NSBIDI_RTL==1</code>,
 | |
|    *       never <code>NSBIDI_MIXED</code>.
 | |
|    *
 | |
|    * @see CountRuns<p>
 | |
|    *
 | |
|    * Example:
 | |
|    * @code
 | |
|    *  int32_t i, count, logicalStart, visualIndex=0, length;
 | |
|    *  nsBidiDirection dir;
 | |
|    *  pBidi->CountRuns(&count);
 | |
|    *  for(i=0; i<count; ++i) {
 | |
|    *    dir = pBidi->GetVisualRun(i, &logicalStart, &length);
 | |
|    *    if(NSBIDI_LTR==dir) {
 | |
|    *      do { // LTR
 | |
|    *        show_char(text[logicalStart++], visualIndex++);
 | |
|    *      } while(--length>0);
 | |
|    *    } else {
 | |
|    *      logicalStart+=length;  // logicalLimit
 | |
|    *      do { // RTL
 | |
|    *        show_char(text[--logicalStart], visualIndex++);
 | |
|    *      } while(--length>0);
 | |
|    *    }
 | |
|    *  }
 | |
|    * @endcode
 | |
|    *
 | |
|    * Note that in right-to-left runs, code like this places
 | |
|    * modifier letters before base characters and second surrogates
 | |
|    * before first ones.
 | |
|    */
 | |
|   nsBidiDirection GetVisualRun(int32_t aRunIndex, int32_t* aLogicalStart,
 | |
|                                int32_t* aLength) {
 | |
|     return nsBidiDirection(
 | |
|         ubidi_getVisualRun(mBiDi, aRunIndex, aLogicalStart, aLength));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This is a convenience function that does not use a nsBidi object.
 | |
|    * It is intended to be used for when an application has determined the levels
 | |
|    * of objects (character sequences) and just needs to have them reordered
 | |
|    * (L2). This is equivalent to using <code>GetVisualMap</code> on a
 | |
|    * <code>nsBidi</code> object.
 | |
|    *
 | |
|    * @param aLevels is an array with <code>aLength</code> levels that have been
 | |
|    *      determined by the application.
 | |
|    *
 | |
|    * @param aLength is the number of levels in the array, or, semantically,
 | |
|    *      the number of objects to be reordered.
 | |
|    *      It must be <code>aLength>0</code>.
 | |
|    *
 | |
|    * @param aIndexMap is a pointer to an array of <code>aLength</code>
 | |
|    *      indexes which will reflect the reordering of the characters.
 | |
|    *      The array does not need to be initialized.<p>
 | |
|    *      The index map will result in
 | |
|    *        <code>aIndexMap[aVisualIndex]==aLogicalIndex</code>.
 | |
|    */
 | |
|   static void ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength,
 | |
|                             int32_t* aIndexMap) {
 | |
|     ubidi_reorderVisual(aLevels, aLength, aIndexMap);
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   nsBidi(const nsBidi&) = delete;
 | |
|   void operator=(const nsBidi&) = delete;
 | |
| 
 | |
|   UBiDi* mBiDi;
 | |
|   // The two fields below are updated when CountRuns is called.
 | |
|   const nsBidiLevel* mLevels = nullptr;
 | |
|   int32_t mLength = 0;
 | |
| };
 | |
| 
 | |
| #endif  // _nsBidi_h_
 | 
