Coverage Report

Created: 2018-09-25 14:53

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