1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsBidiPresUtils.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,513 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef nsBidiPresUtils_h___ 1.11 +#define nsBidiPresUtils_h___ 1.12 + 1.13 +#include "nsBidi.h" 1.14 +#include "nsBidiUtils.h" 1.15 +#include "nsHashKeys.h" 1.16 +#include "nsCoord.h" 1.17 + 1.18 +#ifdef DrawText 1.19 +#undef DrawText 1.20 +#endif 1.21 + 1.22 +struct BidiParagraphData; 1.23 +struct BidiLineData; 1.24 +class nsIFrame; 1.25 +class nsBlockFrame; 1.26 +class nsPresContext; 1.27 +class nsRenderingContext; 1.28 +class nsBlockInFlowLineIterator; 1.29 +class nsStyleContext; 1.30 +template<class T> class nsTHashtable; 1.31 +namespace mozilla { class WritingMode; } 1.32 + 1.33 +/** 1.34 + * A structure representing some continuation state for each frame on the line, 1.35 + * used to determine the first and the last continuation frame for each 1.36 + * continuation chain on the line. 1.37 + */ 1.38 +struct nsFrameContinuationState : public nsVoidPtrHashKey 1.39 +{ 1.40 + nsFrameContinuationState(const void *aFrame) : nsVoidPtrHashKey(aFrame) {} 1.41 + 1.42 + /** 1.43 + * The first visual frame in the continuation chain containing this frame, or 1.44 + * nullptr if this frame is the first visual frame in the chain. 1.45 + */ 1.46 + nsIFrame* mFirstVisualFrame; 1.47 + 1.48 + /** 1.49 + * The number of frames in the continuation chain containing this frame, if 1.50 + * this frame is the first visual frame of the chain, or 0 otherwise. 1.51 + */ 1.52 + uint32_t mFrameCount; 1.53 + 1.54 + /** 1.55 + * TRUE if this frame is the first visual frame of its continuation chain on 1.56 + * this line and the chain has some frames on the previous lines. 1.57 + */ 1.58 + bool mHasContOnPrevLines; 1.59 + 1.60 + /** 1.61 + * TRUE if this frame is the first visual frame of its continuation chain on 1.62 + * this line and the chain has some frames left for next lines. 1.63 + */ 1.64 + bool mHasContOnNextLines; 1.65 +}; 1.66 + 1.67 +/* 1.68 + * Following type is used to pass needed hashtable to reordering methods 1.69 + */ 1.70 +typedef nsTHashtable<nsFrameContinuationState> nsContinuationStates; 1.71 + 1.72 +/** 1.73 + * A structure representing a logical position which should be resolved 1.74 + * into its visual position during BiDi processing. 1.75 + */ 1.76 +struct nsBidiPositionResolve 1.77 +{ 1.78 + // [in] Logical index within string. 1.79 + int32_t logicalIndex; 1.80 + // [out] Visual index within string. 1.81 + // If the logical position was not found, set to kNotFound. 1.82 + int32_t visualIndex; 1.83 + // [out] Visual position of the character, from the left (on the X axis), in twips. 1.84 + // 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. 1.85 + // If the logical position was not found, set to kNotFound. 1.86 + int32_t visualLeftTwips; 1.87 + // [out] Visual width of the character, in twips. 1.88 + // If the logical position was not found, set to kNotFound. 1.89 + int32_t visualWidth; 1.90 +}; 1.91 + 1.92 +class nsBidiPresUtils { 1.93 +public: 1.94 + nsBidiPresUtils(); 1.95 + ~nsBidiPresUtils(); 1.96 + 1.97 + /** 1.98 + * Interface for the processor used by ProcessText. Used by process text to 1.99 + * collect information about the width of subruns and to notify where each 1.100 + * subrun should be rendered. 1.101 + */ 1.102 + class BidiProcessor { 1.103 + public: 1.104 + virtual ~BidiProcessor() { } 1.105 + 1.106 + /** 1.107 + * Sets the current text with the given length and the given direction. 1.108 + * 1.109 + * @remark The reason that the function gives a string instead of an index 1.110 + * is that ProcessText copies and modifies the string passed to it, so 1.111 + * passing an index would be impossible. 1.112 + * 1.113 + * @param aText The string of text. 1.114 + * @param aLength The length of the string of text. 1.115 + * @param aDirection The direction of the text. The string will never have 1.116 + * mixed direction. 1.117 + */ 1.118 + virtual void SetText(const char16_t* aText, 1.119 + int32_t aLength, 1.120 + nsBidiDirection aDirection) = 0; 1.121 + 1.122 + /** 1.123 + * Returns the measured width of the text given in SetText. If SetText was 1.124 + * not called with valid parameters, the result of this call is undefined. 1.125 + * This call is guaranteed to only be called once between SetText calls. 1.126 + * Will be invoked before DrawText. 1.127 + */ 1.128 + virtual nscoord GetWidth() = 0; 1.129 + 1.130 + /** 1.131 + * Draws the text given in SetText to a rendering context. If SetText was 1.132 + * not called with valid parameters, the result of this call is undefined. 1.133 + * This call is guaranteed to only be called once between SetText calls. 1.134 + * 1.135 + * @param aXOffset The offset of the left side of the substring to be drawn 1.136 + * from the beginning of the overall string passed to ProcessText. 1.137 + * @param aWidth The width returned by GetWidth. 1.138 + */ 1.139 + virtual void DrawText(nscoord aXOffset, 1.140 + nscoord aWidth) = 0; 1.141 + }; 1.142 + 1.143 + /** 1.144 + * Make Bidi engine calculate the embedding levels of the frames that are 1.145 + * descendants of a given block frame. 1.146 + * 1.147 + * @param aBlockFrame The block frame 1.148 + * 1.149 + * @lina 06/18/2000 1.150 + */ 1.151 + static nsresult Resolve(nsBlockFrame* aBlockFrame); 1.152 + static nsresult ResolveParagraph(nsBlockFrame* aBlockFrame, 1.153 + BidiParagraphData* aBpd); 1.154 + static void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame, 1.155 + BidiParagraphData* aBpd); 1.156 + 1.157 + /** 1.158 + * Reorder this line using Bidi engine. 1.159 + * Update frame array, following the new visual sequence. 1.160 + * 1.161 + * @lina 05/02/2000 1.162 + */ 1.163 + static void ReorderFrames(nsIFrame* aFirstFrameOnLine, 1.164 + int32_t aNumFramesOnLine, 1.165 + mozilla::WritingMode aLineWM, 1.166 + nscoord& aLineWidth); 1.167 + 1.168 + /** 1.169 + * Format Unicode text, taking into account bidi capabilities 1.170 + * of the platform. The formatting includes: reordering, Arabic shaping, 1.171 + * symmetric and numeric swapping, removing control characters. 1.172 + * 1.173 + * @lina 06/18/2000 1.174 + */ 1.175 + static nsresult FormatUnicodeText(nsPresContext* aPresContext, 1.176 + char16_t* aText, 1.177 + int32_t& aTextLength, 1.178 + nsCharType aCharType, 1.179 + bool aIsOddLevel); 1.180 + 1.181 + /** 1.182 + * Reorder plain text using the Unicode Bidi algorithm and send it to 1.183 + * a rendering context for rendering. 1.184 + * 1.185 + * @param[in] aText the string to be rendered (in logical order) 1.186 + * @param aLength the number of characters in the string 1.187 + * @param aBaseLevel the base embedding level of the string 1.188 + * odd values are right-to-left; even values are left-to-right, plus special 1.189 + * constants as follows (defined in nsBidi.h) 1.190 + * NSBIDI_LTR - left-to-right string 1.191 + * NSBIDI_RTL - right-to-left string 1.192 + * NSBIDI_DEFAULT_LTR - auto direction determined by first strong character, 1.193 + * default is left-to-right 1.194 + * NSBIDI_DEFAULT_RTL - auto direction determined by first strong character, 1.195 + * default is right-to-left 1.196 + * 1.197 + * @param aPresContext the presentation context 1.198 + * @param aRenderingContext the rendering context to render to 1.199 + * @param aTextRunConstructionContext the rendering context to be used to construct the textrun (affects font hinting) 1.200 + * @param aX the x-coordinate to render the string 1.201 + * @param aY the y-coordinate to render the string 1.202 + * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nullptr if this functionality is not required 1.203 + * @param aPosResolveCount number of items in the aPosResolve array 1.204 + */ 1.205 + static nsresult RenderText(const char16_t* aText, 1.206 + int32_t aLength, 1.207 + nsBidiLevel aBaseLevel, 1.208 + nsPresContext* aPresContext, 1.209 + nsRenderingContext& aRenderingContext, 1.210 + nsRenderingContext& aTextRunConstructionContext, 1.211 + nscoord aX, 1.212 + nscoord aY, 1.213 + nsBidiPositionResolve* aPosResolve = nullptr, 1.214 + int32_t aPosResolveCount = 0) 1.215 + { 1.216 + return ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext, aRenderingContext, 1.217 + aTextRunConstructionContext, MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nullptr); 1.218 + } 1.219 + 1.220 + static nscoord MeasureTextWidth(const char16_t* aText, 1.221 + int32_t aLength, 1.222 + nsBidiLevel aBaseLevel, 1.223 + nsPresContext* aPresContext, 1.224 + nsRenderingContext& aRenderingContext) 1.225 + { 1.226 + nscoord length; 1.227 + nsresult rv = ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext, 1.228 + aRenderingContext, aRenderingContext, 1.229 + MODE_MEASURE, 0, 0, nullptr, 0, &length); 1.230 + return NS_SUCCEEDED(rv) ? length : 0; 1.231 + } 1.232 + 1.233 + /** 1.234 + * Check if a line is reordered, i.e., if the child frames are not 1.235 + * all laid out left-to-right. 1.236 + * @param aFirstFrameOnLine : first frame of the line to be tested 1.237 + * @param aNumFramesOnLine : number of frames on this line 1.238 + * @param[out] aLeftMost : leftmost frame on this line 1.239 + * @param[out] aRightMost : rightmost frame on this line 1.240 + */ 1.241 + static bool CheckLineOrder(nsIFrame* aFirstFrameOnLine, 1.242 + int32_t aNumFramesOnLine, 1.243 + nsIFrame** aLeftmost, 1.244 + nsIFrame** aRightmost); 1.245 + 1.246 + /** 1.247 + * Get the frame to the right of the given frame, on the same line. 1.248 + * @param aFrame : We're looking for the frame to the right of this frame. 1.249 + * If null, return the leftmost frame on the line. 1.250 + * @param aFirstFrameOnLine : first frame of the line to be tested 1.251 + * @param aNumFramesOnLine : number of frames on this line 1.252 + */ 1.253 + static nsIFrame* GetFrameToRightOf(const nsIFrame* aFrame, 1.254 + nsIFrame* aFirstFrameOnLine, 1.255 + int32_t aNumFramesOnLine); 1.256 + 1.257 + /** 1.258 + * Get the frame to the left of the given frame, on the same line. 1.259 + * @param aFrame : We're looking for the frame to the left of this frame. 1.260 + * If null, return the rightmost frame on the line. 1.261 + * @param aFirstFrameOnLine : first frame of the line to be tested 1.262 + * @param aNumFramesOnLine : number of frames on this line 1.263 + */ 1.264 + static nsIFrame* GetFrameToLeftOf(const nsIFrame* aFrame, 1.265 + nsIFrame* aFirstFrameOnLine, 1.266 + int32_t aNumFramesOnLine); 1.267 + 1.268 + static nsIFrame* GetFirstLeaf(nsIFrame* aFrame); 1.269 + 1.270 + /** 1.271 + * Get the bidi embedding level of the given (inline) frame. 1.272 + */ 1.273 + static nsBidiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame); 1.274 + 1.275 + /** 1.276 + * Get the paragraph depth of the given (inline) frame. 1.277 + */ 1.278 + static uint8_t GetParagraphDepth(nsIFrame* aFrame); 1.279 + 1.280 + /** 1.281 + * Get the bidi base level of the given (inline) frame. 1.282 + */ 1.283 + static nsBidiLevel GetFrameBaseLevel(nsIFrame* aFrame); 1.284 + 1.285 + enum Mode { MODE_DRAW, MODE_MEASURE }; 1.286 + 1.287 + /** 1.288 + * Reorder plain text using the Unicode Bidi algorithm and send it to 1.289 + * a processor for rendering or measuring 1.290 + * 1.291 + * @param[in] aText the string to be processed (in logical order) 1.292 + * @param aLength the number of characters in the string 1.293 + * @param aBaseLevel the base embedding level of the string 1.294 + * odd values are right-to-left; even values are left-to-right, plus special 1.295 + * constants as follows (defined in nsBidi.h) 1.296 + * NSBIDI_LTR - left-to-right string 1.297 + * NSBIDI_RTL - right-to-left string 1.298 + * NSBIDI_DEFAULT_LTR - auto direction determined by first strong character, 1.299 + * default is left-to-right 1.300 + * NSBIDI_DEFAULT_RTL - auto direction determined by first strong character, 1.301 + * default is right-to-left 1.302 + * 1.303 + * @param aPresContext the presentation context 1.304 + * @param aprocessor the bidi processor 1.305 + * @param aMode the operation to process 1.306 + * MODE_DRAW - invokes DrawText on the processor for each substring 1.307 + * MODE_MEASURE - does not invoke DrawText on the processor 1.308 + * Note that the string is always measured, regardless of mode 1.309 + * @param[in,out] aPosResolve array of logical positions to resolve into 1.310 + * visual positions; can be nullptr if this functionality is not required 1.311 + * @param aPosResolveCount number of items in the aPosResolve array 1.312 + * @param[out] aWidth Pointer to where the width will be stored (may be null) 1.313 + */ 1.314 + static nsresult ProcessText(const char16_t* aText, 1.315 + int32_t aLength, 1.316 + nsBidiLevel aBaseLevel, 1.317 + nsPresContext* aPresContext, 1.318 + BidiProcessor& aprocessor, 1.319 + Mode aMode, 1.320 + nsBidiPositionResolve* aPosResolve, 1.321 + int32_t aPosResolveCount, 1.322 + nscoord* aWidth, 1.323 + nsBidi* aBidiEngine); 1.324 + 1.325 + /** 1.326 + * Make a copy of a string, converting from logical to visual order 1.327 + * 1.328 + * @param aSource the source string 1.329 + * @param aDest the destination string 1.330 + * @param aBaseDirection the base direction of the string 1.331 + * (NSBIDI_LTR or NSBIDI_RTL to force the base direction; 1.332 + * NSBIDI_DEFAULT_LTR or NSBIDI_DEFAULT_RTL to let the bidi engine 1.333 + * determine the direction from rules P2 and P3 of the bidi algorithm. 1.334 + * @see nsBidi::GetPara 1.335 + * @param aOverride if TRUE, the text has a bidi override, according to 1.336 + * the direction in aDir 1.337 + */ 1.338 + static void CopyLogicalToVisual(const nsAString& aSource, 1.339 + nsAString& aDest, 1.340 + nsBidiLevel aBaseDirection, 1.341 + bool aOverride); 1.342 + 1.343 + /** 1.344 + * Use style attributes to determine the base paragraph level to pass to the 1.345 + * bidi algorithm. 1.346 + * 1.347 + * If |unicode-bidi| is set to "[-moz-]plaintext", returns NSBIDI_DEFAULT_LTR, 1.348 + * in other words the direction is determined from the first strong character 1.349 + * in the text according to rules P2 and P3 of the bidi algorithm, or LTR if 1.350 + * there is no strong character. 1.351 + * 1.352 + * Otherwise returns NSBIDI_LTR or NSBIDI_RTL depending on the value of 1.353 + * |direction| 1.354 + */ 1.355 + static nsBidiLevel BidiLevelFromStyle(nsStyleContext* aStyleContext); 1.356 + 1.357 +private: 1.358 + static nsresult 1.359 + ProcessTextForRenderingContext(const char16_t* aText, 1.360 + int32_t aLength, 1.361 + nsBidiLevel aBaseLevel, 1.362 + nsPresContext* aPresContext, 1.363 + nsRenderingContext& aRenderingContext, 1.364 + nsRenderingContext& aTextRunConstructionContext, 1.365 + Mode aMode, 1.366 + nscoord aX, // DRAW only 1.367 + nscoord aY, // DRAW only 1.368 + nsBidiPositionResolve* aPosResolve, /* may be null */ 1.369 + int32_t aPosResolveCount, 1.370 + nscoord* aWidth /* may be null */); 1.371 + 1.372 + /** 1.373 + * Traverse the child frames of the block element and: 1.374 + * Set up an array of the frames in logical order 1.375 + * Create a string containing the text content of all the frames 1.376 + * If we encounter content that requires us to split the element into more 1.377 + * than one paragraph for bidi resolution, resolve the paragraph up to that 1.378 + * point. 1.379 + */ 1.380 + static void TraverseFrames(nsBlockFrame* aBlockFrame, 1.381 + nsBlockInFlowLineIterator* aLineIter, 1.382 + nsIFrame* aCurrentFrame, 1.383 + BidiParagraphData* aBpd); 1.384 + 1.385 + /* 1.386 + * Position aFrame and its descendants to their visual places. Also if aFrame 1.387 + * is not leaf, resize it to embrace its children. 1.388 + * 1.389 + * @param aFrame The frame which itself and its children are 1.390 + * going to be repositioned 1.391 + * @param aIsEvenLevel TRUE means the embedding level of this frame 1.392 + * is even (LTR) 1.393 + * @param[in,out] aStart IN value is the starting position of aFrame 1.394 + * (without considering its inline-start margin) 1.395 + * OUT value will be the ending position of aFrame 1.396 + * (after adding its inline-end margin) 1.397 + * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState 1.398 + */ 1.399 + static void RepositionFrame(nsIFrame* aFrame, 1.400 + bool aIsEvenLevel, 1.401 + nscoord& aStart, 1.402 + nsContinuationStates* aContinuationStates, 1.403 + mozilla::WritingMode aLineWM, 1.404 + nscoord& aLineWidth); 1.405 + 1.406 + /* 1.407 + * Initialize the continuation state(nsFrameContinuationState) to 1.408 + * (nullptr, 0) for aFrame and its descendants. 1.409 + * 1.410 + * @param aFrame The frame which itself and its descendants will 1.411 + * be initialized 1.412 + * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState 1.413 + */ 1.414 + static void InitContinuationStates(nsIFrame* aFrame, 1.415 + nsContinuationStates* aContinuationStates); 1.416 + 1.417 + /* 1.418 + * Determine if aFrame is leftmost or rightmost, and set aIsLeftMost and 1.419 + * aIsRightMost values. Also set continuation states of aContinuationStates. 1.420 + * 1.421 + * A frame is leftmost if it's the first appearance of its continuation chain 1.422 + * on the line and the chain is on its first line if it's LTR or the chain is 1.423 + * on its last line if it's RTL. 1.424 + * A frame is rightmost if it's the last appearance of its continuation chain 1.425 + * on the line and the chain is on its first line if it's RTL or the chain is 1.426 + * on its last line if it's LTR. 1.427 + * 1.428 + * @param aContinuationStates A map from nsIFrame* to nsFrameContinuationState 1.429 + * @param[out] aIsLeftMost TRUE means aFrame is leftmost frame or continuation 1.430 + * @param[out] aIsRightMost TRUE means aFrame is rightmost frame or continuation 1.431 + */ 1.432 + static void IsFirstOrLast(nsIFrame* aFrame, 1.433 + nsContinuationStates* aContinuationStates, 1.434 + bool& aIsFirst /* out */, 1.435 + bool& aIsLast /* out */); 1.436 + 1.437 + /** 1.438 + * Adjust frame positions following their visual order 1.439 + * 1.440 + * @param aFirstChild the first kid 1.441 + * 1.442 + * @lina 04/11/2000 1.443 + */ 1.444 + static void RepositionInlineFrames(BidiLineData* aBld, 1.445 + nsIFrame* aFirstChild, 1.446 + mozilla::WritingMode aLineWM, 1.447 + nscoord& aLineWidth); 1.448 + 1.449 + /** 1.450 + * Helper method for Resolve() 1.451 + * Truncate a text frame to the end of a single-directional run and possibly 1.452 + * create a continuation frame for the remainder of its content. 1.453 + * 1.454 + * @param aFrame the original frame 1.455 + * @param aNewFrame [OUT] the new frame that was created 1.456 + * @param aFrameIndex [IN/OUT] index of aFrame in mLogicalFrames 1.457 + * @param aStart [IN] the start of the content mapped by aFrame (and 1.458 + * any fluid continuations) 1.459 + * @param aEnd [IN] the offset of the end of the single-directional 1.460 + * text run. 1.461 + * @see Resolve() 1.462 + * @see RemoveBidiContinuation() 1.463 + */ 1.464 + static inline 1.465 + nsresult EnsureBidiContinuation(nsIFrame* aFrame, 1.466 + nsIFrame** aNewFrame, 1.467 + int32_t& aFrameIndex, 1.468 + int32_t aStart, 1.469 + int32_t aEnd); 1.470 + 1.471 + /** 1.472 + * Helper method for Resolve() 1.473 + * Convert one or more bidi continuation frames created in a previous reflow by 1.474 + * EnsureBidiContinuation() into fluid continuations. 1.475 + * @param aFrame the frame whose continuations are to be removed 1.476 + * @param aFirstIndex index of aFrame in mLogicalFrames 1.477 + * @param aLastIndex index of the last frame to be removed 1.478 + * @param aOffset [OUT] count of directional frames removed. Since 1.479 + * directional frames have control characters 1.480 + * corresponding to them in mBuffer, the pointers to 1.481 + * mBuffer in Resolve() will need to be updated after 1.482 + * deleting the frames. 1.483 + * 1.484 + * @see Resolve() 1.485 + * @see EnsureBidiContinuation() 1.486 + */ 1.487 + static void RemoveBidiContinuation(BidiParagraphData* aBpd, 1.488 + nsIFrame* aFrame, 1.489 + int32_t aFirstIndex, 1.490 + int32_t aLastIndex, 1.491 + int32_t& aOffset); 1.492 + static void CalculateCharType(nsBidi* aBidiEngine, 1.493 + const char16_t* aText, 1.494 + int32_t& aOffset, 1.495 + int32_t aCharTypeLimit, 1.496 + int32_t& aRunLimit, 1.497 + int32_t& aRunLength, 1.498 + int32_t& aRunCount, 1.499 + uint8_t& aCharType, 1.500 + uint8_t& aPrevCharType); 1.501 + 1.502 + static void StripBidiControlCharacters(char16_t* aText, 1.503 + int32_t& aTextLength); 1.504 + 1.505 + static bool WriteLogicalToVisual(const char16_t* aSrc, 1.506 + uint32_t aSrcLength, 1.507 + char16_t* aDest, 1.508 + nsBidiLevel aBaseDirection, 1.509 + nsBidi* aBidiEngine); 1.510 + 1.511 + static void WriteReverse(const char16_t* aSrc, 1.512 + uint32_t aSrcLength, 1.513 + char16_t* aDest); 1.514 +}; 1.515 + 1.516 +#endif /* nsBidiPresUtils_h___ */