2017-10-27 20:33:53 +03:00
|
|
|
/* -*- 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
|
2012-05-21 15:12:37 +04:00
|
|
|
* 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/. */
|
2001-03-07 04:52:16 +03:00
|
|
|
|
2002-02-19 23:41:32 +03:00
|
|
|
#ifndef nsBidi_h__
|
|
|
|
#define nsBidi_h__
|
2001-03-07 04:52:16 +03:00
|
|
|
|
2017-09-22 12:37:17 +03:00
|
|
|
#include "unicode/ubidi.h"
|
2017-09-22 12:37:17 +03:00
|
|
|
#include "ICUUtils.h"
|
2017-09-22 12:37:17 +03:00
|
|
|
#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>.
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
nsBidi()
|
|
|
|
{
|
|
|
|
mBiDi = ubidi_open();
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/** @brief Destructor. */
|
2017-09-22 12:37:17 +03:00
|
|
|
~nsBidi()
|
|
|
|
{
|
|
|
|
ubidi_close(mBiDi);
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
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);
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
nsBidiDirection GetDirection()
|
|
|
|
{
|
|
|
|
return nsBidiDirection(ubidi_getDirection(mBiDi));
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the paragraph level of the text.
|
|
|
|
*
|
|
|
|
* @param aParaLevel receives a <code>NSBIDI_XXX</code> value indicating
|
|
|
|
* the paragraph level
|
|
|
|
*
|
|
|
|
* @see nsBidiLevel
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
nsBidiLevel GetParaLevel()
|
|
|
|
{
|
|
|
|
return ubidi_getParaLevel(mBiDi);
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
2017-10-05 10:11:50 +03:00
|
|
|
* <code>CountRuns</code> should be called before this.
|
|
|
|
* before the runs are retrieved.
|
2017-09-22 12:37:17 +03:00
|
|
|
*
|
|
|
|
* @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>.
|
2017-10-05 10:11:50 +03:00
|
|
|
* This pointer cannot be <code>nullptr</code>.
|
2017-09-22 12:37:17 +03:00
|
|
|
*
|
|
|
|
* @param aLevel will receive the level of the run.
|
2017-10-05 10:11:50 +03:00
|
|
|
* This pointer cannot be <code>nullptr</code>.
|
2017-09-22 12:37:17 +03:00
|
|
|
*/
|
2017-10-05 10:11:50 +03:00
|
|
|
void GetLogicalRun(int32_t aLogicalStart,
|
|
|
|
int32_t* aLogicalLimit, nsBidiLevel* aLevel);
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2017-10-05 10:11:50 +03:00
|
|
|
nsresult CountRuns(int32_t* aRunCount);
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2017-09-22 12:37:17 +03:00
|
|
|
* @returns the directionality of the run,
|
2017-09-22 12:37:17 +03:00
|
|
|
* <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) {
|
2017-09-22 12:37:17 +03:00
|
|
|
* dir = pBidi->GetVisualRun(i, &logicalStart, &length);
|
2017-09-22 12:37:17 +03:00
|
|
|
* 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.
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
nsBidiDirection GetVisualRun(int32_t aRunIndex,
|
|
|
|
int32_t* aLogicalStart, int32_t* aLength)
|
|
|
|
{
|
|
|
|
return nsBidiDirection(ubidi_getVisualRun(mBiDi, aRunIndex,
|
|
|
|
aLogicalStart, aLength));
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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>.
|
|
|
|
*/
|
2017-09-22 12:37:17 +03:00
|
|
|
static void ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength,
|
|
|
|
int32_t* aIndexMap)
|
|
|
|
{
|
|
|
|
ubidi_reorderVisual(aLevels, aLength, aIndexMap);
|
|
|
|
}
|
2017-09-22 12:37:17 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsBidi(const nsBidi&) = delete;
|
|
|
|
void operator=(const nsBidi&) = delete;
|
|
|
|
|
|
|
|
UBiDi* mBiDi;
|
2017-10-05 10:11:50 +03:00
|
|
|
// The two fields below are updated when CountRuns is called.
|
|
|
|
const nsBidiLevel* mLevels = nullptr;
|
|
|
|
int32_t mLength = 0;
|
2017-09-22 12:37:17 +03:00
|
|
|
};
|
2001-03-07 04:52:16 +03:00
|
|
|
|
2002-02-19 23:41:32 +03:00
|
|
|
#endif // _nsBidi_h_
|