Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/nsBidi.h
Line
Count
Source (jump to first uncovered line)
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 nsBidi_h__
8
#define nsBidi_h__
9
10
#include "unicode/ubidi.h"
11
#include "ICUUtils.h"
12
#include "nsIFrame.h" // for nsBidiLevel/nsBidiDirection declarations
13
14
// nsBidi implemented as a simple wrapper around the bidi reordering engine
15
// from ICU.
16
// We could eliminate this and let callers use the ICU functions directly
17
// once we no longer care about building without ICU available.
18
19
class nsBidi
20
{
21
public:
22
  /** @brief Default constructor.
23
   *
24
   * The nsBidi object is initially empty. It is assigned
25
   * the Bidi properties of a paragraph by <code>SetPara()</code>.
26
   */
27
  nsBidi()
28
0
  {
29
0
    mBiDi = ubidi_open();
30
0
  }
31
32
  /** @brief Destructor. */
33
  ~nsBidi()
34
0
  {
35
0
    ubidi_close(mBiDi);
36
0
  }
37
38
  /**
39
   * Perform the Unicode Bidi algorithm.
40
   *
41
   * @param aText is a pointer to the single-paragraph text that the
42
   *      Bidi algorithm will be performed on
43
   *      (step (P1) of the algorithm is performed externally).
44
   *      <strong>The text must be (at least) <code>aLength</code> long.</strong>
45
   *
46
   * @param aLength is the length of the text; if <code>aLength==-1</code> then
47
   *      the text must be zero-terminated.
48
   *
49
   * @param aParaLevel specifies the default level for the paragraph;
50
   *      it is typically 0 (LTR) or 1 (RTL).
51
   *      If the function shall determine the paragraph level from the text,
52
   *      then <code>aParaLevel</code> can be set to
53
   *      either <code>NSBIDI_DEFAULT_LTR</code>
54
   *      or <code>NSBIDI_DEFAULT_RTL</code>;
55
   *      if there is no strongly typed character, then
56
   *      the desired default is used (0 for LTR or 1 for RTL).
57
   *      Any other value between 0 and <code>NSBIDI_MAX_EXPLICIT_LEVEL</code>
58
   *      is also valid, with odd levels indicating RTL.
59
   */
60
  nsresult SetPara(const char16_t* aText, int32_t aLength,
61
                   nsBidiLevel aParaLevel)
62
  {
63
    UErrorCode error = U_ZERO_ERROR;
64
    ubidi_setPara(mBiDi, reinterpret_cast<const UChar*>(aText), aLength,
65
                  aParaLevel, nullptr, &error);
66
    return ICUUtils::UErrorToNsResult(error);
67
  }
68
69
  /**
70
   * Get the directionality of the text.
71
   *
72
   * @param aDirection receives a <code>NSBIDI_XXX</code> value that indicates
73
   *       if the entire text represented by this object is unidirectional,
74
   *       and which direction, or if it is mixed-directional.
75
   *
76
   * @see nsBidiDirection
77
   */
78
  nsBidiDirection GetDirection()
79
  {
80
    return nsBidiDirection(ubidi_getDirection(mBiDi));
81
  }
82
83
  /**
84
   * Get the paragraph level of the text.
85
   *
86
   * @param aParaLevel receives a <code>NSBIDI_XXX</code> value indicating
87
   *                   the paragraph level
88
   *
89
   * @see nsBidiLevel
90
   */
91
  nsBidiLevel GetParaLevel()
92
  {
93
    return ubidi_getParaLevel(mBiDi);
94
  }
95
96
  /**
97
   * Get a logical run.
98
   * This function returns information about a run and is used
99
   * to retrieve runs in logical order.<p>
100
   * This is especially useful for line-breaking on a paragraph.
101
   * <code>CountRuns</code> should be called before this.
102
   * before the runs are retrieved.
103
   *
104
   * @param aLogicalStart is the first character of the run.
105
   *
106
   * @param aLogicalLimit will receive the limit of the run.
107
   *      The l-value that you point to here may be the
108
   *      same expression (variable) as the one for
109
   *      <code>aLogicalStart</code>.
110
   *      This pointer cannot be <code>nullptr</code>.
111
   *
112
   * @param aLevel will receive the level of the run.
113
   *      This pointer cannot be <code>nullptr</code>.
114
   */
115
  void GetLogicalRun(int32_t aLogicalStart,
116
                     int32_t* aLogicalLimit, nsBidiLevel* aLevel);
117
118
  /**
119
   * Get the number of runs.
120
   * This function may invoke the actual reordering on the
121
   * <code>nsBidi</code> object, after <code>SetPara</code>
122
   * may have resolved only the levels of the text. Therefore,
123
   * <code>CountRuns</code> may have to allocate memory,
124
   * and may fail doing so.
125
   *
126
   * @param aRunCount will receive the number of runs.
127
   */
128
  nsresult CountRuns(int32_t* aRunCount);
129
130
  /**
131
   * Get one run's logical start, length, and directionality,
132
   * which can be 0 for LTR or 1 for RTL.
133
   * In an RTL run, the character at the logical start is
134
   * visually on the right of the displayed run.
135
   * The length is the number of characters in the run.<p>
136
   * <code>CountRuns</code> should be called
137
   * before the runs are retrieved.
138
   *
139
   * @param aRunIndex is the number of the run in visual order, in the
140
   *      range <code>[0..CountRuns-1]</code>.
141
   *
142
   * @param aLogicalStart is the first logical character index in the text.
143
   *      The pointer may be <code>nullptr</code> if this index is not needed.
144
   *
145
   * @param aLength is the number of characters (at least one) in the run.
146
   *      The pointer may be <code>nullptr</code> if this is not needed.
147
   *
148
   * @returns the directionality of the run,
149
   *       <code>NSBIDI_LTR==0</code> or <code>NSBIDI_RTL==1</code>,
150
   *       never <code>NSBIDI_MIXED</code>.
151
   *
152
   * @see CountRuns<p>
153
   *
154
   * Example:
155
   * @code
156
   *  int32_t i, count, logicalStart, visualIndex=0, length;
157
   *  nsBidiDirection dir;
158
   *  pBidi->CountRuns(&count);
159
   *  for(i=0; i<count; ++i) {
160
   *    dir = pBidi->GetVisualRun(i, &logicalStart, &length);
161
   *    if(NSBIDI_LTR==dir) {
162
   *      do { // LTR
163
   *        show_char(text[logicalStart++], visualIndex++);
164
   *      } while(--length>0);
165
   *    } else {
166
   *      logicalStart+=length;  // logicalLimit
167
   *      do { // RTL
168
   *        show_char(text[--logicalStart], visualIndex++);
169
   *      } while(--length>0);
170
   *    }
171
   *  }
172
   * @endcode
173
   *
174
   * Note that in right-to-left runs, code like this places
175
   * modifier letters before base characters and second surrogates
176
   * before first ones.
177
   */
178
  nsBidiDirection GetVisualRun(int32_t aRunIndex,
179
                               int32_t* aLogicalStart, int32_t* aLength)
180
  {
181
    return nsBidiDirection(ubidi_getVisualRun(mBiDi, aRunIndex,
182
                                              aLogicalStart, aLength));
183
  }
184
185
  /**
186
   * This is a convenience function that does not use a nsBidi object.
187
   * It is intended to be used for when an application has determined the levels
188
   * of objects (character sequences) and just needs to have them reordered (L2).
189
   * This is equivalent to using <code>GetVisualMap</code> on a
190
   * <code>nsBidi</code> object.
191
   *
192
   * @param aLevels is an array with <code>aLength</code> levels that have been
193
   *      determined by the application.
194
   *
195
   * @param aLength is the number of levels in the array, or, semantically,
196
   *      the number of objects to be reordered.
197
   *      It must be <code>aLength>0</code>.
198
   *
199
   * @param aIndexMap is a pointer to an array of <code>aLength</code>
200
   *      indexes which will reflect the reordering of the characters.
201
   *      The array does not need to be initialized.<p>
202
   *      The index map will result in
203
   *        <code>aIndexMap[aVisualIndex]==aLogicalIndex</code>.
204
   */
205
  static void ReorderVisual(const nsBidiLevel* aLevels, int32_t aLength,
206
                            int32_t* aIndexMap)
207
  {
208
    ubidi_reorderVisual(aLevels, aLength, aIndexMap);
209
  }
210
211
private:
212
  nsBidi(const nsBidi&) = delete;
213
  void operator=(const nsBidi&) = delete;
214
215
  UBiDi* mBiDi;
216
  // The two fields below are updated when CountRuns is called.
217
  const nsBidiLevel* mLevels = nullptr;
218
  int32_t mLength = 0;
219
};
220
221
#endif // _nsBidi_h_