From ad90f8900cd9209f192788c2001fc354fc72bfd6 Mon Sep 17 00:00:00 2001 From: "smontagu%netscape.com" Date: Mon, 12 Nov 2001 20:51:48 +0000 Subject: [PATCH] Fix for bug 81773: Bidi XUL text (e.g. bookmarks, tab titles) was flipping to and fro on systems without native Bidi support. r=mkaply, r/sr=hyatt, sr=attinasi --- layout/base/nsBidiPresUtils.cpp | 71 ++++++++++++++++++++++++ layout/base/nsBidiPresUtils.h | 21 +++++++ layout/base/public/nsBidiPresUtils.h | 21 +++++++ layout/base/src/nsBidiPresUtils.cpp | 71 ++++++++++++++++++++++++ layout/xul/base/src/nsTextBoxFrame.cpp | 77 ++++---------------------- 5 files changed, 196 insertions(+), 65 deletions(-) diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp index 5815c6de071a..1b26d980947d 100644 --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -1080,5 +1080,76 @@ nsresult nsBidiPresUtils::GetBidiEngine(nsIBidi** aBidiEngine) } return rv; } + +nsresult nsBidiPresUtils::RenderText(PRUnichar* aText, + PRInt32 aLength, + nsBidiDirection aBaseDirection, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nscoord aX, + nscoord aY) +{ + PRInt32 runCount; + + mBuffer.Assign(aText); + + nsresult rv = mBidiEngine->SetPara(mBuffer.get(), aLength, aBaseDirection, nsnull); + if (NS_FAILED(rv)) + return rv; + + rv = mBidiEngine->CountRuns(&runCount); + if (NS_FAILED(rv)) + return rv; + + nscoord width; + PRBool isRTL = PR_FALSE; + PRInt32 i, start, limit, length; + PRUint8 charType; + PRUint8 prevType = eCharType_LeftToRight; + nsBidiLevel level; + PRInt32 lineOffset = 0; + PRInt32 runLength = 0; + + PRUint32 hints = 0; + aRenderingContext.GetHints(hints); + PRBool isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING); + + for (i = 0; i < runCount; i++) { + rv = mBidiEngine->GetVisualRun(i, &start, &length, &aBaseDirection); + if (NS_FAILED(rv)) + return rv; + + rv = mBidiEngine->GetLogicalRun(start, &limit, &level); + if (NS_FAILED(rv)) + return rv; + + runLength = limit - start; + lineOffset = start; + PRInt32 typeLimit = PR_MIN(limit, aLength); + CalculateCharType(lineOffset, typeLimit, limit, runLength, runCount, charType, prevType); + + if (eCharType_RightToLeftArabic == charType) { + isBidiSystem = (hints & NS_RENDERING_HINT_ARABIC_SHAPING); + } + if (isBidiSystem && (CHARTYPE_IS_RTL(charType) ^ isRTL) ) { + // set reading order into DC + isRTL = !isRTL; + aRenderingContext.SetRightToLeftText(isRTL); + } + FormatUnicodeText(aPresContext, aText + start, length, + (nsCharType)charType, level & 1, + isBidiSystem); + + aRenderingContext.GetWidth(aText + start, length, width, nsnull); + aRenderingContext.DrawString(aText + start, length, aX, aY, width); + aX += width; + } // for + + // Restore original reading order + if (isRTL) { + aRenderingContext.SetRightToLeftText(PR_FALSE); + } + return NS_OK; +} #endif // IBMBIDI diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h index 6930ab21eb45..80afd1fb2bd0 100644 --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -79,6 +79,27 @@ public: */ nsresult GetBidiEngine(nsIBidi** aBidiEngine); + /** + * Reorder plain text using the Unicode Bidi algorithm and send it to + * a rendering context for rendering. + * + * @param aText the string to be rendered + * @param aLength the number of characters in the string + * @param aBaseDirection the base direction of the string + * NSBIDI_LTR - left-to-right string + * NSBIDI_RTL - right-to-left string + * @param aPresContext the presentation context + * @param aRenderingContext the rendering context + * @param aTextRect contains the coordinates to render the string + */ + nsresult nsBidiPresUtils::RenderText(PRUnichar* aText, + PRInt32 aLength, + nsBidiDirection aBaseDirection, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nscoord aX, + nscoord aY); + private: /** * Create a string containing entire text content of this block. diff --git a/layout/base/public/nsBidiPresUtils.h b/layout/base/public/nsBidiPresUtils.h index 6930ab21eb45..80afd1fb2bd0 100644 --- a/layout/base/public/nsBidiPresUtils.h +++ b/layout/base/public/nsBidiPresUtils.h @@ -79,6 +79,27 @@ public: */ nsresult GetBidiEngine(nsIBidi** aBidiEngine); + /** + * Reorder plain text using the Unicode Bidi algorithm and send it to + * a rendering context for rendering. + * + * @param aText the string to be rendered + * @param aLength the number of characters in the string + * @param aBaseDirection the base direction of the string + * NSBIDI_LTR - left-to-right string + * NSBIDI_RTL - right-to-left string + * @param aPresContext the presentation context + * @param aRenderingContext the rendering context + * @param aTextRect contains the coordinates to render the string + */ + nsresult nsBidiPresUtils::RenderText(PRUnichar* aText, + PRInt32 aLength, + nsBidiDirection aBaseDirection, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nscoord aX, + nscoord aY); + private: /** * Create a string containing entire text content of this block. diff --git a/layout/base/src/nsBidiPresUtils.cpp b/layout/base/src/nsBidiPresUtils.cpp index 5815c6de071a..1b26d980947d 100644 --- a/layout/base/src/nsBidiPresUtils.cpp +++ b/layout/base/src/nsBidiPresUtils.cpp @@ -1080,5 +1080,76 @@ nsresult nsBidiPresUtils::GetBidiEngine(nsIBidi** aBidiEngine) } return rv; } + +nsresult nsBidiPresUtils::RenderText(PRUnichar* aText, + PRInt32 aLength, + nsBidiDirection aBaseDirection, + nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nscoord aX, + nscoord aY) +{ + PRInt32 runCount; + + mBuffer.Assign(aText); + + nsresult rv = mBidiEngine->SetPara(mBuffer.get(), aLength, aBaseDirection, nsnull); + if (NS_FAILED(rv)) + return rv; + + rv = mBidiEngine->CountRuns(&runCount); + if (NS_FAILED(rv)) + return rv; + + nscoord width; + PRBool isRTL = PR_FALSE; + PRInt32 i, start, limit, length; + PRUint8 charType; + PRUint8 prevType = eCharType_LeftToRight; + nsBidiLevel level; + PRInt32 lineOffset = 0; + PRInt32 runLength = 0; + + PRUint32 hints = 0; + aRenderingContext.GetHints(hints); + PRBool isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING); + + for (i = 0; i < runCount; i++) { + rv = mBidiEngine->GetVisualRun(i, &start, &length, &aBaseDirection); + if (NS_FAILED(rv)) + return rv; + + rv = mBidiEngine->GetLogicalRun(start, &limit, &level); + if (NS_FAILED(rv)) + return rv; + + runLength = limit - start; + lineOffset = start; + PRInt32 typeLimit = PR_MIN(limit, aLength); + CalculateCharType(lineOffset, typeLimit, limit, runLength, runCount, charType, prevType); + + if (eCharType_RightToLeftArabic == charType) { + isBidiSystem = (hints & NS_RENDERING_HINT_ARABIC_SHAPING); + } + if (isBidiSystem && (CHARTYPE_IS_RTL(charType) ^ isRTL) ) { + // set reading order into DC + isRTL = !isRTL; + aRenderingContext.SetRightToLeftText(isRTL); + } + FormatUnicodeText(aPresContext, aText + start, length, + (nsCharType)charType, level & 1, + isBidiSystem); + + aRenderingContext.GetWidth(aText + start, length, width, nsnull); + aRenderingContext.DrawString(aText + start, length, aX, aY, width); + aX += width; + } // for + + // Restore original reading order + if (isRTL) { + aRenderingContext.SetRightToLeftText(PR_FALSE); + } + return NS_OK; +} #endif // IBMBIDI diff --git a/layout/xul/base/src/nsTextBoxFrame.cpp b/layout/xul/base/src/nsTextBoxFrame.cpp index ca8f1fa98ef5..d0e43a10bcec 100644 --- a/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/layout/xul/base/src/nsTextBoxFrame.cpp @@ -64,6 +64,7 @@ #ifdef IBMBIDI #include "nsIUBidiUtils.h" #include "nsBidiPresUtils.h" +#include "nsReadableUtils.h" #endif // IBMBIDI #define ELLIPSIS "..." @@ -409,77 +410,23 @@ nsTextBoxFrame::PaintTitle(nsIPresContext* aPresContext, if (mState & NS_FRAME_IS_BIDI) { nsBidiPresUtils* bidiUtils; + aPresContext->SetBidiEnabled(PR_TRUE); aPresContext->GetBidiUtils(&bidiUtils); if (bidiUtils) { - nsCOMPtr bidiEngine; - bidiUtils->GetBidiEngine(getter_AddRefs(bidiEngine)); - - if (bidiEngine) { - const nsStyleVisibility* vis; - GetStyleData(eStyleStruct_Visibility, (const nsStyleStruct*&) vis); - PRUnichar* buffer = (PRUnichar*) mCroppedTitle.get(); - PRInt32 runCount; + PRUnichar* buffer = ToNewUnicode(mCroppedTitle); + if (buffer) { + const nsStyleVisibility* vis = (const nsStyleVisibility*)mStyleContext->GetStyleData(eStyleStruct_Visibility); nsBidiDirection direction = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ? NSBIDI_RTL : NSBIDI_LTR; - - rv = bidiEngine->SetPara(buffer, mCroppedTitle.Length(), direction, nsnull); - - if (NS_SUCCEEDED(rv) ) { - rv = bidiEngine->CountRuns(&runCount); - - if (NS_SUCCEEDED(rv) ) { - nscoord width; - PRBool isRTL = PR_FALSE; - PRInt32 i, start, limit, length; - nsCharType charType; - nsBidiLevel level; - - PRBool isBidiSystem; - PRUint32 hints = 0; - aRenderingContext.GetHints(hints); - isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING); - - for (i = 0; i < runCount; i++) { - rv = bidiEngine->GetVisualRun(i, &start, &length, &direction); - if (NS_FAILED(rv) ) { - break; - } - bidiEngine->GetCharTypeAt(start, &charType); - - rv = bidiEngine->GetLogicalRun(start, &limit, &level); - if (NS_FAILED(rv) ) { - break; - } - if (eCharType_RightToLeftArabic == charType) { - isBidiSystem = (hints & NS_RENDERING_HINT_ARABIC_SHAPING); - } - if (isBidiSystem && (CHARTYPE_IS_RTL(charType) ^ isRTL) ) { - // set reading order into DC - isRTL = !isRTL; - aRenderingContext.SetRightToLeftText(isRTL); - } - bidiUtils->FormatUnicodeText(aPresContext, buffer + start, length, - charType, level & 1, - isBidiSystem); - - aRenderingContext.GetWidth(buffer + start, length, width, nsnull); - aRenderingContext.DrawString(buffer + start, length, textRect.x, - textRect.y + baseline, width); - textRect.x += width; - } // for - // Restore original x (for aRenderingContext.FillRect below), - // as well as reading order - textRect.x = aRect.x; - if (isRTL) { - aRenderingContext.SetRightToLeftText(PR_FALSE); - } - } - } - } // bidiEngine - } // bidiUtils - } // frame is bidi + rv = bidiUtils->RenderText(buffer, mCroppedTitle.Length(), direction, + aPresContext, aRenderingContext, + textRect.x, textRect.y + baseline); + nsMemory::Free(buffer); + } + } + } if (NS_FAILED(rv) ) #endif // IBMBIDI aRenderingContext.DrawString(mCroppedTitle, textRect.x, textRect.y + baseline);