1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
20 * Portions created by the Initial Developer are Copyright (C) 2000
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
42 #ifndef nsBidiPresUtils_h___
43 #define nsBidiPresUtils_h___
48 #include "nsBidiUtils.h"
50 #include "nsDataHashtable.h"
51 #include "nsBlockFrame.h"
52 #include "nsTHashtable.h"
59 * A structure representing some continuation state for each frame on the line,
60 * used to determine the first and the last continuation frame for each
61 * continuation chain on the line.
63 struct nsFrameContinuationState
: public nsVoidPtrHashKey
65 nsFrameContinuationState(const void *aFrame
) : nsVoidPtrHashKey(aFrame
) {}
68 * The first visual frame in the continuation chain containing this frame, or
69 * nsnull if this frame is the first visual frame in the chain.
71 nsIFrame
* mFirstVisualFrame
;
74 * The number of frames in the continuation chain containing this frame, if
75 * this frame is the first visual frame of the chain, or 0 otherwise.
80 * TRUE if this frame is the first visual frame of its continuation chain on
81 * this line and the chain has some frames on the previous lines.
83 PRPackedBool mHasContOnPrevLines
;
86 * TRUE if this frame is the first visual frame of its continuation chain on
87 * this line and the chain has some frames left for next lines.
89 PRPackedBool mHasContOnNextLines
;
93 * Following type is used to pass needed hashtable to reordering methods
95 typedef nsTHashtable
<nsFrameContinuationState
> nsContinuationStates
;
98 * A structure representing a logical position which should be resolved
99 * into its visual position during BiDi processing.
101 struct nsBidiPositionResolve
103 // [in] Logical index within string.
104 PRInt32 logicalIndex
;
105 // [out] Visual index within string.
106 // If the logical position was not found, set to kNotFound.
108 // [out] Visual position of the character, from the left (on the X axis), in twips.
109 // 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.
110 // If the logical position was not found, set to kNotFound.
111 PRInt32 visualLeftTwips
;
112 // [out] Visual width of the character, in twips.
113 // If the logical position was not found, set to kNotFound.
117 class nsBidiPresUtils
{
121 PRBool
IsSuccessful(void) const;
124 * Interface for the processor used by ProcessText. Used by process text to
125 * collect information about the width of subruns and to notify where each
126 * subrun should be rendered.
128 class BidiProcessor
{
130 virtual ~BidiProcessor() { }
133 * Sets the current text with the given length and the given direction.
135 * @remark The reason that the function gives a string instead of an index
136 * is that ProcessText copies and modifies the string passed to it, so
137 * passing an index would be impossible.
139 * @param aText The string of text.
140 * @param aLength The length of the string of text.
141 * @param aDirection The direction of the text. The string will never have
144 virtual void SetText(const PRUnichar
* aText
,
146 nsBidiDirection aDirection
) = 0;
149 * Returns the measured width of the text given in SetText. If SetText was
150 * not called with valid parameters, the result of this call is undefined.
151 * This call is guaranteed to only be called once between SetText calls.
152 * Will be invoked before DrawText.
154 virtual nscoord
GetWidth() = 0;
157 * Draws the text given in SetText to a rendering context. If SetText was
158 * not called with valid parameters, the result of this call is undefined.
159 * This call is guaranteed to only be called once between SetText calls.
161 * @param aXOffset The offset of the left side of the substring to be drawn
162 * from the beginning of the overall string passed to ProcessText.
163 * @param aWidth The width returned by GetWidth.
165 virtual void DrawText(nscoord aXOffset
,
170 * Make Bidi engine calculate the embedding levels of the frames that are
171 * descendants of a given block frame.
173 * @param aBlockFrame The block frame
177 nsresult
Resolve(nsBlockFrame
* aBlockFrame
);
180 * Reorder this line using Bidi engine.
181 * Update frame array, following the new visual sequence.
185 void ReorderFrames(nsIFrame
* aFirstFrameOnLine
,
186 PRInt32 aNumFramesOnLine
);
189 * Format Unicode text, taking into account bidi capabilities
190 * of the platform. The formatting includes: reordering, Arabic shaping,
191 * symmetric and numeric swapping, removing control characters.
195 nsresult
FormatUnicodeText(nsPresContext
* aPresContext
,
197 PRInt32
& aTextLength
,
198 nsCharType aCharType
,
202 * Reorder plain text using the Unicode Bidi algorithm and send it to
203 * a rendering context for rendering.
205 * @param[in] aText the string to be rendered (in logical order)
206 * @param aLength the number of characters in the string
207 * @param aBaseDirection the base direction of the string
208 * NSBIDI_LTR - left-to-right string
209 * NSBIDI_RTL - right-to-left string
210 * @param aPresContext the presentation context
211 * @param aRenderingContext the rendering context to render to
212 * @param aTextRunConstructionContext the rendering context to be used to construct the textrun (affects font hinting)
213 * @param aX the x-coordinate to render the string
214 * @param aY the y-coordinate to render the string
215 * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nsnull if this functionality is not required
216 * @param aPosResolveCount number of items in the aPosResolve array
218 nsresult
RenderText(const PRUnichar
* aText
,
220 nsBidiDirection aBaseDirection
,
221 nsPresContext
* aPresContext
,
222 nsIRenderingContext
& aRenderingContext
,
223 nsIRenderingContext
& aTextRunConstructionContext
,
226 nsBidiPositionResolve
* aPosResolve
= nsnull
,
227 PRInt32 aPosResolveCount
= 0)
229 return ProcessTextForRenderingContext(aText
, aLength
, aBaseDirection
, aPresContext
, aRenderingContext
,
230 aTextRunConstructionContext
, MODE_DRAW
, aX
, aY
, aPosResolve
, aPosResolveCount
, nsnull
);
233 nscoord
MeasureTextWidth(const PRUnichar
* aText
,
235 nsBidiDirection aBaseDirection
,
236 nsPresContext
* aPresContext
,
237 nsIRenderingContext
& aRenderingContext
)
240 nsresult rv
= ProcessTextForRenderingContext(aText
, aLength
, aBaseDirection
, aPresContext
,
241 aRenderingContext
, aRenderingContext
,
242 MODE_MEASURE
, 0, 0, nsnull
, 0, &length
);
243 return NS_SUCCEEDED(rv
) ? length
: 0;
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
254 PRBool
CheckLineOrder(nsIFrame
* aFirstFrameOnLine
,
255 PRInt32 aNumFramesOnLine
,
256 nsIFrame
** aLeftmost
,
257 nsIFrame
** aRightmost
);
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
266 nsIFrame
* GetFrameToRightOf(const nsIFrame
* aFrame
,
267 nsIFrame
* aFirstFrameOnLine
,
268 PRInt32 aNumFramesOnLine
);
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
277 nsIFrame
* GetFrameToLeftOf(const nsIFrame
* aFrame
,
278 nsIFrame
* aFirstFrameOnLine
,
279 PRInt32 aNumFramesOnLine
);
282 * Get the bidi embedding level of the given (inline) frame.
284 static nsBidiLevel
GetFrameEmbeddingLevel(nsIFrame
* aFrame
);
287 * Get the bidi base level of the given (inline) frame.
289 static nsBidiLevel
GetFrameBaseLevel(nsIFrame
* aFrame
);
291 enum Mode
{ MODE_DRAW
, MODE_MEASURE
};
294 * Reorder plain text using the Unicode Bidi algorithm and send it to
295 * a processor for rendering or measuring
297 * @param[in] aText the string to be processed (in logical order)
298 * @param aLength the number of characters in the string
299 * @param aBaseDirection the base direction of the string
300 * NSBIDI_LTR - left-to-right string
301 * NSBIDI_RTL - right-to-left string
302 * @param aPresContext the presentation context
303 * @param aprocessor the bidi processor
304 * @param aMode the operation to process
305 * MODE_DRAW - invokes DrawText on the processor for each substring
306 * MODE_MEASURE - does not invoke DrawText on the processor
307 * Note that the string is always measured, regardless of mode
308 * @param[in,out] aPosResolve array of logical positions to resolve into
309 * visual positions; can be nsnull if this functionality is not required
310 * @param aPosResolveCount number of items in the aPosResolve array
311 * @param[out] aWidth Pointer to where the width will be stored (may be null)
313 nsresult
ProcessText(const PRUnichar
* aText
,
315 nsBidiDirection aBaseDirection
,
316 nsPresContext
* aPresContext
,
317 BidiProcessor
& aprocessor
,
319 nsBidiPositionResolve
* aPosResolve
,
320 PRInt32 aPosResolveCount
,
324 * Make a copy of a string, converting from logical to visual order
326 * @param aSource the source string
327 * @param aDest the destination string
328 * @param aBaseDirection the base direction of the string
329 * (NSBIDI_LTR or NSBIDI_RTL to force the base direction;
330 * NSBIDI_DEFAULT_LTR or NSBIDI_DEFAULT_RTL to let the bidi engine
331 * determine the direction from rules P2 and P3 of the bidi algorithm.
332 * @see nsBidi::GetPara
333 * @param aOverride if TRUE, the text has a bidi override, according to
334 * the direction in aDir
336 void CopyLogicalToVisual(const nsAString
& aSource
,
338 nsBidiLevel aBaseDirection
,
342 * Guess at how much memory is being used by this nsBidiPresUtils instance,
343 * including memory used by nsBidi.
345 PRUint32
EstimateMemoryUsed();
347 void Traverse(nsCycleCollectionTraversalCallback
&cb
) const;
351 nsresult
ProcessTextForRenderingContext(const PRUnichar
* aText
,
353 nsBidiDirection aBaseDirection
,
354 nsPresContext
* aPresContext
,
355 nsIRenderingContext
& aRenderingContext
,
356 nsIRenderingContext
& aTextRunConstructionContext
,
358 nscoord aX
, // DRAW only
359 nscoord aY
, // DRAW only
360 nsBidiPositionResolve
* aPosResolve
, /* may be null */
361 PRInt32 aPosResolveCount
,
362 nscoord
* aWidth
/* may be null */);
365 * Create a string containing entire text content of this block.
369 void CreateBlockBuffer();
372 * Set up an array of the frames after splitting frames so that each frame has
373 * consistent directionality. At this point the frames are still in logical
376 void InitLogicalArray(nsIFrame
* aCurrentFrame
);
379 * Initialize the logically-ordered array of frames
380 * using the top-level frames of a single line
382 void InitLogicalArrayFromLine(nsIFrame
* aFirstFrameOnLine
,
383 PRInt32 aNumFramesOnLine
);
386 * Reorder the frame array from logical to visual order
388 * @param aReordered TRUE on return if the visual order is different from
390 * @param aHasRTLFrames TRUE on return if at least one of the frames is RTL
391 * (and therefore might have reordered descendents)
393 nsresult
Reorder(PRBool
& aReordered
, PRBool
& aHasRTLFrames
);
396 * Position aFrame and it's descendants to their visual places. Also if aFrame
397 * is not leaf, resize it to embrace it's children.
399 * @param aFrame The frame which itself and its children are going
401 * @param aIsOddLevel TRUE means the embedding level of this frame is odd
402 * @param[in,out] aLeft IN value is the starting position of aFrame(without
403 * considering its left margin)
404 * OUT value will be the ending position of aFrame(after
405 * adding its right margin)
406 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
408 void RepositionFrame(nsIFrame
* aFrame
,
411 nsContinuationStates
* aContinuationStates
) const;
414 * Initialize the continuation state(nsFrameContinuationState) to
415 * (nsnull, 0) for aFrame and its descendants.
417 * @param aFrame The frame which itself and its descendants will
419 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
421 void InitContinuationStates(nsIFrame
* aFrame
,
422 nsContinuationStates
* aContinuationStates
) const;
425 * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
426 * aIsRightMost values. Also set continuation states of aContinuationStates.
428 * A frame is leftmost if it's the first appearance of its continuation chain
429 * on the line and the chain is on its first line if it's LTR or the chain is
430 * on its last line if it's RTL.
431 * A frame is rightmost if it's the last appearance of its continuation chain
432 * on the line and the chain is on its first line if it's RTL or the chain is
433 * on its last line if it's LTR.
435 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
436 * @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation
437 * @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation
439 void IsLeftOrRightMost(nsIFrame
* aFrame
,
440 nsContinuationStates
* aContinuationStates
,
441 PRBool
& aIsLeftMost
/* out */,
442 PRBool
& aIsRightMost
/* out */) const;
445 * Adjust frame positions following their visual order
447 * @param aFirstChild the first kid
451 void RepositionInlineFrames(nsIFrame
* aFirstChild
) const;
454 * Helper method for Resolve()
455 * Truncate a text frame to the end of a single-directional run and possibly
456 * create a continuation frame for the remainder of its content.
458 * @param aFrame the original frame
459 * @param aNewFrame [OUT] the new frame that was created
460 * @param aFrameIndex [IN/OUT] index of aFrame in mLogicalFrames
461 * @param aStart [IN] the start of the content mapped by aFrame (and
462 * any fluid continuations)
463 * @param aEnd [IN] the offset of the end of the single-directional
466 * @see RemoveBidiContinuation()
469 void EnsureBidiContinuation(nsIFrame
* aFrame
,
470 nsIFrame
** aNewFrame
,
471 PRInt32
& aFrameIndex
,
476 * Helper method for Resolve()
477 * Convert one or more bidi continuation frames created in a previous reflow by
478 * EnsureBidiContinuation() into fluid continuations.
479 * @param aFrame the frame whose continuations are to be removed
480 * @param aFirstIndex index of aFrame in mLogicalFrames
481 * @param aLastIndex index of the last frame to be removed
482 * @param aOffset [OUT] count of directional frames removed. Since
483 * directional frames have control characters
484 * corresponding to them in mBuffer, the pointers to
485 * mBuffer in Resolve() will need to be updated after
486 * deleting the frames.
489 * @see EnsureBidiContinuation()
491 void RemoveBidiContinuation(nsIFrame
* aFrame
,
494 PRInt32
& aOffset
) const;
495 void CalculateCharType(PRInt32
& aOffset
,
496 PRInt32 aCharTypeLimit
,
501 PRUint8
& aPrevCharType
) const;
503 void StripBidiControlCharacters(PRUnichar
* aText
,
504 PRInt32
& aTextLength
) const;
506 static PRBool
WriteLogicalToVisual(const PRUnichar
* aSrc
,
509 nsBidiLevel aBaseDirection
,
510 nsBidi
* aBidiEngine
);
512 static void WriteReverse(const PRUnichar
* aSrc
,
516 nsAutoString mBuffer
;
517 nsTArray
<nsIFrame
*> mLogicalFrames
;
518 nsTArray
<nsIFrame
*> mVisualFrames
;
519 nsDataHashtable
<nsISupportsHashKey
, PRInt32
> mContentToFrameIndex
;
528 #endif /* nsBidiPresUtils_h___ */