1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * IBM Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2000
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * IBM Corporation
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifdef IBMBIDI
41 :
42 : #ifndef nsBidiPresUtils_h___
43 : #define nsBidiPresUtils_h___
44 :
45 : #include "nsTArray.h"
46 : #include "nsIFrame.h"
47 : #include "nsBidi.h"
48 : #include "nsBidiUtils.h"
49 : #include "nsCOMPtr.h"
50 : #include "nsDataHashtable.h"
51 : #include "nsBlockFrame.h"
52 : #include "nsTHashtable.h"
53 :
54 : #ifdef DrawText
55 : #undef DrawText
56 : #endif
57 :
58 : struct BidiParagraphData;
59 : struct BidiLineData;
60 :
61 : /**
62 : * A structure representing some continuation state for each frame on the line,
63 : * used to determine the first and the last continuation frame for each
64 : * continuation chain on the line.
65 : */
66 : struct nsFrameContinuationState : public nsVoidPtrHashKey
67 : {
68 : nsFrameContinuationState(const void *aFrame) : nsVoidPtrHashKey(aFrame) {}
69 :
70 : /**
71 : * The first visual frame in the continuation chain containing this frame, or
72 : * nsnull if this frame is the first visual frame in the chain.
73 : */
74 : nsIFrame* mFirstVisualFrame;
75 :
76 : /**
77 : * The number of frames in the continuation chain containing this frame, if
78 : * this frame is the first visual frame of the chain, or 0 otherwise.
79 : */
80 : PRUint32 mFrameCount;
81 :
82 : /**
83 : * TRUE if this frame is the first visual frame of its continuation chain on
84 : * this line and the chain has some frames on the previous lines.
85 : */
86 : bool mHasContOnPrevLines;
87 :
88 : /**
89 : * TRUE if this frame is the first visual frame of its continuation chain on
90 : * this line and the chain has some frames left for next lines.
91 : */
92 : bool mHasContOnNextLines;
93 : };
94 :
95 : /*
96 : * Following type is used to pass needed hashtable to reordering methods
97 : */
98 : typedef nsTHashtable<nsFrameContinuationState> nsContinuationStates;
99 :
100 : /**
101 : * A structure representing a logical position which should be resolved
102 : * into its visual position during BiDi processing.
103 : */
104 : struct nsBidiPositionResolve
105 : {
106 : // [in] Logical index within string.
107 : PRInt32 logicalIndex;
108 : // [out] Visual index within string.
109 : // If the logical position was not found, set to kNotFound.
110 : PRInt32 visualIndex;
111 : // [out] Visual position of the character, from the left (on the X axis), in twips.
112 : // 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.
113 : // If the logical position was not found, set to kNotFound.
114 : PRInt32 visualLeftTwips;
115 : // [out] Visual width of the character, in twips.
116 : // If the logical position was not found, set to kNotFound.
117 : PRInt32 visualWidth;
118 : };
119 :
120 : class nsBidiPresUtils {
121 : public:
122 : nsBidiPresUtils();
123 : ~nsBidiPresUtils();
124 :
125 : /**
126 : * Interface for the processor used by ProcessText. Used by process text to
127 : * collect information about the width of subruns and to notify where each
128 : * subrun should be rendered.
129 : */
130 0 : class BidiProcessor {
131 : public:
132 0 : virtual ~BidiProcessor() { }
133 :
134 : /**
135 : * Sets the current text with the given length and the given direction.
136 : *
137 : * @remark The reason that the function gives a string instead of an index
138 : * is that ProcessText copies and modifies the string passed to it, so
139 : * passing an index would be impossible.
140 : *
141 : * @param aText The string of text.
142 : * @param aLength The length of the string of text.
143 : * @param aDirection The direction of the text. The string will never have
144 : * mixed direction.
145 : */
146 : virtual void SetText(const PRUnichar* aText,
147 : PRInt32 aLength,
148 : nsBidiDirection aDirection) = 0;
149 :
150 : /**
151 : * Returns the measured width of the text given in SetText. If SetText was
152 : * not called with valid parameters, the result of this call is undefined.
153 : * This call is guaranteed to only be called once between SetText calls.
154 : * Will be invoked before DrawText.
155 : */
156 : virtual nscoord GetWidth() = 0;
157 :
158 : /**
159 : * Draws the text given in SetText to a rendering context. If SetText was
160 : * not called with valid parameters, the result of this call is undefined.
161 : * This call is guaranteed to only be called once between SetText calls.
162 : *
163 : * @param aXOffset The offset of the left side of the substring to be drawn
164 : * from the beginning of the overall string passed to ProcessText.
165 : * @param aWidth The width returned by GetWidth.
166 : */
167 : virtual void DrawText(nscoord aXOffset,
168 : nscoord aWidth) = 0;
169 : };
170 :
171 : /**
172 : * Make Bidi engine calculate the embedding levels of the frames that are
173 : * descendants of a given block frame.
174 : *
175 : * @param aBlockFrame The block frame
176 : *
177 : * @lina 06/18/2000
178 : */
179 : static nsresult Resolve(nsBlockFrame* aBlockFrame);
180 : static nsresult ResolveParagraph(nsBlockFrame* aBlockFrame,
181 : BidiParagraphData* aBpd);
182 : static void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
183 : BidiParagraphData* aBpd);
184 :
185 : /**
186 : * Reorder this line using Bidi engine.
187 : * Update frame array, following the new visual sequence.
188 : *
189 : * @lina 05/02/2000
190 : */
191 : static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
192 : PRInt32 aNumFramesOnLine);
193 :
194 : /**
195 : * Format Unicode text, taking into account bidi capabilities
196 : * of the platform. The formatting includes: reordering, Arabic shaping,
197 : * symmetric and numeric swapping, removing control characters.
198 : *
199 : * @lina 06/18/2000
200 : */
201 : static nsresult FormatUnicodeText(nsPresContext* aPresContext,
202 : PRUnichar* aText,
203 : PRInt32& aTextLength,
204 : nsCharType aCharType,
205 : bool aIsOddLevel);
206 :
207 : /**
208 : * Reorder plain text using the Unicode Bidi algorithm and send it to
209 : * a rendering context for rendering.
210 : *
211 : * @param[in] aText the string to be rendered (in logical order)
212 : * @param aLength the number of characters in the string
213 : * @param aBaseDirection the base direction of the string
214 : * NSBIDI_LTR - left-to-right string
215 : * NSBIDI_RTL - right-to-left string
216 : * @param aPresContext the presentation context
217 : * @param aRenderingContext the rendering context to render to
218 : * @param aTextRunConstructionContext the rendering context to be used to construct the textrun (affects font hinting)
219 : * @param aX the x-coordinate to render the string
220 : * @param aY the y-coordinate to render the string
221 : * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nsnull if this functionality is not required
222 : * @param aPosResolveCount number of items in the aPosResolve array
223 : */
224 : static nsresult RenderText(const PRUnichar* aText,
225 : PRInt32 aLength,
226 : nsBidiDirection aBaseDirection,
227 : nsPresContext* aPresContext,
228 : nsRenderingContext& aRenderingContext,
229 : nsRenderingContext& aTextRunConstructionContext,
230 : nscoord aX,
231 : nscoord aY,
232 : nsBidiPositionResolve* aPosResolve = nsnull,
233 : PRInt32 aPosResolveCount = 0)
234 : {
235 : return ProcessTextForRenderingContext(aText, aLength, aBaseDirection, aPresContext, aRenderingContext,
236 : aTextRunConstructionContext, MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nsnull);
237 : }
238 :
239 : static nscoord MeasureTextWidth(const PRUnichar* aText,
240 : PRInt32 aLength,
241 : nsBidiDirection aBaseDirection,
242 : nsPresContext* aPresContext,
243 : nsRenderingContext& aRenderingContext)
244 : {
245 : nscoord length;
246 : nsresult rv = ProcessTextForRenderingContext(aText, aLength, aBaseDirection, aPresContext,
247 : aRenderingContext, aRenderingContext,
248 : MODE_MEASURE, 0, 0, nsnull, 0, &length);
249 : return NS_SUCCEEDED(rv) ? length : 0;
250 : }
251 :
252 : /**
253 : * Check if a line is reordered, i.e., if the child frames are not
254 : * all laid out left-to-right.
255 : * @param aFirstFrameOnLine : first frame of the line to be tested
256 : * @param aNumFramesOnLine : number of frames on this line
257 : * @param[out] aLeftMost : leftmost frame on this line
258 : * @param[out] aRightMost : rightmost frame on this line
259 : */
260 : static bool CheckLineOrder(nsIFrame* aFirstFrameOnLine,
261 : PRInt32 aNumFramesOnLine,
262 : nsIFrame** aLeftmost,
263 : nsIFrame** aRightmost);
264 :
265 : /**
266 : * Get the frame to the right of the given frame, on the same line.
267 : * @param aFrame : We're looking for the frame to the right of this frame.
268 : * If null, return the leftmost frame on the line.
269 : * @param aFirstFrameOnLine : first frame of the line to be tested
270 : * @param aNumFramesOnLine : number of frames on this line
271 : */
272 : static nsIFrame* GetFrameToRightOf(const nsIFrame* aFrame,
273 : nsIFrame* aFirstFrameOnLine,
274 : PRInt32 aNumFramesOnLine);
275 :
276 : /**
277 : * Get the frame to the left of the given frame, on the same line.
278 : * @param aFrame : We're looking for the frame to the left of this frame.
279 : * If null, return the rightmost frame on the line.
280 : * @param aFirstFrameOnLine : first frame of the line to be tested
281 : * @param aNumFramesOnLine : number of frames on this line
282 : */
283 : static nsIFrame* GetFrameToLeftOf(const nsIFrame* aFrame,
284 : nsIFrame* aFirstFrameOnLine,
285 : PRInt32 aNumFramesOnLine);
286 :
287 : /**
288 : * Get the bidi embedding level of the given (inline) frame.
289 : */
290 : static nsBidiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame);
291 :
292 : /**
293 : * Get the bidi base level of the given (inline) frame.
294 : */
295 : static nsBidiLevel GetFrameBaseLevel(nsIFrame* aFrame);
296 :
297 : enum Mode { MODE_DRAW, MODE_MEASURE };
298 :
299 : /**
300 : * Reorder plain text using the Unicode Bidi algorithm and send it to
301 : * a processor for rendering or measuring
302 : *
303 : * @param[in] aText the string to be processed (in logical order)
304 : * @param aLength the number of characters in the string
305 : * @param aBaseDirection the base direction of the string
306 : * NSBIDI_LTR - left-to-right string
307 : * NSBIDI_RTL - right-to-left string
308 : * @param aPresContext the presentation context
309 : * @param aprocessor the bidi processor
310 : * @param aMode the operation to process
311 : * MODE_DRAW - invokes DrawText on the processor for each substring
312 : * MODE_MEASURE - does not invoke DrawText on the processor
313 : * Note that the string is always measured, regardless of mode
314 : * @param[in,out] aPosResolve array of logical positions to resolve into
315 : * visual positions; can be nsnull if this functionality is not required
316 : * @param aPosResolveCount number of items in the aPosResolve array
317 : * @param[out] aWidth Pointer to where the width will be stored (may be null)
318 : */
319 : static nsresult ProcessText(const PRUnichar* aText,
320 : PRInt32 aLength,
321 : nsBidiDirection aBaseDirection,
322 : nsPresContext* aPresContext,
323 : BidiProcessor& aprocessor,
324 : Mode aMode,
325 : nsBidiPositionResolve* aPosResolve,
326 : PRInt32 aPosResolveCount,
327 : nscoord* aWidth,
328 : nsBidi* aBidiEngine);
329 :
330 : /**
331 : * Make a copy of a string, converting from logical to visual order
332 : *
333 : * @param aSource the source string
334 : * @param aDest the destination string
335 : * @param aBaseDirection the base direction of the string
336 : * (NSBIDI_LTR or NSBIDI_RTL to force the base direction;
337 : * NSBIDI_DEFAULT_LTR or NSBIDI_DEFAULT_RTL to let the bidi engine
338 : * determine the direction from rules P2 and P3 of the bidi algorithm.
339 : * @see nsBidi::GetPara
340 : * @param aOverride if TRUE, the text has a bidi override, according to
341 : * the direction in aDir
342 : */
343 : static void CopyLogicalToVisual(const nsAString& aSource,
344 : nsAString& aDest,
345 : nsBidiLevel aBaseDirection,
346 : bool aOverride);
347 :
348 : private:
349 : static nsresult
350 : ProcessTextForRenderingContext(const PRUnichar* aText,
351 : PRInt32 aLength,
352 : nsBidiDirection aBaseDirection,
353 : nsPresContext* aPresContext,
354 : nsRenderingContext& aRenderingContext,
355 : nsRenderingContext& aTextRunConstructionContext,
356 : Mode aMode,
357 : nscoord aX, // DRAW only
358 : nscoord aY, // DRAW only
359 : nsBidiPositionResolve* aPosResolve, /* may be null */
360 : PRInt32 aPosResolveCount,
361 : nscoord* aWidth /* may be null */);
362 :
363 : /**
364 : * Traverse the child frames of the block element and:
365 : * Set up an array of the frames in logical order
366 : * Create a string containing the text content of all the frames
367 : * If we encounter content that requires us to split the element into more
368 : * than one paragraph for bidi resolution, resolve the paragraph up to that
369 : * point.
370 : */
371 : static void TraverseFrames(nsBlockFrame* aBlockFrame,
372 : nsBlockInFlowLineIterator* aLineIter,
373 : nsIFrame* aCurrentFrame,
374 : BidiParagraphData* aBpd);
375 :
376 : /*
377 : * Position aFrame and it's descendants to their visual places. Also if aFrame
378 : * is not leaf, resize it to embrace it's children.
379 : *
380 : * @param aFrame The frame which itself and its children are going
381 : * to be repositioned
382 : * @param aIsOddLevel TRUE means the embedding level of this frame is odd
383 : * @param[in,out] aLeft IN value is the starting position of aFrame(without
384 : * considering its left margin)
385 : * OUT value will be the ending position of aFrame(after
386 : * adding its right margin)
387 : * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
388 : */
389 : static void RepositionFrame(nsIFrame* aFrame,
390 : bool aIsOddLevel,
391 : nscoord& aLeft,
392 : nsContinuationStates* aContinuationStates);
393 :
394 : /*
395 : * Initialize the continuation state(nsFrameContinuationState) to
396 : * (nsnull, 0) for aFrame and its descendants.
397 : *
398 : * @param aFrame The frame which itself and its descendants will
399 : * be initialized
400 : * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
401 : */
402 : static void InitContinuationStates(nsIFrame* aFrame,
403 : nsContinuationStates* aContinuationStates);
404 :
405 : /*
406 : * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and
407 : * aIsRightMost values. Also set continuation states of aContinuationStates.
408 : *
409 : * A frame is leftmost if it's the first appearance of its continuation chain
410 : * on the line and the chain is on its first line if it's LTR or the chain is
411 : * on its last line if it's RTL.
412 : * A frame is rightmost if it's the last appearance of its continuation chain
413 : * on the line and the chain is on its first line if it's RTL or the chain is
414 : * on its last line if it's LTR.
415 : *
416 : * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState
417 : * @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation
418 : * @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation
419 : */
420 : static void IsLeftOrRightMost(nsIFrame* aFrame,
421 : nsContinuationStates* aContinuationStates,
422 : bool& aIsLeftMost /* out */,
423 : bool& aIsRightMost /* out */);
424 :
425 : /**
426 : * Adjust frame positions following their visual order
427 : *
428 : * @param aFirstChild the first kid
429 : *
430 : * @lina 04/11/2000
431 : */
432 : static void RepositionInlineFrames(BidiLineData* aBld,
433 : nsIFrame* aFirstChild);
434 :
435 : /**
436 : * Helper method for Resolve()
437 : * Truncate a text frame to the end of a single-directional run and possibly
438 : * create a continuation frame for the remainder of its content.
439 : *
440 : * @param aFrame the original frame
441 : * @param aNewFrame [OUT] the new frame that was created
442 : * @param aFrameIndex [IN/OUT] index of aFrame in mLogicalFrames
443 : * @param aStart [IN] the start of the content mapped by aFrame (and
444 : * any fluid continuations)
445 : * @param aEnd [IN] the offset of the end of the single-directional
446 : * text run.
447 : * @see Resolve()
448 : * @see RemoveBidiContinuation()
449 : */
450 : static inline
451 : nsresult EnsureBidiContinuation(nsIFrame* aFrame,
452 : nsIFrame** aNewFrame,
453 : PRInt32& aFrameIndex,
454 : PRInt32 aStart,
455 : PRInt32 aEnd);
456 :
457 : /**
458 : * Helper method for Resolve()
459 : * Convert one or more bidi continuation frames created in a previous reflow by
460 : * EnsureBidiContinuation() into fluid continuations.
461 : * @param aFrame the frame whose continuations are to be removed
462 : * @param aFirstIndex index of aFrame in mLogicalFrames
463 : * @param aLastIndex index of the last frame to be removed
464 : * @param aOffset [OUT] count of directional frames removed. Since
465 : * directional frames have control characters
466 : * corresponding to them in mBuffer, the pointers to
467 : * mBuffer in Resolve() will need to be updated after
468 : * deleting the frames.
469 : *
470 : * @see Resolve()
471 : * @see EnsureBidiContinuation()
472 : */
473 : static void RemoveBidiContinuation(BidiParagraphData* aBpd,
474 : nsIFrame* aFrame,
475 : PRInt32 aFirstIndex,
476 : PRInt32 aLastIndex,
477 : PRInt32& aOffset);
478 : static void CalculateCharType(nsBidi* aBidiEngine,
479 : const PRUnichar* aText,
480 : PRInt32& aOffset,
481 : PRInt32 aCharTypeLimit,
482 : PRInt32& aRunLimit,
483 : PRInt32& aRunLength,
484 : PRInt32& aRunCount,
485 : PRUint8& aCharType,
486 : PRUint8& aPrevCharType);
487 :
488 : static void StripBidiControlCharacters(PRUnichar* aText,
489 : PRInt32& aTextLength);
490 :
491 : static bool WriteLogicalToVisual(const PRUnichar* aSrc,
492 : PRUint32 aSrcLength,
493 : PRUnichar* aDest,
494 : nsBidiLevel aBaseDirection,
495 : nsBidi* aBidiEngine);
496 :
497 : static void WriteReverse(const PRUnichar* aSrc,
498 : PRUint32 aSrcLength,
499 : PRUnichar* aDest);
500 : };
501 :
502 : #endif /* nsBidiPresUtils_h___ */
503 :
504 : #endif // IBMBIDI
|