Do Arabic shaping earlier before measuring the text so that it gets laid out correctly. Bugs 117041, 138097. r=ftang, sr=waterson

This commit is contained in:
smontagu%netscape.com 2002-06-11 21:00:20 +00:00
parent 2e70ad3106
commit 66051e90f8
12 changed files with 538 additions and 56 deletions

View File

@ -256,7 +256,7 @@ nsresult ArabicShaping(const PRUnichar* aString, PRUint32 aLen,
PRBool aInputLogical, PRBool aOutputLogical)
{
nsAutoString tempString(aString);
PRUnichar *tempBuf = (PRUnichar*)tempString.get();
PRUnichar *tempBuf = NS_CONST_CAST(PRUnichar*, tempString.get());
if (aInputLogical) {
ReverseString(tempBuf, aLen);
}
@ -318,7 +318,8 @@ nsresult ArabicShaping(const PRUnichar* aString, PRUint32 aLen,
for(i=0;i<8;i++) {
if(key == gArabicLigatureMap[i]) {
done = PR_TRUE;
*lDest++ = 0x200B;//ZERO WIDTH SPACE
// lam and alef in the source are mapped to a lam-alef ligature in the
// destination, so lSrc is incremented by 2 here
*lDest++ = 0xFEF5 + i;
lSrc+=2;
break;

View File

@ -870,6 +870,7 @@ nsBidiPresUtils::FormatUnicodeText(nsIPresContext* aPresContext,
PRBool aIsOddLevel,
PRBool aIsBidiSystem)
{
NS_ASSERTION(aIsOddLevel == 0 || aIsOddLevel == 1, "aIsOddLevel should be 0 or 1");
nsresult rv = NS_OK;
// ahmed
//adjusted for correct numeral shaping
@ -933,7 +934,7 @@ nsBidiPresUtils::FormatUnicodeText(nsIPresContext* aPresContext,
if (mBuffer.Length() < aTextLength) {
mBuffer.SetLength(aTextLength);
}
PRUnichar* buffer = (PRUnichar*)mBuffer.get();
PRUnichar* buffer = NS_CONST_CAST(PRUnichar*, mBuffer.get());
if (doReverse) {
rv = mBidiEngine->WriteReverse(aText, aTextLength, buffer,
@ -1162,4 +1163,44 @@ nsresult nsBidiPresUtils::RenderText(PRUnichar* aText,
return NS_OK;
}
nsresult
nsBidiPresUtils::ReorderUnicodeText(PRUnichar* aText,
PRInt32& aTextLength,
nsCharType aCharType,
PRBool aIsOddLevel,
PRBool aIsBidiSystem)
{
NS_ASSERTION(aIsOddLevel == 0 || aIsOddLevel == 1, "aIsOddLevel should be 0 or 1");
nsresult rv = NS_OK;
PRBool doReverse = PR_FALSE;
if (aIsBidiSystem) {
if ( (CHARTYPE_IS_RTL(aCharType)) ^ (aIsOddLevel) )
doReverse = PR_TRUE;
}
else {
if (aIsOddLevel)
doReverse = PR_TRUE;
}
if (doReverse) {
PRInt32 newLen;
if (mBuffer.Length() < aTextLength) {
mBuffer.SetLength(aTextLength);
}
PRUnichar* buffer = NS_CONST_CAST(PRUnichar*, mBuffer.get());
if (doReverse) {
rv = mBidiEngine->WriteReverse(aText, aTextLength, buffer,
NSBIDI_DO_MIRRORING, &newLen);
if (NS_SUCCEEDED(rv) ) {
aTextLength = newLen;
memcpy(aText, buffer, aTextLength * sizeof(PRUnichar) );
}
}
}
return rv;
}
#endif // IBMBIDI

View File

@ -74,6 +74,17 @@ public:
PRBool aIsOddLevel,
PRBool aIsBidiSystem);
/**
* Reorder Unicode text, taking into account bidi capabilities of the
* platform. The reordering includes symmetric swapping and removing
* control characters.
*/
nsresult ReorderUnicodeText(PRUnichar* aText,
PRInt32& aTextLength,
nsCharType aCharType,
PRBool aIsOddLevel,
PRBool aIsBidiSystem);
/**
* Return our nsBidi object (bidi reordering engine)
*/

View File

@ -256,7 +256,7 @@ nsresult ArabicShaping(const PRUnichar* aString, PRUint32 aLen,
PRBool aInputLogical, PRBool aOutputLogical)
{
nsAutoString tempString(aString);
PRUnichar *tempBuf = (PRUnichar*)tempString.get();
PRUnichar *tempBuf = NS_CONST_CAST(PRUnichar*, tempString.get());
if (aInputLogical) {
ReverseString(tempBuf, aLen);
}
@ -318,7 +318,8 @@ nsresult ArabicShaping(const PRUnichar* aString, PRUint32 aLen,
for(i=0;i<8;i++) {
if(key == gArabicLigatureMap[i]) {
done = PR_TRUE;
*lDest++ = 0x200B;//ZERO WIDTH SPACE
// lam and alef in the source are mapped to a lam-alef ligature in the
// destination, so lSrc is incremented by 2 here
*lDest++ = 0xFEF5 + i;
lSrc+=2;
break;

View File

@ -74,6 +74,17 @@ public:
PRBool aIsOddLevel,
PRBool aIsBidiSystem);
/**
* Reorder Unicode text, taking into account bidi capabilities of the
* platform. The reordering includes symmetric swapping and removing
* control characters.
*/
nsresult ReorderUnicodeText(PRUnichar* aText,
PRInt32& aTextLength,
nsCharType aCharType,
PRBool aIsOddLevel,
PRBool aIsBidiSystem);
/**
* Return our nsBidi object (bidi reordering engine)
*/

View File

@ -870,6 +870,7 @@ nsBidiPresUtils::FormatUnicodeText(nsIPresContext* aPresContext,
PRBool aIsOddLevel,
PRBool aIsBidiSystem)
{
NS_ASSERTION(aIsOddLevel == 0 || aIsOddLevel == 1, "aIsOddLevel should be 0 or 1");
nsresult rv = NS_OK;
// ahmed
//adjusted for correct numeral shaping
@ -933,7 +934,7 @@ nsBidiPresUtils::FormatUnicodeText(nsIPresContext* aPresContext,
if (mBuffer.Length() < aTextLength) {
mBuffer.SetLength(aTextLength);
}
PRUnichar* buffer = (PRUnichar*)mBuffer.get();
PRUnichar* buffer = NS_CONST_CAST(PRUnichar*, mBuffer.get());
if (doReverse) {
rv = mBidiEngine->WriteReverse(aText, aTextLength, buffer,
@ -1162,4 +1163,44 @@ nsresult nsBidiPresUtils::RenderText(PRUnichar* aText,
return NS_OK;
}
nsresult
nsBidiPresUtils::ReorderUnicodeText(PRUnichar* aText,
PRInt32& aTextLength,
nsCharType aCharType,
PRBool aIsOddLevel,
PRBool aIsBidiSystem)
{
NS_ASSERTION(aIsOddLevel == 0 || aIsOddLevel == 1, "aIsOddLevel should be 0 or 1");
nsresult rv = NS_OK;
PRBool doReverse = PR_FALSE;
if (aIsBidiSystem) {
if ( (CHARTYPE_IS_RTL(aCharType)) ^ (aIsOddLevel) )
doReverse = PR_TRUE;
}
else {
if (aIsOddLevel)
doReverse = PR_TRUE;
}
if (doReverse) {
PRInt32 newLen;
if (mBuffer.Length() < aTextLength) {
mBuffer.SetLength(aTextLength);
}
PRUnichar* buffer = NS_CONST_CAST(PRUnichar*, mBuffer.get());
if (doReverse) {
rv = mBidiEngine->WriteReverse(aText, aTextLength, buffer,
NSBIDI_DO_MIRRORING, &newLen);
if (NS_SUCCEEDED(rv) ) {
aTextLength = newLen;
memcpy(aText, buffer, aTextLength * sizeof(PRUnichar) );
}
}
}
return rv;
}
#endif // IBMBIDI

View File

@ -2254,23 +2254,17 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
#ifdef IBMBIDI
PRBool isRightToLeftOnBidiPlatform = PR_FALSE;
PRBool isBidiSystem = PR_FALSE;
PRUint32 hints = 0;
aRenderingContext.GetHints(hints);
PRBool bidiEnabled;
nsCharType charType = eCharType_LeftToRight;
aPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING);
aPresContext->SetIsBidiSystem(isBidiSystem);
aPresContext->GetIsBidiSystem(isBidiSystem);
GetBidiProperty(aPresContext, nsLayoutAtoms::embeddingLevel, (void**) &level,sizeof(level));
GetBidiProperty(aPresContext, nsLayoutAtoms::charType, (void**) &charType,sizeof(charType));
if (isBidiSystem && (eCharType_RightToLeft == charType) ) {
isRightToLeftOnBidiPlatform = PR_TRUE;
}
else if (eCharType_RightToLeftArabic == charType) {
isRightToLeftOnBidiPlatform = (hints & NS_RENDERING_HINT_ARABIC_SHAPING);
}
isRightToLeftOnBidiPlatform = (isBidiSystem &&
(eCharType_RightToLeft == charType ||
eCharType_RightToLeftArabic == charType));
if (isRightToLeftOnBidiPlatform) {
// indicate that the platform should use its native
// capabilities to reorder the text with right-to-left
@ -2280,11 +2274,12 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
nsBidiPresUtils* bidiUtils;
aPresContext->GetBidiUtils(&bidiUtils);
if (bidiUtils) {
bidiUtils->FormatUnicodeText(aPresContext, text, textLength,
charType, level & 1, isBidiSystem);
PRInt32 rememberTextLength = textLength;
bidiUtils->ReorderUnicodeText(text, textLength,
charType, level & 1, isBidiSystem);
NS_ASSERTION(rememberTextLength == textLength, "Bidi formatting changed text length");
}
}
if (0 < textLength) { // textLength might change due to the bidi formattimg
#endif // IBMBIDI
if (!displaySelection || !isSelected ) //draw text normally
{
@ -2434,7 +2429,6 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
}
}
#ifdef IBMBIDI
}
if (isRightToLeftOnBidiPlatform) {
// indicate that future text should not be reordered with
// right-to-left base direction
@ -2510,7 +2504,16 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
PRInt32 textLength;
PRInt32 numSpaces;
#ifdef IBMBIDI
// Simulate a non-Bidi system for char by char measuring
PRBool isBidiSystem = PR_FALSE;
aPresContext->GetIsBidiSystem(isBidiSystem);
aPresContext->SetIsBidiSystem(PR_FALSE);
#endif
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
#ifdef IBMBIDI
aPresContext->SetIsBidiSystem(isBidiSystem);
#endif
if (textLength <= 0) {
// If we've already assigned aNewContent, make sure to 0 it out here.
// aNewContent is undefined in the case that we return a failure,
@ -2940,9 +2943,17 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
nsTextTransformer tx(lb, nsnull, aPresContext);
PRInt32 numSpaces;
#ifdef IBMBIDI
// Simulate a non-Bidi system for char by char painting
PRBool isBidiSystem = PR_FALSE;
aPresContext->GetIsBidiSystem(isBidiSystem);
aPresContext->SetIsBidiSystem(PR_FALSE);
#endif
numSpaces = PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
&paintBuffer, &textLength);
#ifdef IBMBIDI
aPresContext->SetIsBidiSystem(isBidiSystem);
#endif
PRInt32* ip = indexBuffer.mBuffer;
PRUnichar* text = paintBuffer.mBuffer;
@ -2963,12 +2974,13 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
(void**) &level,sizeof(level));
GetBidiProperty(aPresContext, nsLayoutAtoms::charType,
(void**) &charType,sizeof(charType));
PRInt32 rememberTextLength = textLength;
// Since we paint char by char, handle the text like on non-bidi platform
bidiUtils->FormatUnicodeText(aPresContext, text, textLength, charType,
level & 1, PR_FALSE);
bidiUtils->ReorderUnicodeText(text, textLength, charType,
level & 1, PR_FALSE);
NS_ASSERTION(rememberTextLength == textLength, "Bidi formatting changed text length");
}
}
if (0 != textLength) { // textLength might change due to the bidi formattimg
#endif // IBMBIDI
ComputeExtraJustificationSpacing(aRenderingContext, aTextStyle, text, textLength, numSpaces);
if (!displaySelection || !isSelected) {
@ -3066,9 +3078,6 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
delete details;
}
}
#ifdef IBMBIDI
}
#endif // IBMBIDI
}
}
@ -5186,6 +5195,18 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
if ( (mContentLength > 0) && (mState & NS_FRAME_IS_BIDI) ) {
startingOffset = mContentOffset;
}
PRBool bidiEnabled;
aPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
nsCharType charType = eCharType_LeftToRight;
PRUint32 hints = 0;
aReflowState.rendContext->GetHints(hints);
GetBidiProperty(aPresContext, nsLayoutAtoms::charType, (void**)&charType, sizeof(charType));
PRBool isBidiSystem = (eCharType_RightToLeftArabic == charType) ?
(hints & NS_RENDERING_HINT_ARABIC_SHAPING) :
(hints & NS_RENDERING_HINT_BIDI_REORDERING);
aPresContext->SetIsBidiSystem(isBidiSystem);
}
#endif //IBMBIDI
nsLineLayout& lineLayout = *aReflowState.mLineLayout;
TextStyle ts(aPresContext, *aReflowState.rendContext, mStyleContext);

View File

@ -49,6 +49,9 @@
#include "nsICaseConversion.h"
#include "prenv.h"
#include "nsIPref.h"
#ifdef IBMBIDI
#include "nsLayoutAtoms.h"
#endif
PRPackedBool nsTextTransformer::sWordSelectPrefInited = PR_FALSE;
@ -176,6 +179,9 @@ nsTextTransformer::nsTextTransformer(nsILineBreaker* aLineBreaker,
aPresContext->
GetLanguageSpecificTransformType(&mLanguageSpecificTransformType);
#ifdef IBMBIDI
mPresContext = aPresContext;
#endif
if (aLineBreaker == nsnull && aWordBreaker == nsnull )
NS_ASSERTION(0, "invalid creation of nsTextTransformer");
@ -199,6 +205,22 @@ nsTextTransformer::Init(nsIFrame* aFrame,
PRInt32 aStartingOffset,
PRBool aLeaveAsAscii)
{
#ifdef IBMBIDI
PRBool bidiEnabled;
mPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
PRBool isBidiSystem;
aFrame->GetBidiProperty(mPresContext, nsLayoutAtoms::charType,
(void**)&mCharType, sizeof(mCharType));
mPresContext->GetIsBidiSystem(isBidiSystem);
if (mCharType == eCharType_RightToLeftArabic && !isBidiSystem) {
SetNeedsArabicShaping(PR_TRUE);
}
SetNeedsNumericShaping(PR_TRUE);
}
#endif
// Get the contents text content
nsresult rv;
nsCOMPtr<nsITextContent> tc = do_QueryInterface(aContent, &rv);
@ -987,6 +1009,14 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
eLanguageSpecificTransformType_None) {
LanguageSpecificTransform(result, wordLen, aWasTransformed);
}
#ifdef IBMBIDI
if (NeedsArabicShaping()) {
DoArabicShaping(result, wordLen, aWasTransformed);
}
if (NeedsNumericShaping()) {
DoNumericShaping(result, wordLen, aWasTransformed);
}
#endif
}
}
@ -1359,8 +1389,94 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
return result;
}
//----------------------------------------------------------------------
#ifdef IBMBIDI
void
nsTextTransformer::DoArabicShaping(PRUnichar* aText,
PRInt32& aTextLength,
PRBool* aWasTransformed)
{
if (aTextLength <= 0)
return;
PRInt32 newLen;
PRBool isVisual;
mPresContext->IsVisualMode(isVisual);
nsAutoString buf;
buf.SetLength(aTextLength);
PRUnichar* buffer = (PRUnichar*)buf.get();
ArabicShaping(aText, buf.Length(), buffer, (PRUint32 *)&newLen, !isVisual, !isVisual);
PRUnichar *source = buffer;
PRUnichar *target = aText;
for (PRInt32 i = 0; i < newLen; i++) {
if (*source == CH_ZWNJ || *source == CH_ZWJ) {
source++;
}
else {
*target++ = *source++;
}
}
aTextLength = target - aText;
*aWasTransformed = PR_TRUE;
}
void
nsTextTransformer::DoNumericShaping(PRUnichar* aText,
PRInt32& aTextLength,
PRBool* aWasTransformed)
{
if (aTextLength <= 0)
return;
PRUint32 bidiOptions;
mPresContext->GetBidi(&bidiOptions);
switch (GET_BIDI_OPTION_NUMERAL(bidiOptions)) {
case IBMBIDI_NUMERAL_HINDI:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
break;
case IBMBIDI_NUMERAL_ARABIC:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
case IBMBIDI_NUMERAL_REGULAR:
switch (mCharType) {
case eCharType_EuropeanNumber:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
case eCharType_ArabicNumber:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
break;
default:
break;
}
break;
case IBMBIDI_NUMERAL_HINDICONTEXT:
if (((GET_BIDI_OPTION_DIRECTION(bidiOptions)==IBMBIDI_TEXTDIRECTION_RTL) &&
(IS_ARABIC_DIGIT (aText[0]))) ||
(eCharType_ArabicNumber == mCharType))
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
else if (eCharType_EuropeanNumber == mCharType)
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
default:
break;
}
}
#endif
//----------------------------------------------------------------------
// Self test logic for this class. This will (hopefully) make sure
// that the forward and backward word iterator methods continue to
// function as people change things...

View File

@ -40,6 +40,10 @@
#include "nsTextFragment.h"
#include "nsISupports.h"
#include "nsIPresContext.h"
#ifdef IBMBIDI
#include "nsBidi.h"
#include "nsBidiUtils.h"
#endif
class nsIContent;
class nsIFrame;
@ -81,6 +85,14 @@ class nsIWordBreaker;
// The text in the transform buffer is ascii
#define NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII 4
#ifdef IBMBIDI
// The text in the transform buffer needs Arabic shaping
#define NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING 8
// The text in the transform buffer needs numeric shaping
#define NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING 16
#endif
// A growable text buffer that tries to avoid using malloc by having a
// builtin buffer. Ideally used as an automatic variable.
class nsAutoTextBuffer {
@ -183,20 +195,34 @@ public:
// Returns PR_TRUE if the LEAVE_AS_ASCII flag is set
PRBool LeaveAsAscii() const {
return (mFlags & NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII) != 0;
}
// Returns PR_TRUE if any of the characters are multibyte (greater than 127)
PRBool HasMultibyte() const {
return (mFlags & NS_TEXT_TRANSFORMER_HAS_MULTIBYTE) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_HAS_MULTIBYTE) != 0;
}
// Returns PR_TRUE if the text in the transform bufer is ascii (i.e., it
// doesn't contain any multibyte characters)
PRBool TransformedTextIsAscii() const {
return (mFlags & NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII) != 0;
}
#ifdef IBMBIDI
// Returns PR_TRUE if the text in the transform bufer needs Arabic
// shaping
PRBool NeedsArabicShaping() const {
return (mFlags & NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING) != 0;
}
// Returns PR_TRUE if the text in the transform bufer needs numeric
// shaping
PRBool NeedsNumericShaping() const {
return (mFlags & NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING) != 0;
}
#endif
// Set or clears the LEAVE_AS_ASCII bit
void SetLeaveAsAscii(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII :
@ -215,6 +241,20 @@ public:
mFlags &= (~NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII);
}
#ifdef IBMBIDI
// Set or clears the NS_TEXT_TRANSFORMER_TRANSFORMED_DO_ARABIC_SHAPING bit
void SetNeedsArabicShaping(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING :
mFlags &= (~NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING);
}
// Set or clears the NS_TEXT_TRANSFORMER_TRANSFORMED_DO_NUMERIC_SHAPING bit
void SetNeedsNumericShaping(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING :
mFlags &= (~NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING);
}
#endif
PRUnichar* GetWordBuffer() {
return mTransformBuf.GetBuffer();
}
@ -257,6 +297,12 @@ protected:
void LanguageSpecificTransform(PRUnichar* aText, PRInt32 aLen,
PRBool* aWasTransformed);
#ifdef IBMBIDI
void DoArabicShaping(PRUnichar* aText, PRInt32& aTextLength, PRBool* aWasTransformed);
void DoNumericShaping(PRUnichar* aText, PRInt32& aTextLength, PRBool* aWasTransformed);
#endif
// The text fragment that we are looking at
const nsTextFragment* mFrag;
@ -276,6 +322,11 @@ protected:
nsLanguageSpecificTransformType mLanguageSpecificTransformType;
#ifdef IBMBIDI
nsIPresContext* mPresContext;
nsCharType mCharType;
#endif
// Buffer used to hold the transformed words from GetNextWord or
// GetPrevWord
nsAutoTextBuffer mTransformBuf;

View File

@ -2254,23 +2254,17 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
#ifdef IBMBIDI
PRBool isRightToLeftOnBidiPlatform = PR_FALSE;
PRBool isBidiSystem = PR_FALSE;
PRUint32 hints = 0;
aRenderingContext.GetHints(hints);
PRBool bidiEnabled;
nsCharType charType = eCharType_LeftToRight;
aPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
isBidiSystem = (hints & NS_RENDERING_HINT_BIDI_REORDERING);
aPresContext->SetIsBidiSystem(isBidiSystem);
aPresContext->GetIsBidiSystem(isBidiSystem);
GetBidiProperty(aPresContext, nsLayoutAtoms::embeddingLevel, (void**) &level,sizeof(level));
GetBidiProperty(aPresContext, nsLayoutAtoms::charType, (void**) &charType,sizeof(charType));
if (isBidiSystem && (eCharType_RightToLeft == charType) ) {
isRightToLeftOnBidiPlatform = PR_TRUE;
}
else if (eCharType_RightToLeftArabic == charType) {
isRightToLeftOnBidiPlatform = (hints & NS_RENDERING_HINT_ARABIC_SHAPING);
}
isRightToLeftOnBidiPlatform = (isBidiSystem &&
(eCharType_RightToLeft == charType ||
eCharType_RightToLeftArabic == charType));
if (isRightToLeftOnBidiPlatform) {
// indicate that the platform should use its native
// capabilities to reorder the text with right-to-left
@ -2280,11 +2274,12 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
nsBidiPresUtils* bidiUtils;
aPresContext->GetBidiUtils(&bidiUtils);
if (bidiUtils) {
bidiUtils->FormatUnicodeText(aPresContext, text, textLength,
charType, level & 1, isBidiSystem);
PRInt32 rememberTextLength = textLength;
bidiUtils->ReorderUnicodeText(text, textLength,
charType, level & 1, isBidiSystem);
NS_ASSERTION(rememberTextLength == textLength, "Bidi formatting changed text length");
}
}
if (0 < textLength) { // textLength might change due to the bidi formattimg
#endif // IBMBIDI
if (!displaySelection || !isSelected ) //draw text normally
{
@ -2434,7 +2429,6 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
}
}
#ifdef IBMBIDI
}
if (isRightToLeftOnBidiPlatform) {
// indicate that future text should not be reordered with
// right-to-left base direction
@ -2510,7 +2504,16 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
PRInt32 textLength;
PRInt32 numSpaces;
#ifdef IBMBIDI
// Simulate a non-Bidi system for char by char measuring
PRBool isBidiSystem = PR_FALSE;
aPresContext->GetIsBidiSystem(isBidiSystem);
aPresContext->SetIsBidiSystem(PR_FALSE);
#endif
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
#ifdef IBMBIDI
aPresContext->SetIsBidiSystem(isBidiSystem);
#endif
if (textLength <= 0) {
// If we've already assigned aNewContent, make sure to 0 it out here.
// aNewContent is undefined in the case that we return a failure,
@ -2940,9 +2943,17 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
nsTextTransformer tx(lb, nsnull, aPresContext);
PRInt32 numSpaces;
#ifdef IBMBIDI
// Simulate a non-Bidi system for char by char painting
PRBool isBidiSystem = PR_FALSE;
aPresContext->GetIsBidiSystem(isBidiSystem);
aPresContext->SetIsBidiSystem(PR_FALSE);
#endif
numSpaces = PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
&paintBuffer, &textLength);
#ifdef IBMBIDI
aPresContext->SetIsBidiSystem(isBidiSystem);
#endif
PRInt32* ip = indexBuffer.mBuffer;
PRUnichar* text = paintBuffer.mBuffer;
@ -2963,12 +2974,13 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
(void**) &level,sizeof(level));
GetBidiProperty(aPresContext, nsLayoutAtoms::charType,
(void**) &charType,sizeof(charType));
PRInt32 rememberTextLength = textLength;
// Since we paint char by char, handle the text like on non-bidi platform
bidiUtils->FormatUnicodeText(aPresContext, text, textLength, charType,
level & 1, PR_FALSE);
bidiUtils->ReorderUnicodeText(text, textLength, charType,
level & 1, PR_FALSE);
NS_ASSERTION(rememberTextLength == textLength, "Bidi formatting changed text length");
}
}
if (0 != textLength) { // textLength might change due to the bidi formattimg
#endif // IBMBIDI
ComputeExtraJustificationSpacing(aRenderingContext, aTextStyle, text, textLength, numSpaces);
if (!displaySelection || !isSelected) {
@ -3066,9 +3078,6 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
delete details;
}
}
#ifdef IBMBIDI
}
#endif // IBMBIDI
}
}
@ -5186,6 +5195,18 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
if ( (mContentLength > 0) && (mState & NS_FRAME_IS_BIDI) ) {
startingOffset = mContentOffset;
}
PRBool bidiEnabled;
aPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
nsCharType charType = eCharType_LeftToRight;
PRUint32 hints = 0;
aReflowState.rendContext->GetHints(hints);
GetBidiProperty(aPresContext, nsLayoutAtoms::charType, (void**)&charType, sizeof(charType));
PRBool isBidiSystem = (eCharType_RightToLeftArabic == charType) ?
(hints & NS_RENDERING_HINT_ARABIC_SHAPING) :
(hints & NS_RENDERING_HINT_BIDI_REORDERING);
aPresContext->SetIsBidiSystem(isBidiSystem);
}
#endif //IBMBIDI
nsLineLayout& lineLayout = *aReflowState.mLineLayout;
TextStyle ts(aPresContext, *aReflowState.rendContext, mStyleContext);

