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___
45 #include "nsVoidArray.h"
48 #include "nsBidiUtils.h"
50 #include "nsDataHashtable.h"
51 #include "nsBlockFrame.h"
52 #include "nsTHashtable.h"
55 * A structure representing some continuation state for each frame on the line,
56 * used to determine the first and the last continuation frame for each
57 * continuation chain on the line.
59 struct nsFrameContinuationState
: public nsVoidPtrHashKey
61 nsFrameContinuationState(const void *aFrame
) : nsVoidPtrHashKey(aFrame
) {}
64 * The first visual frame in the continuation chain containing this frame, or
65 * nsnull if this frame is the first visual frame in the chain.
67 nsIFrame
* mFirstVisualFrame
;
70 * The number of frames in the continuation chain containing this frame, if
71 * this frame is the first visual frame of the chain, or 0 otherwise.
76 * TRUE if this frame is the first visual frame of its continuation chain on
77 * this line and the chain has some frames on the previous lines.
79 PRPackedBool mHasContOnPrevLines
;
82 * TRUE if this frame is the first visual frame of its continuation chain on
83 * this line and the chain has some frames left for next lines.
85 PRPackedBool mHasContOnNextLines
;
89 * Following type is used to pass needed hashtable to reordering methods
91 typedef nsTHashtable
<nsFrameContinuationState
> nsContinuationStates
;
94 * A structure representing a logical position which should be resolved
95 * into its visual position during BiDi processing.
97 struct nsBidiPositionResolve
99 // [in] Logical index within string.
100 PRInt32 logicalIndex
;
101 // [out] Visual index within string.
102 // If the logical position was not found, set to kNotFound.
104 // [out] Visual position of the character, from the left (on the X axis), in twips.
105 // 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.
106 // If the logical position was not found, set to kNotFound.
107 PRInt32 visualLeftTwips
;
110 class nsBidiPresUtils
{
114 PRBool
IsSuccessful(void) const;
117 * Interface for the processor used by ProcessText. Used by process text to
118 * collect information about the width of subruns and to notify where each
119 * subrun should be rendered.
121 class BidiProcessor
{
123 virtual ~BidiProcessor() { }
126 * Sets the current text with the given length and the given direction.
128 * @remark The reason that the function gives a string instead of an index
129 * is that ProcessText copies and modifies the string passed to it, so
130 * passing an index would be impossible.
132 * @param aText The string of text.
133 * @param aLength The length of the string of text.
134 * @param aDirection The direction of the text. The string will never have
137 virtual void SetText(const PRUnichar
* aText
,
139 nsBidiDirection aDirection
) = 0;
142 * Returns the measured width of the text given in SetText. If SetText was
143 * not called with valid parameters, the result of this call is undefined.
144 * This call is guaranteed to only be called once between SetText calls.
145 * Will be invoked before DrawText.
147 virtual nscoord
GetWidth() = 0;
150 * Draws the text given in SetText to a rendering context. If SetText was
151 * not called with valid parameters, the result of this call is undefined.
152 * This call is guaranteed to only be called once between SetText calls.
154 * @param aXOffset The offset of the left side of the substring to be drawn
155 * from the beginning of the overall string passed to ProcessText.
156 * @param aWidth The width returned by GetWidth.
158 virtual void DrawText(nscoord aXOffset
,
163 * Make Bidi engine calculate the embedding levels of the frames that are
164 * descendants of a given block frame.
166 * @param aBlockFrame The block frame
167 * @param aIsVisualFormControl [IN] Set if we are in a form control on a
169 * @see nsBlockFrame::IsVisualFormControl
173 nsresult
Resolve(nsBlockFrame
* aBlockFrame
,
174 PRBool aIsVisualFormControl
);
177 * Reorder this line using Bidi engine.
178 * Update frame array, following the new visual sequence.
182 void ReorderFrames(nsIFrame
* aFirstFrameOnLine
,
183 PRInt32 aNumFramesOnLine
);
186 * Format Unicode text, taking into account bidi capabilities
187 * of the platform. The formatting includes: reordering, Arabic shaping,
188 * symmetric and numeric swapping, removing control characters.
192 nsresult
FormatUnicodeText(nsPresContext
* aPresContext
,
194 PRInt32
& aTextLength
,
195 nsCharType aCharType
,
199 * Return our nsBidi object (bidi reordering engine)
201 nsresult
GetBidiEngine(nsBidi
** aBidiEngine
);
204 * Reorder plain text using the Unicode Bidi algorithm and send it to
205 * a rendering context for rendering.
207 * @param[in] aText the string to be rendered (in logical order)
208 * @param aLength the number of characters in the string
209 * @param aBaseDirection the base direction of the string
210 * NSBIDI_LTR - left-to-right string
211 * NSBIDI_RTL - right-to-left string
212 * @param aPresContext the presentation context
213 * @param aRenderingContext the rendering context
214 * @param aX the x-coordinate to render the string
215 * @param aY the y-coordinate to render the string
216 * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nsnull if this functionality is not required
217 * @param aPosResolveCount number of items in the aPosResolve array
219 nsresult
RenderText(const PRUnichar
* aText
,
221 nsBidiDirection aBaseDirection
,
222 nsPresContext
* aPresContext
,
223 nsIRenderingContext
& aRenderingContext
,
226 nsBidiPositionResolve
* aPosResolve
= nsnull
,
227 PRInt32 aPosResolveCount
= 0)
229 return ProcessTextForRenderingContext(aText
, aLength
, aBaseDirection
, aPresContext
, aRenderingContext
,
230 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
, aRenderingContext
,
241 MODE_MEASURE
, 0, 0, nsnull
, 0, &length
);
242 return NS_SUCCEEDED(rv
) ? length
: 0;
246 * Check if a line is reordered, i.e., if the child frames are not
247 * all laid out left-to-right.
248 * @param aFirstFrameOnLine : first frame of the line to be tested
249 * @param aNumFramesOnLine : number of frames on this line
250 * @param[out] aLeftMost : leftmost frame on this line
251 * @param[out] aRightMost : rightmost frame on this line
253 PRBool
CheckLineOrder(nsIFrame
* aFirstFrameOnLine
,
254 PRInt32 aNumFramesOnLine
,
255 nsIFrame
** aLeftmost
,
256 nsIFrame
** aRightmost
);
259 * Get the frame to the right of the given frame, on the same line.
260 * @param aFrame : We're looking for the frame to the right of this frame.
261 * If null, return the leftmost frame on the line.
262 * @param aFirstFrameOnLine : first frame of the line to be tested
263 * @param aNumFramesOnLine : number of frames on this line
265 nsIFrame
* GetFrameToRightOf(const nsIFrame
* aFrame
,
266 nsIFrame
* aFirstFrameOnLine
,
267 PRInt32 aNumFramesOnLine
);
270 * Get the frame to the left of the given frame, on the same line.
271 * @param aFrame : We're looking for the frame to the left of this frame.
272 * If null, return the rightmost frame on the line.
273 * @param aFirstFrameOnLine : first frame of the line to be tested
274 * @param aNumFramesOnLine : number of frames on this line
276 nsIFrame
* GetFrameToLeftOf(const nsIFrame
* aFrame
,
277 nsIFrame
* aFirstFrameOnLine
,
278 PRInt32 aNumFramesOnLine
);
281 * Get the bidi embedding level of the given (inline) frame.
283 static nsBidiLevel
GetFrameEmbeddingLevel(nsIFrame
* aFrame
);
286 * Get the bidi base level of the given (inline) frame.
288 static nsBidiLevel
GetFrameBaseLevel(nsIFrame
* aFrame
);
290 enum Mode
{ MODE_DRAW
, MODE_MEASURE
};
293 * Reorder plain text using the Unicode Bidi algorithm and send it to
294 * a processor for rendering or measuring
296 * @param[in] aText the string to be processed (in logical order)
297 * @param aLength the number of characters in the string
298 * @param aBaseDirection the base direction of the string
299 * NSBIDI_LTR - left-to-right string
300 * NSBIDI_RTL - right-to-left string
301 * @param aPresContext the presentation context
302 * @param aprocessor the bidi processor
303 * @param aMode the operation to process
304 * MODE_DRAW - invokes DrawText on the processor for each substring
305 * MODE_MEASURE - does not invoke DrawText on the processor
306 * Note that the string is always measured, regardless of mode
307 * @param[in,out] aPosResolve array of logical positions to resolve into
308 * visual positions; can be nsnull if this functionality is not required
309 * @param aPosResolveCount number of items in the aPosResolve array
310 * @param[out] aWidth Pointer to where the width will be stored (may be null)
312 nsresult
ProcessText(const PRUnichar
* aText
,
314 nsBidiDirection aBaseDirection
,
315 nsPresContext
* aPresContext
,
316 BidiProcessor
& aprocessor
,
318 nsBidiPositionResolve
* aPosResolve
,
319 PRInt32 aPosResolveCount
,
323 nsresult
ProcessTextForRenderingContext(const PRUnichar
* aText
,
325 nsBidiDirection aBaseDirection
,
326 nsPresContext
* aPresContext
,
327 nsIRenderingContext
& aRenderingContext
,
329 nscoord aX
, // DRAW only
330 nscoord aY
, // DRAW only
331 nsBidiPositionResolve
* aPosResolve
, /* may be null */
332 PRInt32 aPosResolveCount
,
333 nscoord
* aWidth
/* may be null */);
336 * Create a string containing entire text content of this block.
340 void CreateBlockBuffer();
343 * Set up an array of the frames after splitting frames so that each frame has
344 * consistent directionality. At this point the frames are still in logical
347 void InitLogicalArray(nsIFrame
* aCurrentFrame
);
350 * Initialize the logically-ordered array of frames
351 * using the top-level frames of a single line
353 void InitLogicalArrayFromLine(nsIFrame
* aFirstFrameOnLine
,
354 PRInt32 aNumFramesOnLine
);
357 * Reorder the frame array from logical to visual order
359 * @param aReordered TRUE on return if the visual order is different from
361 * @param aHasRTLFrames TRUE on return if at least one of the frames is RTL
362 * (and therefore might have reordered descendents)
364 nsresult
Reorder(PRBool
& aReordered
, PRBool
& aHasRTLFrames
);
367 * Position aFrame and it's descendants to their visual places. Also if aFrame
368 * is not leaf, resize it to embrace it's children.
370 * @param aFrame The frame which itself and its children are going
372 * @param aIsOddLevel TRUE means the embedding level of this frame is odd
373 * @param[in,out] aLeft IN value is the starting position of aFrame(without
374 * considering its left margin)
375 * OUT value will be the ending position of aFrame(after
376 * adding its right margin)
377 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
379 void RepositionFrame(nsIFrame
* aFrame
,
382 nsContinuationStates
* aContinuationStates
) const;
385 * Initialize the continuation state(nsFrameContinuationState) to
386 * (nsnull, 0) for aFrame and its descendants.
388 * @param aFrame The frame which itself and its descendants will
390 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
392 void InitContinuationStates(nsIFrame
* aFrame
,
393 nsContinuationStates
* aContinuationStates
) const;
396 * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
397 * aIsRightMost values. Also set continuation states of aContinuationStates.
399 * A frame is leftmost if it's the first appearance of its continuation chain
400 * on the line and the chain is on its first line if it's LTR or the chain is
401 * on its last line if it's RTL.
402 * A frame is rightmost if it's the last appearance of its continuation chain
403 * on the line and the chain is on its first line if it's RTL or the chain is
404 * on its last line if it's LTR.
406 * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
407 * @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation
408 * @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation
410 void IsLeftOrRightMost(nsIFrame
* aFrame
,
411 nsContinuationStates
* aContinuationStates
,
412 PRBool
& aIsLeftMost
/* out */,
413 PRBool
& aIsRightMost
/* out */) const;
416 * Adjust frame positions following their visual order
418 * @param aFirstChild the first kid
422 void RepositionInlineFrames(nsIFrame
* aFirstChild
) const;
425 * Helper method for Resolve()
426 * Truncate a text frame to the end of a single-directional run and possibly
427 * create a continuation frame for the remainder of its content.
429 * @param aFrame the original frame
430 * @param aNewFrame [OUT] the new frame that was created
431 * @param aFrameIndex [IN/OUT] index of aFrame in mLogicalFrames
432 * @param aStart [IN] the start of the content mapped by aFrame (and
433 * any fluid continuations)
434 * @param aEnd [IN] the offset of the end of the single-directional
436 * @param aLineNeedsUpdate [OUT] set to true if we're re-using a frame (which
437 * might be on another line).
439 * If there is already a bidi continuation for this frame in mLogicalFrames,
440 * no new frame will be created. On exit aNewFrame will point to the existing
441 * bidi continuation and aFrameIndex will contain its index.
443 * If aFrame has fluid continuations (which can happen when re-resolving
444 * after line breaking) all the frames in the continuation chain except for
445 * the last one will be set to zero length and the last one will be truncated
448 * aFrame must always be a first-in-flow.
451 * @see RemoveBidiContinuation()
453 PRBool
EnsureBidiContinuation(nsIFrame
* aFrame
,
454 nsIFrame
** aNewFrame
,
455 PRInt32
& aFrameIndex
,
458 PRBool
& aLineNeedsUpdate
);
461 * Helper method for Resolve()
462 * Convert one or more bidi continuation frames created in a previous reflow by
463 * EnsureBidiContinuation() into fluid continuations.
464 * @param aFrame the frame whose continuations are to be removed
465 * @param aFirstIndex index of aFrame in mLogicalFrames
466 * @param aLastIndex index of the last frame to be removed
467 * @param aOffset [OUT] count of directional frames removed. Since
468 * directional frames have control characters
469 * corresponding to them in mBuffer, the pointers to
470 * mBuffer in Resolve() will need to be updated after
471 * deleting the frames.
474 * @see EnsureBidiContinuation()
476 void RemoveBidiContinuation(nsIFrame
* aFrame
,
479 PRInt32
& aOffset
) const;
480 void CalculateCharType(PRInt32
& aOffset
,
481 PRInt32 aCharTypeLimit
,
486 PRUint8
& aPrevCharType
) const;
488 void StripBidiControlCharacters(PRUnichar
* aText
,
489 PRInt32
& aTextLength
) const;
490 nsAutoString mBuffer
;
491 nsVoidArray mLogicalFrames
;
492 nsVoidArray mVisualFrames
;
493 nsDataHashtable
<nsISupportsHashKey
, PRInt32
> mContentToFrameIndex
;
502 #endif /* nsBidiPresUtils_h___ */