tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsBidiPresUtils.h (24029B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef nsBidiPresUtils_h___
      8 #define nsBidiPresUtils_h___
      9 
     10 #include "gfxContext.h"
     11 #include "mozilla/intl/BidiClass.h"
     12 #include "mozilla/intl/BidiEmbeddingLevel.h"
     13 #include "nsBidiUtils.h"
     14 #include "nsCoord.h"
     15 #include "nsHashKeys.h"
     16 #include "nsLineBox.h"
     17 #include "nsTArray.h"
     18 
     19 #ifdef DrawText
     20 #  undef DrawText
     21 #endif
     22 
     23 struct BidiParagraphData;
     24 class BidiLineData;
     25 class gfxContext;
     26 class nsFontMetrics;
     27 class nsIFrame;
     28 class nsBlockFrame;
     29 class nsPresContext;
     30 struct nsSize;
     31 template <class T>
     32 class nsTHashtable;
     33 namespace mozilla {
     34 namespace intl {
     35 class Bidi;
     36 }
     37 class ComputedStyle;
     38 class LogicalMargin;
     39 class WritingMode;
     40 }  // namespace mozilla
     41 
     42 /**
     43 * A structure representing some continuation state for each frame on the line,
     44 * used to determine the first and the last continuation frame for each
     45 * continuation chain on the line.
     46 */
     47 struct nsFrameContinuationState : public nsVoidPtrHashKey {
     48  explicit nsFrameContinuationState(const void* aFrame)
     49      : nsVoidPtrHashKey(aFrame) {}
     50 
     51  /**
     52   * The first visual frame in the continuation chain containing this frame, or
     53   * nullptr if this frame is the first visual frame in the chain.
     54   */
     55  nsIFrame* mFirstVisualFrame{nullptr};
     56 
     57  /**
     58   * The number of frames in the continuation chain containing this frame, if
     59   * this frame is the first visual frame of the chain, or 0 otherwise.
     60   */
     61  uint32_t mFrameCount{0};
     62 
     63  /**
     64   * TRUE if this frame is the first visual frame of its continuation chain on
     65   * this line and the chain has some frames on the previous lines.
     66   */
     67  bool mHasContOnPrevLines{false};
     68 
     69  /**
     70   * TRUE if this frame is the first visual frame of its continuation chain on
     71   * this line and the chain has some frames left for next lines.
     72   */
     73  bool mHasContOnNextLines{false};
     74 };
     75 
     76 // A table of nsFrameContinuationState objects.
     77 //
     78 // This state is used between calls to nsBidiPresUtils::IsFirstOrLast.
     79 struct nsContinuationStates {
     80  static constexpr size_t kArrayMax = 32;
     81 
     82  // We use the array to gather up all the continuation state objects.  If in
     83  // the end there are more than kArrayMax of them, we convert it to a hash
     84  // table for faster lookup.
     85  bool mUseTable = false;
     86  AutoTArray<nsFrameContinuationState, kArrayMax> mValues;
     87  nsTHashtable<nsFrameContinuationState> mTable;
     88 
     89  void Insert(nsIFrame* aFrame) {
     90    if (MOZ_UNLIKELY(mUseTable)) {
     91      mTable.PutEntry(aFrame);
     92      return;
     93    }
     94    if (MOZ_LIKELY(mValues.Length() < kArrayMax)) {
     95      mValues.AppendElement(aFrame);
     96      return;
     97    }
     98    for (const auto& entry : mValues) {
     99      mTable.PutEntry(entry.GetKey());
    100    }
    101    mTable.PutEntry(aFrame);
    102    mValues.Clear();
    103    mUseTable = true;
    104  }
    105 
    106  nsFrameContinuationState* Get(nsIFrame* aFrame) {
    107    MOZ_ASSERT(mValues.IsEmpty() != mTable.IsEmpty(),
    108               "expect entries to either be in mValues or in mTable");
    109    if (mUseTable) {
    110      return mTable.GetEntry(aFrame);
    111    }
    112    for (size_t i = 0, len = mValues.Length(); i != len; ++i) {
    113      if (mValues[i].GetKey() == aFrame) {
    114        return &mValues[i];
    115      }
    116    }
    117    return nullptr;
    118  }
    119 };
    120 
    121 /**
    122 * A structure representing a logical position which should be resolved
    123 * into its visual position during BiDi processing.
    124 */
    125 struct nsBidiPositionResolve {
    126  // [in] Logical index within string.
    127  int32_t logicalIndex;
    128  // [out] Visual index within string.
    129  // If the logical position was not found, set to kNotFound.
    130  int32_t visualIndex;
    131  // [out] Visual position of the character, from the left (on the X axis), in
    132  // twips. Eessentially, this is the X position (relative to the rendering
    133  // context) where the text was drawn + the font metric of the visual string to
    134  // the left of the given logical position. If the logical position was not
    135  // found, set to kNotFound.
    136  int32_t visualLeftTwips;
    137  // [out] Visual width of the character, in twips.
    138  // If the logical position was not found, set to kNotFound.
    139  int32_t visualWidth;
    140 };
    141 
    142 class nsBidiPresUtils {
    143 public:
    144  typedef mozilla::gfx::DrawTarget DrawTarget;
    145 
    146  nsBidiPresUtils();
    147  ~nsBidiPresUtils();
    148 
    149  /**
    150   * Interface for the processor used by ProcessText. Used by process text to
    151   * collect information about the width of subruns and to notify where each
    152   * subrun should be rendered.
    153   */
    154  class BidiProcessor {
    155   public:
    156    virtual ~BidiProcessor() = default;
    157 
    158    /**
    159     * Sets the current text with the given length and the given direction.
    160     *
    161     * @remark The reason that the function gives a string instead of an index
    162     *  is that ProcessText copies and modifies the string passed to it, so
    163     *  passing an index would be impossible.
    164     *
    165     * @param aText The string of text.
    166     * @param aLength The length of the string of text.
    167     * @param aDirection The direction of the text. The string will never have
    168     *  mixed direction.
    169     */
    170    virtual void SetText(const char16_t* aText, int32_t aLength,
    171                         mozilla::intl::BidiDirection aDirection) = 0;
    172 
    173    /**
    174     * Returns the measured width of the text given in SetText. If SetText was
    175     * not called with valid parameters, the result of this call is undefined.
    176     * This call is guaranteed to only be called once between SetText calls.
    177     * Will be invoked before DrawText.
    178     */
    179    virtual nscoord GetWidth() = 0;
    180 
    181    /**
    182     * Draws the text given in SetText to a rendering context. If SetText was
    183     * not called with valid parameters, the result of this call is undefined.
    184     * This call is guaranteed to only be called once between SetText calls.
    185     *
    186     * @param aXOffset The offset of the left side of the substring to be drawn
    187     *  from the beginning of the overall string passed to ProcessText.
    188     */
    189    virtual void DrawText(nscoord aXOffset) = 0;
    190  };
    191 
    192  /**
    193   * Make Bidi engine calculate the embedding levels of the frames that are
    194   * descendants of a given block frame.
    195   *
    196   * @param aBlockFrame          The block frame
    197   *
    198   *  @lina 06/18/2000
    199   */
    200  static nsresult Resolve(nsBlockFrame* aBlockFrame);
    201  static nsresult ResolveParagraph(BidiParagraphData* aBpd);
    202  static void ResolveParagraphWithinBlock(BidiParagraphData* aBpd);
    203 
    204  /**
    205   * Reorder this line using Bidi engine.
    206   * Update frame array, following the new visual sequence.
    207   *
    208   * @return total inline size
    209   *
    210   * @lina 05/02/2000
    211   */
    212  static nscoord ReorderFrames(nsIFrame* aFirstFrameOnLine,
    213                               int32_t aNumFramesOnLine,
    214                               mozilla::WritingMode aLineWM,
    215                               const nsSize& aContainerSize, nscoord aStart);
    216 
    217  /**
    218   * Format Unicode text, taking into account bidi capabilities
    219   * of the platform. The formatting includes: reordering, Arabic shaping,
    220   * symmetric and numeric swapping, removing control characters.
    221   *
    222   * @lina 06/18/2000
    223   */
    224  static nsresult FormatUnicodeText(nsPresContext* aPresContext,
    225                                    char16_t* aText, int32_t& aTextLength,
    226                                    mozilla::intl::BidiClass aBidiClass);
    227 
    228  /**
    229   * Reorder plain text using the Unicode Bidi algorithm and send it to
    230   * a rendering context for rendering.
    231   *
    232   * @param[in] aText  the string to be rendered (in logical order)
    233   * @param aLength the number of characters in the string
    234   * @param aBaseLevel the base embedding level of the string
    235   * @param aPresContext the presentation context
    236   * @param aRenderingContext the rendering context to render to
    237   * @param aTextRunConstructionContext the rendering context to be used to
    238   * construct the textrun (affects font hinting)
    239   * @param aX the x-coordinate to render the string
    240   * @param aY the y-coordinate to render the string
    241   * @param[in,out] aPosResolve array of logical positions to resolve into
    242   * visual positions; can be nullptr if this functionality is not required
    243   * @param aPosResolveCount number of items in the aPosResolve array
    244   */
    245  static nsresult RenderText(const char16_t* aText, int32_t aLength,
    246                             mozilla::intl::BidiEmbeddingLevel aBaseLevel,
    247                             nsPresContext* aPresContext,
    248                             gfxContext& aRenderingContext,
    249                             DrawTarget* aTextRunConstructionDrawTarget,
    250                             nsFontMetrics& aFontMetrics, nscoord aX,
    251                             nscoord aY,
    252                             nsBidiPositionResolve* aPosResolve = nullptr,
    253                             int32_t aPosResolveCount = 0) {
    254    return ProcessTextForRenderingContext(
    255        aText, aLength, aBaseLevel, aPresContext, aRenderingContext,
    256        aTextRunConstructionDrawTarget, aFontMetrics, MODE_DRAW, aX, aY,
    257        aPosResolve, aPosResolveCount, nullptr);
    258  }
    259 
    260  static nscoord MeasureTextWidth(const char16_t* aText, int32_t aLength,
    261                                  mozilla::intl::BidiEmbeddingLevel aBaseLevel,
    262                                  nsPresContext* aPresContext,
    263                                  gfxContext& aRenderingContext,
    264                                  nsFontMetrics& aFontMetrics) {
    265    nscoord length;
    266    nsresult rv = ProcessTextForRenderingContext(
    267        aText, aLength, aBaseLevel, aPresContext, aRenderingContext,
    268        aRenderingContext.GetDrawTarget(), aFontMetrics, MODE_MEASURE, 0, 0,
    269        nullptr, 0, &length);
    270    return NS_SUCCEEDED(rv) ? length : 0;
    271  }
    272 
    273  /**
    274   * Check if a line is reordered, i.e., if the child frames are not
    275   * all laid out left-to-right.
    276   * @param aFirstFrameOnLine : first frame of the line to be tested
    277   * @param aNumFramesOnLine : number of frames on this line
    278   * @param[out] aLeftMost : leftmost frame on this line
    279   * @param[out] aRightMost : rightmost frame on this line
    280   */
    281  static bool CheckLineOrder(nsIFrame* aFirstFrameOnLine,
    282                             int32_t aNumFramesOnLine, nsIFrame** aLeftmost,
    283                             nsIFrame** aRightmost);
    284 
    285  /**
    286   * Get the frame to the right of the given frame, on the same line.
    287   * @param aFrame : We're looking for the frame to the right of this frame.
    288   *                 If null, return the leftmost frame on the line.
    289   * @param aFirstFrameOnLine : first frame of the line to be tested
    290   * @param aNumFramesOnLine : number of frames on this line
    291   */
    292  static nsIFrame* GetFrameToRightOf(const nsIFrame* aFrame,
    293                                     nsIFrame* aFirstFrameOnLine,
    294                                     int32_t aNumFramesOnLine);
    295 
    296  /**
    297   * Get the frame to the left of the given frame, on the same line.
    298   * @param aFrame : We're looking for the frame to the left of this frame.
    299   *                 If null, return the rightmost frame on the line.
    300   * @param aFirstFrameOnLine : first frame of the line to be tested
    301   * @param aNumFramesOnLine : number of frames on this line
    302   */
    303  static nsIFrame* GetFrameToLeftOf(const nsIFrame* aFrame,
    304                                    nsIFrame* aFirstFrameOnLine,
    305                                    int32_t aNumFramesOnLine);
    306 
    307  static nsIFrame* GetFirstLeaf(nsIFrame* aFrame);
    308 
    309  /**
    310   * Get the bidi data of the given (inline) frame.
    311   */
    312  static mozilla::FrameBidiData GetFrameBidiData(nsIFrame* aFrame);
    313 
    314  /**
    315   * Get the bidi embedding level of the given (inline) frame.
    316   */
    317  static mozilla::intl::BidiEmbeddingLevel GetFrameEmbeddingLevel(
    318      nsIFrame* aFrame);
    319 
    320  /**
    321   * Get the bidi base level of the given (inline) frame.
    322   */
    323  static mozilla::intl::BidiEmbeddingLevel GetFrameBaseLevel(
    324      const nsIFrame* aFrame);
    325 
    326  /**
    327   * Get a mozilla::intl::BidiDirection representing the direction implied by
    328   * the bidi base level of the frame.
    329   * @return mozilla::intl::BidiDirection
    330   */
    331  static mozilla::intl::BidiDirection ParagraphDirection(
    332      const nsIFrame* aFrame) {
    333    return GetFrameBaseLevel(aFrame).Direction();
    334  }
    335 
    336  /**
    337   * Get a mozilla::intl::BidiDirection representing the direction implied by
    338   * the bidi embedding level of the frame.
    339   * @return mozilla::intl::BidiDirection
    340   */
    341  static mozilla::intl::BidiDirection FrameDirection(nsIFrame* aFrame) {
    342    return GetFrameEmbeddingLevel(aFrame).Direction();
    343  }
    344 
    345  static bool IsFrameInParagraphDirection(nsIFrame* aFrame) {
    346    return ParagraphDirection(aFrame) == FrameDirection(aFrame);
    347  }
    348 
    349  // This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
    350  // because it uses the frame pointer passed in without drilling down to
    351  // the leaf frame.
    352  static bool IsReversedDirectionFrame(const nsIFrame* aFrame) {
    353    mozilla::FrameBidiData bidiData = aFrame->GetBidiData();
    354    return !bidiData.embeddingLevel.IsSameDirection(bidiData.baseLevel);
    355  }
    356 
    357  enum Mode { MODE_DRAW, MODE_MEASURE };
    358 
    359  /**
    360   * Reorder plain text using the Unicode Bidi algorithm and send it to
    361   * a processor for rendering or measuring
    362   *
    363   * @param[in] aText  the string to be processed (in logical order)
    364   * @param aLength the number of characters in the string
    365   * @param aBaseLevel the base embedding level of the string
    366   * @param aPresContext the presentation context
    367   * @param aprocessor the bidi processor
    368   * @param aMode the operation to process
    369   *  MODE_DRAW - invokes DrawText on the processor for each substring
    370   *  MODE_MEASURE - does not invoke DrawText on the processor
    371   *  Note that the string is always measured, regardless of mode
    372   * @param[in,out] aPosResolve array of logical positions to resolve into
    373   *  visual positions; can be nullptr if this functionality is not required
    374   * @param aPosResolveCount number of items in the aPosResolve array
    375   * @param[out] aWidth Pointer to where the width will be stored (may be null)
    376   */
    377  static nsresult ProcessText(const char16_t* aText, size_t aLength,
    378                              mozilla::intl::BidiEmbeddingLevel aBaseLevel,
    379                              nsPresContext* aPresContext,
    380                              BidiProcessor& aprocessor, Mode aMode,
    381                              nsBidiPositionResolve* aPosResolve,
    382                              int32_t aPosResolveCount, nscoord* aWidth,
    383                              mozilla::intl::Bidi& aBidiEngine);
    384 
    385  /**
    386   * Use style attributes to determine the base paragraph level to pass to the
    387   * bidi algorithm.
    388   *
    389   * If |unicode-bidi| is set to "[-moz-]plaintext", returns
    390   * BidiEmbeddingLevel::DefaultLTR, in other words the direction is determined
    391   * from the first strong character in the text according to rules P2 and P3 of
    392   * the bidi algorithm, or LTR if there is no strong character.
    393   *
    394   * Otherwise returns BidiEmbeddingLevel::LTR or BidiEmbeddingLevel::RTL
    395   * depending on the value of |direction|
    396   */
    397  static mozilla::intl::BidiEmbeddingLevel BidiLevelFromStyle(
    398      mozilla::ComputedStyle* aComputedStyle);
    399 
    400 private:
    401  friend class BidiLineData;
    402 
    403  static nsresult ProcessTextForRenderingContext(
    404      const char16_t* aText, int32_t aLength,
    405      mozilla::intl::BidiEmbeddingLevel aBaseLevel, nsPresContext* aPresContext,
    406      gfxContext& aRenderingContext, DrawTarget* aTextRunConstructionDrawTarget,
    407      nsFontMetrics& aFontMetrics, Mode aMode,
    408      nscoord aX,                         // DRAW only
    409      nscoord aY,                         // DRAW only
    410      nsBidiPositionResolve* aPosResolve, /* may be null */
    411      int32_t aPosResolveCount, nscoord* aWidth /* may be null */);
    412 
    413  /**
    414   * Simplified form of ProcessText body, used when aText is a single Unicode
    415   * character (one UTF-16 codepoint, or a surrogate pair), or a run that is
    416   * known to have no bidi content.
    417   */
    418  static void ProcessSimpleRun(const char16_t* aText, size_t aLength,
    419                               mozilla::intl::BidiEmbeddingLevel aBaseLevel,
    420                               nsPresContext* aPresContext,
    421                               BidiProcessor& aprocessor, Mode aMode,
    422                               nsBidiPositionResolve* aPosResolve,
    423                               int32_t aPosResolveCount, nscoord* aWidth);
    424 
    425  /**
    426   * Traverse the child frames of the block element and:
    427   *  Set up an array of the frames in logical order
    428   *  Create a string containing the text content of all the frames
    429   *  If we encounter content that requires us to split the element into more
    430   *  than one paragraph for bidi resolution, resolve the paragraph up to that
    431   *  point.
    432   */
    433  static void TraverseFrames(nsIFrame* aCurrentFrame, BidiParagraphData* aBpd);
    434 
    435  /**
    436   * Perform a recursive "pre-traversal" of the child frames of a block or
    437   * inline container frame, to determine whether full bidi resolution is
    438   * actually needed.
    439   * This explores the same frames as TraverseFrames (above), but is less
    440   * expensive and may allow us to avoid performing the full TraverseFrames
    441   * operation.
    442   * @param   aFirstChild  frame to start traversal from
    443   * @param[in/out]  aCurrContent  the content node that we've most recently
    444   *          scanned for RTL characters (so that when descendant frames refer
    445   *          to the same content, we can avoid repeatedly scanning it).
    446   * @return  true if it finds that bidi is (or may be) required,
    447   *          false if no potentially-bidi content is present.
    448   */
    449  static bool ChildListMayRequireBidi(nsIFrame* aFirstChild,
    450                                      nsIContent** aCurrContent);
    451 
    452  /**
    453   * Position ruby content frames (ruby base/text frame).
    454   * Called from RepositionRubyFrame.
    455   */
    456  static void RepositionRubyContentFrame(
    457      nsIFrame* aFrame, mozilla::WritingMode aFrameWM,
    458      const mozilla::LogicalMargin& aBorderPadding);
    459 
    460  /*
    461   * Position ruby frames. Called from RepositionFrame.
    462   */
    463  static nscoord RepositionRubyFrame(
    464      nsIFrame* aFrame, nsContinuationStates* aContinuationStates,
    465      const mozilla::WritingMode aContainerWM,
    466      const mozilla::LogicalMargin& aBorderPadding);
    467 
    468  /*
    469   * Position aFrame and its descendants to their visual places. Also if aFrame
    470   * is not leaf, resize it to embrace its children.
    471   *
    472   * @param aFrame               The frame which itself and its children are
    473   *                             going to be repositioned
    474   * @param aIsEvenLevel         TRUE means the embedding level of this frame
    475   *                             is even (LTR)
    476   * @param aStartOrEnd          The distance to the start or the end of aFrame
    477   *                             without considering its inline margin. If the
    478   *                             container is reordering frames in reverse
    479   *                             direction, it's the distance to the end,
    480   *                             otherwise, it's the distance to the start.
    481   * @param aContinuationStates  A map from nsIFrame* to
    482   *                             nsFrameContinuationState
    483   * @return                     The isize aFrame takes, including margins.
    484   */
    485  static nscoord RepositionFrame(nsIFrame* aFrame, bool aIsEvenLevel,
    486                                 nscoord aStartOrEnd,
    487                                 nsContinuationStates* aContinuationStates,
    488                                 mozilla::WritingMode aContainerWM,
    489                                 bool aContainerReverseOrder,
    490                                 const nsSize& aContainerSize);
    491 
    492  /*
    493   * Initialize the continuation state(nsFrameContinuationState) to
    494   * (nullptr, 0) for aFrame and its descendants.
    495   *
    496   * @param aFrame               The frame which itself and its descendants will
    497   *                             be initialized
    498   * @param aContinuationStates  A map from nsIFrame* to
    499   *                             nsFrameContinuationState
    500   */
    501  static void InitContinuationStates(nsIFrame* aFrame,
    502                                     nsContinuationStates* aContinuationStates);
    503 
    504  /*
    505   * Determine if aFrame is first or last, and set aIsFirst and
    506   * aIsLast values. Also set continuation states of
    507   * aContinuationStates.
    508   *
    509   * A frame is first if it's the first appearance of its continuation
    510   * chain on the line and the chain is on its first line.
    511   * A frame is last if it's the last appearance of its continuation
    512   * chain on the line and the chain is on its last line.
    513   *
    514   * N.B: "First appearance" and "Last appearance" in the previous
    515   * paragraph refer to the frame's inline direction, not necessarily
    516   * the line's.
    517   *
    518   * @param aContinuationStates        A map from nsIFrame* to
    519   *                                    nsFrameContinuationState
    520   * @param[in] aSpanDirMatchesLineDir TRUE means that the inline
    521   *                                    direction of aFrame is the same
    522   *                                    as its container
    523   * @param[out] aIsFirst              TRUE means aFrame is first frame
    524   *                                    or continuation
    525   * @param[out] aIsLast               TRUE means aFrame is last frame
    526   *                                    or continuation
    527   */
    528  static void IsFirstOrLast(nsIFrame* aFrame,
    529                            nsContinuationStates* aContinuationStates,
    530                            bool aSpanInLineOrder /* in */,
    531                            bool& aIsFirst /* out */, bool& aIsLast /* out */);
    532 
    533  /**
    534   *  Adjust frame positions following their visual order
    535   *
    536   *  @param aFirstChild the first kid
    537   *  @return total inline size
    538   *
    539   *  @lina 04/11/2000
    540   */
    541  static nscoord RepositionInlineFrames(const BidiLineData& aBld,
    542                                        mozilla::WritingMode aLineWM,
    543                                        const nsSize& aContainerSize,
    544                                        nscoord aStart);
    545 
    546  /**
    547   * Helper method for Resolve()
    548   * Truncate a text frame to the end of a single-directional run and possibly
    549   * create a continuation frame for the remainder of its content.
    550   *
    551   * @param aFrame       the original frame
    552   * @param aLine        the line box containing aFrame
    553   * @param aNewFrame    [OUT] the new frame that was created
    554   * @param aStart       [IN] the start of the content mapped by aFrame (and
    555   *                          any fluid continuations)
    556   * @param aEnd         [IN] the offset of the end of the single-directional
    557   *                          text run.
    558   * @see Resolve()
    559   * @see RemoveBidiContinuation()
    560   */
    561  static inline void EnsureBidiContinuation(nsIFrame* aFrame,
    562                                            const nsLineList::iterator aLine,
    563                                            nsIFrame** aNewFrame,
    564                                            int32_t aStart, int32_t aEnd);
    565 
    566  /**
    567   * Helper method for Resolve()
    568   * Convert one or more bidi continuation frames created in a previous reflow
    569   * by EnsureBidiContinuation() into fluid continuations.
    570   * @param aFrame       the frame whose continuations are to be removed
    571   * @param aFirstIndex  index of aFrame in mLogicalFrames
    572   * @param aLastIndex   index of the last frame to be removed
    573   *
    574   * @see Resolve()
    575   * @see EnsureBidiContinuation()
    576   */
    577  static void RemoveBidiContinuation(BidiParagraphData* aBpd, nsIFrame* aFrame,
    578                                     int32_t aFirstIndex, int32_t aLastIndex);
    579 
    580  static void CalculateBidiClass(const char16_t* aText, int32_t& aOffset,
    581                                 int32_t aBidiClassLimit, int32_t& aRunLimit,
    582                                 int32_t& aRunLength, int32_t& aRunCount,
    583                                 mozilla::intl::BidiClass& aBidiClass,
    584                                 mozilla::intl::BidiClass& aPrevBidiClass);
    585 
    586  static void StripBidiControlCharacters(char16_t* aText, int32_t& aTextLength);
    587 };
    588 
    589 #endif /* nsBidiPresUtils_h___ */