View File

@ -49,6 +49,9 @@
#include "nsICaseConversion.h"
#include "prenv.h"
#include "nsIPref.h"
#ifdef IBMBIDI
#include "nsLayoutAtoms.h"
#endif
PRPackedBool nsTextTransformer::sWordSelectPrefInited = PR_FALSE;
@ -176,6 +179,9 @@ nsTextTransformer::nsTextTransformer(nsILineBreaker* aLineBreaker,
aPresContext->
GetLanguageSpecificTransformType(&mLanguageSpecificTransformType);
#ifdef IBMBIDI
mPresContext = aPresContext;
#endif
if (aLineBreaker == nsnull && aWordBreaker == nsnull )
NS_ASSERTION(0, "invalid creation of nsTextTransformer");
@ -199,6 +205,22 @@ nsTextTransformer::Init(nsIFrame* aFrame,
PRInt32 aStartingOffset,
PRBool aLeaveAsAscii)
{
#ifdef IBMBIDI
PRBool bidiEnabled;
mPresContext->GetBidiEnabled(&bidiEnabled);
if (bidiEnabled) {
PRBool isBidiSystem;
aFrame->GetBidiProperty(mPresContext, nsLayoutAtoms::charType,
(void**)&mCharType, sizeof(mCharType));
mPresContext->GetIsBidiSystem(isBidiSystem);
if (mCharType == eCharType_RightToLeftArabic && !isBidiSystem) {
SetNeedsArabicShaping(PR_TRUE);
}
SetNeedsNumericShaping(PR_TRUE);
}
#endif
// Get the contents text content
nsresult rv;
nsCOMPtr<nsITextContent> tc = do_QueryInterface(aContent, &rv);
@ -987,6 +1009,14 @@ nsTextTransformer::GetNextWord(PRBool aInWord,
eLanguageSpecificTransformType_None) {
LanguageSpecificTransform(result, wordLen, aWasTransformed);
}
#ifdef IBMBIDI
if (NeedsArabicShaping()) {
DoArabicShaping(result, wordLen, aWasTransformed);
}
if (NeedsNumericShaping()) {
DoNumericShaping(result, wordLen, aWasTransformed);
}
#endif
}
}
@ -1359,8 +1389,94 @@ nsTextTransformer::GetPrevWord(PRBool aInWord,
return result;
}
//----------------------------------------------------------------------
#ifdef IBMBIDI
void
nsTextTransformer::DoArabicShaping(PRUnichar* aText,
PRInt32& aTextLength,
PRBool* aWasTransformed)
{
if (aTextLength <= 0)
return;
PRInt32 newLen;
PRBool isVisual;
mPresContext->IsVisualMode(isVisual);
nsAutoString buf;
buf.SetLength(aTextLength);
PRUnichar* buffer = (PRUnichar*)buf.get();
ArabicShaping(aText, buf.Length(), buffer, (PRUint32 *)&newLen, !isVisual, !isVisual);
PRUnichar *source = buffer;
PRUnichar *target = aText;
for (PRInt32 i = 0; i < newLen; i++) {
if (*source == CH_ZWNJ || *source == CH_ZWJ) {
source++;
}
else {
*target++ = *source++;
}
}
aTextLength = target - aText;
*aWasTransformed = PR_TRUE;
}
void
nsTextTransformer::DoNumericShaping(PRUnichar* aText,
PRInt32& aTextLength,
PRBool* aWasTransformed)
{
if (aTextLength <= 0)
return;
PRUint32 bidiOptions;
mPresContext->GetBidi(&bidiOptions);
switch (GET_BIDI_OPTION_NUMERAL(bidiOptions)) {
case IBMBIDI_NUMERAL_HINDI:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
break;
case IBMBIDI_NUMERAL_ARABIC:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
case IBMBIDI_NUMERAL_REGULAR:
switch (mCharType) {
case eCharType_EuropeanNumber:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
case eCharType_ArabicNumber:
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
break;
default:
break;
}
break;
case IBMBIDI_NUMERAL_HINDICONTEXT:
if (((GET_BIDI_OPTION_DIRECTION(bidiOptions)==IBMBIDI_TEXTDIRECTION_RTL) &&
(IS_ARABIC_DIGIT (aText[0]))) ||
(eCharType_ArabicNumber == mCharType))
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_HINDI);
else if (eCharType_EuropeanNumber == mCharType)
HandleNumbers(aText, aTextLength, IBMBIDI_NUMERAL_ARABIC);
break;
default:
break;
}
}
#endif
//----------------------------------------------------------------------
// Self test logic for this class. This will (hopefully) make sure
// that the forward and backward word iterator methods continue to
// function as people change things...

