diff options
Diffstat (limited to 'layout/base/nsBidi.h')
-rw-r--r-- | layout/base/nsBidi.h | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/layout/base/nsBidi.h b/layout/base/nsBidi.h new file mode 100644 index 0000000000..9c6e456da2 --- /dev/null +++ b/layout/base/nsBidi.h @@ -0,0 +1,208 @@ +/* -*- 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_ |