View File

@ -40,6 +40,10 @@
#include "nsTextFragment.h"
#include "nsISupports.h"
#include "nsIPresContext.h"
#ifdef IBMBIDI
#include "nsBidi.h"
#include "nsBidiUtils.h"
#endif
class nsIContent;
class nsIFrame;
@ -81,6 +85,14 @@ class nsIWordBreaker;
// The text in the transform buffer is ascii
#define NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII 4
#ifdef IBMBIDI
// The text in the transform buffer needs Arabic shaping
#define NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING 8
// The text in the transform buffer needs numeric shaping
#define NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING 16
#endif
// A growable text buffer that tries to avoid using malloc by having a
// builtin buffer. Ideally used as an automatic variable.
class nsAutoTextBuffer {
@ -183,20 +195,34 @@ public:
// Returns PR_TRUE if the LEAVE_AS_ASCII flag is set
PRBool LeaveAsAscii() const {
return (mFlags & NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII) != 0;
}
// Returns PR_TRUE if any of the characters are multibyte (greater than 127)
PRBool HasMultibyte() const {
return (mFlags & NS_TEXT_TRANSFORMER_HAS_MULTIBYTE) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_HAS_MULTIBYTE) != 0;
}
// Returns PR_TRUE if the text in the transform bufer is ascii (i.e., it
// doesn't contain any multibyte characters)
PRBool TransformedTextIsAscii() const {
return (mFlags & NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII) ? PR_TRUE : PR_FALSE;
return (mFlags & NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII) != 0;
}
#ifdef IBMBIDI
// Returns PR_TRUE if the text in the transform bufer needs Arabic
// shaping
PRBool NeedsArabicShaping() const {
return (mFlags & NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING) != 0;
}
// Returns PR_TRUE if the text in the transform bufer needs numeric
// shaping
PRBool NeedsNumericShaping() const {
return (mFlags & NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING) != 0;
}
#endif
// Set or clears the LEAVE_AS_ASCII bit
void SetLeaveAsAscii(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_LEAVE_AS_ASCII :
@ -215,6 +241,20 @@ public:
mFlags &= (~NS_TEXT_TRANSFORMER_TRANSFORMED_TEXT_IS_ASCII);
}
#ifdef IBMBIDI
// Set or clears the NS_TEXT_TRANSFORMER_TRANSFORMED_DO_ARABIC_SHAPING bit
void SetNeedsArabicShaping(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING :
mFlags &= (~NS_TEXT_TRANSFORMER_DO_ARABIC_SHAPING);
}
// Set or clears the NS_TEXT_TRANSFORMER_TRANSFORMED_DO_NUMERIC_SHAPING bit
void SetNeedsNumericShaping(PRBool aValue) {
aValue ? mFlags |= NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING :
mFlags &= (~NS_TEXT_TRANSFORMER_DO_NUMERIC_SHAPING);
}
#endif
PRUnichar* GetWordBuffer() {
return mTransformBuf.GetBuffer();
}
@ -257,6 +297,12 @@ protected:
void LanguageSpecificTransform(PRUnichar* aText, PRInt32 aLen,
PRBool* aWasTransformed);
#ifdef IBMBIDI
void DoArabicShaping(PRUnichar* aText, PRInt32& aTextLength, PRBool* aWasTransformed);
void DoNumericShaping(PRUnichar* aText, PRInt32& aTextLength, PRBool* aWasTransformed);
#endif
// The text fragment that we are looking at
const nsTextFragment* mFrag;
@ -276,6 +322,11 @@ protected:
nsLanguageSpecificTransformType mLanguageSpecificTransformType;
#ifdef IBMBIDI
nsIPresContext* mPresContext;
nsCharType mCharType;
#endif
// Buffer used to hold the transformed words from GetNextWord or
// GetPrevWord
nsAutoTextBuffer mTransformBuf;