Bug 1100071 patch 2: add macros for common tests whether bidi level is odd and whether two bidi levels have the same parity, r=dholbert

This commit is contained in:
Simon Montagu 2014-11-20 12:45:22 +02:00
parent aafee71bb6
commit ad766a1fcb
10 changed files with 95 additions and 68 deletions

View File

@ -3253,7 +3253,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
mFontgrp->UpdateUserFonts(); // ensure user font generation is current
// adjust flags for current direction run
uint32_t flags = mTextRunFlags;
if (direction & 1) {
if (direction == NSBIDI_RTL) {
flags |= gfxTextRunFactory::TEXT_IS_RTL;
} else {
flags &= ~gfxTextRunFactory::TEXT_IS_RTL;

View File

@ -45,6 +45,25 @@ enum nsCharType {
*/
typedef enum nsCharType nsCharType;
/**
* Find the direction of an embedding level or paragraph level set by
* the Unicode Bidi Algorithm. (Even levels are left-to-right, odd
* levels right-to-left.
*/
#define IS_LEVEL_RTL(level) (((level) & 1) == 1)
/**
* Check whether two bidi levels have the same parity and thus the same
* directionality
*/
#define IS_SAME_DIRECTION(level1, level2) (((level1 ^ level2) & 1) == 0)
/**
* Convert from nsBidiLevel to nsBidiDirection
*/
#define DIRECTION_FROM_LEVEL(level) ((IS_LEVEL_RTL(level)) \
? NSBIDI_RTL : NSBIDI_LTR)
/**
* definitions of bidirection character types by category
*/

View File

@ -361,7 +361,7 @@ struct BidiLineData {
nsBidiLevel level = nsBidiPresUtils::GetFrameEmbeddingLevel(frame);
mLevels.AppendElement(level);
mIndexMap.AppendElement(0);
if (level & 1) {
if (IS_LEVEL_RTL(level)) {
hasRTLFrames = true;
}
}
@ -1539,7 +1539,7 @@ nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
for (; index != limit; index += step) {
frame = aBld->VisualFrameAt(index);
RepositionFrame(frame,
!(aBld->mLevels[aBld->mIndexMap[index]] & 1),
!(IS_LEVEL_RTL(aBld->mLevels[aBld->mIndexMap[index]])),
start,
&continuationStates,
aLineWM,
@ -1675,9 +1675,9 @@ nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
nsresult
nsBidiPresUtils::FormatUnicodeText(nsPresContext* aPresContext,
char16_t* aText,
int32_t& aTextLength,
nsCharType aCharType,
bool aIsOddLevel)
int32_t& aTextLength,
nsCharType aCharType,
nsBidiDirection aDir)
{
nsresult rv = NS_OK;
// ahmed
@ -1877,8 +1877,7 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
uint32_t visualStart = 0;
uint8_t charType;
uint8_t prevType = eCharType_LeftToRight;
nsBidiLevel level;
for(int nPosResolve=0; nPosResolve < aPosResolveCount; ++nPosResolve)
{
aPosResolve[nPosResolve].visualIndex = kNotFound;
@ -1892,10 +1891,12 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
if (NS_FAILED(rv))
return rv;
nsBidiLevel level;
rv = aBidiEngine->GetLogicalRun(start, &limit, &level);
if (NS_FAILED(rv))
return rv;
dir = DIRECTION_FROM_LEVEL(level);
int32_t subRunLength = limit - start;
int32_t lineOffset = start;
int32_t typeLimit = std::min(limit, aLength);
@ -1914,8 +1915,8 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
* x-coordinate of the end of the run for the start of the next run.
*/
if (level & 1) {
aprocessor.SetText(aText + start, subRunLength, nsBidiDirection(level & 1));
if (dir == NSBIDI_RTL) {
aprocessor.SetText(aText + start, subRunLength, dir);
width = aprocessor.GetWidth();
xOffset += width;
xEndRun = xOffset;
@ -1925,18 +1926,18 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
// CalculateCharType can increment subRunCount if the run
// contains mixed character types
CalculateCharType(aBidiEngine, aText, lineOffset, typeLimit, subRunLimit, subRunLength, subRunCount, charType, prevType);
nsAutoString runVisualText;
runVisualText.Assign(aText + start, subRunLength);
if (int32_t(runVisualText.Length()) < subRunLength)
return NS_ERROR_OUT_OF_MEMORY;
FormatUnicodeText(aPresContext, runVisualText.BeginWriting(), subRunLength,
(nsCharType)charType, level & 1);
FormatUnicodeText(aPresContext, runVisualText.BeginWriting(),
subRunLength, (nsCharType)charType, dir);
aprocessor.SetText(runVisualText.get(), subRunLength, nsBidiDirection(level & 1));
aprocessor.SetText(runVisualText.get(), subRunLength, dir);
width = aprocessor.GetWidth();
totalWidth += width;
if (level & 1) {
if (dir == NSBIDI_RTL) {
xOffset -= width;
}
if (aMode == MODE_DRAW) {
@ -2007,7 +2008,7 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
// The position in the text where this run's "left part" begins.
const char16_t* visualLeftPart;
const char16_t* visualRightSide;
if (level & 1) {
if (dir == NSBIDI_RTL) {
// One day, son, this could all be replaced with mBidiEngine.GetVisualIndex ...
posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start));
// Skipping to the "left part".
@ -2024,16 +2025,16 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
}
// The delta between the start of the run and the left part's end.
int32_t visualLeftLength = posResolve->visualIndex - visualStart;
aprocessor.SetText(visualLeftPart, visualLeftLength, nsBidiDirection(level & 1));
aprocessor.SetText(visualLeftPart, visualLeftLength, dir);
subWidth = aprocessor.GetWidth();
aprocessor.SetText(visualRightSide, visualLeftLength + 1, nsBidiDirection(level & 1));
aprocessor.SetText(visualRightSide, visualLeftLength + 1, dir);
posResolve->visualLeftTwips = xOffset + subWidth;
posResolve->visualWidth = aprocessor.GetWidth() - subWidth;
}
}
}
if (!(level & 1)) {
if (dir == NSBIDI_LTR) {
xOffset += width;
}
@ -2042,10 +2043,10 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
subRunLimit = typeLimit;
subRunLength = typeLimit - lineOffset;
} // while
if (level & 1) {
if (dir == NSBIDI_RTL) {
xOffset = xEndRun;
}
visualStart += length;
} // for
@ -2075,8 +2076,8 @@ public:
}
virtual void SetText(const char16_t* aText,
int32_t aLength,
nsBidiDirection aDirection) MOZ_OVERRIDE
int32_t aLength,
nsBidiDirection aDirection) MOZ_OVERRIDE
{
mFontMetrics->SetTextRunRTL(aDirection==NSBIDI_RTL);
mText = aText;

View File

@ -107,15 +107,15 @@ public:
* @remark The reason that the function gives a string instead of an index
* is that ProcessText copies and modifies the string passed to it, so
* passing an index would be impossible.
*
*
* @param aText The string of text.
* @param aLength The length of the string of text.
* @param aDirection The direction of the text. The string will never have
* mixed direction.
*/
virtual void SetText(const char16_t* aText,
int32_t aLength,
nsBidiDirection aDirection) = 0;
int32_t aLength,
nsBidiDirection aDirection) = 0;
/**
* Returns the measured width of the text given in SetText. If SetText was
@ -171,11 +171,11 @@ public:
*
* @lina 06/18/2000
*/
static nsresult FormatUnicodeText(nsPresContext* aPresContext,
char16_t* aText,
static nsresult FormatUnicodeText(nsPresContext* aPresContext,
char16_t* aText,
int32_t& aTextLength,
nsCharType aCharType,
bool aIsOddLevel);
nsBidiDirection aDir);
/**
* Reorder plain text using the Unicode Bidi algorithm and send it to

View File

@ -678,8 +678,10 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
aBidiLevel = std::max(aBidiLevel, std::min(levelBefore, levelAfter)); // rule c3
aBidiLevel = std::min(aBidiLevel, std::max(levelBefore, levelAfter)); // rule c4
if (aBidiLevel == levelBefore // rule c1
|| (aBidiLevel > levelBefore && aBidiLevel < levelAfter && !((aBidiLevel ^ levelBefore) & 1)) // rule c5
|| (aBidiLevel < levelBefore && aBidiLevel > levelAfter && !((aBidiLevel ^ levelBefore) & 1))) // rule c9
|| (aBidiLevel > levelBefore && aBidiLevel < levelAfter &&
IS_SAME_DIRECTION(aBidiLevel, levelBefore)) // rule c5
|| (aBidiLevel < levelBefore && aBidiLevel > levelAfter &&
IS_SAME_DIRECTION(aBidiLevel, levelBefore))) // rule c9
{
if (theFrame != frameBefore)
{
@ -708,8 +710,10 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
}
}
else if (aBidiLevel == levelAfter // rule c2
|| (aBidiLevel > levelBefore && aBidiLevel < levelAfter && !((aBidiLevel ^ levelAfter) & 1)) // rule c6
|| (aBidiLevel < levelBefore && aBidiLevel > levelAfter && !((aBidiLevel ^ levelAfter) & 1))) // rule c10
|| (aBidiLevel > levelBefore && aBidiLevel < levelAfter &&
IS_SAME_DIRECTION(aBidiLevel, levelAfter)) // rule c6
|| (aBidiLevel < levelBefore && aBidiLevel > levelAfter &&
IS_SAME_DIRECTION(aBidiLevel, levelAfter))) // rule c10
{
if (theFrame != frameAfter)
{
@ -739,33 +743,33 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
}
}
else if (aBidiLevel > levelBefore && aBidiLevel < levelAfter // rule c7/8
&& !((levelBefore ^ levelAfter) & 1) // before and after have the same parity
&& ((aBidiLevel ^ levelAfter) & 1)) // caret has different parity
&& IS_SAME_DIRECTION(levelBefore, levelAfter) // before and after have the same parity
&& !IS_SAME_DIRECTION(aBidiLevel, levelAfter)) // caret has different parity
{
if (NS_SUCCEEDED(aFrameSelection->GetFrameFromLevel(frameAfter, eDirNext, aBidiLevel, &theFrame)))
{
theFrame->GetOffsets(start, end);
levelAfter = NS_GET_EMBEDDING_LEVEL(theFrame);
if (aBidiLevel & 1) // c8: caret to the right of the rightmost character
theFrameOffset = (levelAfter & 1) ? start : end;
if (IS_LEVEL_RTL(aBidiLevel)) // c8: caret to the right of the rightmost character
theFrameOffset = IS_LEVEL_RTL(levelAfter) ? start : end;
else // c7: caret to the left of the leftmost character
theFrameOffset = (levelAfter & 1) ? end : start;
theFrameOffset = IS_LEVEL_RTL(levelAfter) ? end : start;
}
}
else if (aBidiLevel < levelBefore && aBidiLevel > levelAfter // rule c11/12
&& !((levelBefore ^ levelAfter) & 1) // before and after have the same parity
&& ((aBidiLevel ^ levelAfter) & 1)) // caret has different parity
&& IS_SAME_DIRECTION(levelBefore, levelAfter) // before and after have the same parity
&& !IS_SAME_DIRECTION(aBidiLevel, levelAfter)) // caret has different parity
{
if (NS_SUCCEEDED(aFrameSelection->GetFrameFromLevel(frameBefore, eDirPrevious, aBidiLevel, &theFrame)))
{
theFrame->GetOffsets(start, end);
levelBefore = NS_GET_EMBEDDING_LEVEL(theFrame);
if (aBidiLevel & 1) // c12: caret to the left of the leftmost character
theFrameOffset = (levelBefore & 1) ? end : start;
if (IS_LEVEL_RTL(aBidiLevel)) // c12: caret to the left of the leftmost character
theFrameOffset = IS_LEVEL_RTL(levelBefore) ? end : start;
else // c11: caret to the right of the rightmost character
theFrameOffset = (levelBefore & 1) ? start : end;
theFrameOffset = IS_LEVEL_RTL(levelBefore) ? start : end;
}
}
}
}
}
}

View File

@ -8,6 +8,7 @@
#include "nsRect.h"
#include "nsStyleContext.h"
#include "nsBidiUtils.h"
// If WRITING_MODE_VERTICAL_ENABLED is defined, we will attempt to support
// the vertical writing-mode values; if it is not defined, then
@ -309,11 +310,11 @@ public:
//XXX change uint8_t to UBiDiLevel after bug 924851
void SetDirectionFromBidiLevel(uint8_t level)
{
if (level & 1) {
// odd level, set RTL
if (IS_LEVEL_RTL(level)) {
// set RTL
mWritingMode |= eBidiMask;
} else {
// even level, set LTR
// set LTR
mWritingMode &= ~eBidiMask;
}
}

View File

@ -130,6 +130,11 @@ struct nsContentAndOffset
#define FORCE_SELECTION_UPDATE 1
#define CALC_DEBUG 0
// This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
// because it uses the frame pointer passed in without drilling down to
// the leaf frame.
#define REVERSED_DIRECTION_FRAME(frame) \
(!IS_SAME_DIRECTION(NS_GET_EMBEDDING_LEVEL(frame), NS_GET_BASE_LEVEL(frame)))
#include "nsILineIterator.h"
@ -5910,7 +5915,7 @@ nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
NS_PTR_TO_INT32(Properties().Get(nsIFrame::EmbeddingLevelProperty(),
&hasEmbeddingLevel));
bool isRTL = hasEmbeddingLevel
? (embeddingLevel & 1) == 1
? IS_LEVEL_RTL(embeddingLevel)
: StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
if ((!isRTL && inOffset > newOffset) ||
(isRTL && inOffset <= newOffset)) {
@ -6354,8 +6359,7 @@ nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
// Determine movement direction relative to frame
static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
{
bool isReverseDirection = aVisual ?
(NS_GET_EMBEDDING_LEVEL(frame) & 1) != (NS_GET_BASE_LEVEL(frame) & 1) : false;
bool isReverseDirection = aVisual && REVERSED_DIRECTION_FRAME(frame);
return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
}
@ -6652,7 +6656,7 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame);
// If the direction of the frame on the edge is opposite to that of the line,
// we'll need to drill down to its opposite end, so reverse endOfLine.
if ((embeddingLevel & 1) == !lineIsRTL)
if (IS_LEVEL_RTL(embeddingLevel) == !lineIsRTL)
endOfLine = !endOfLine;
}
} else {
@ -6875,8 +6879,8 @@ nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
if (*framePtr) {
nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr);
if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) ==
(aDirection == eDirPrevious)) {
bool frameIsRTL = IS_LEVEL_RTL(embeddingLevel);
if ((frameIsRTL == lineIsRTL) == (aDirection == eDirPrevious)) {
nsFrame::GetFirstLeaf(presContext, framePtr);
} else {
nsFrame::GetLastLeaf(presContext, framePtr);
@ -6945,11 +6949,9 @@ nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
*aOutOffset = (aDirection == eDirNext) ? 0 : -1;
if (aVisual) {
uint8_t newLevel = NS_GET_EMBEDDING_LEVEL(traversedFrame);
uint8_t newBaseLevel = NS_GET_BASE_LEVEL(traversedFrame);
if ((newLevel & 1) != (newBaseLevel & 1)) // The new frame is reverse-direction, go to the other end
*aOutOffset = -1 - *aOutOffset;
if (aVisual && REVERSED_DIRECTION_FRAME(traversedFrame)) {
// The new frame is reverse-direction, go to the other end
*aOutOffset = -1 - *aOutOffset;
}
*aOutFrame = traversedFrame;
return NS_OK;

View File

@ -367,11 +367,11 @@ nsFrameList::GetPrevVisualFor(nsIFrame* aFrame) const
} else {
// Just get the next or prev sibling, depending on block and frame direction.
nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
if (IS_SAME_DIRECTION(frameEmbeddingLevel, baseLevel)) {
return aFrame ? aFrame->GetPrevSibling() : LastChild();
} else {
return aFrame ? aFrame->GetNextSibling() : mFirstChild;
}
}
}
}
@ -441,7 +441,7 @@ nsFrameList::GetNextVisualFor(nsIFrame* aFrame) const
} else {
// Just get the next or prev sibling, depending on block and frame direction.
nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild);
if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) {
if (IS_SAME_DIRECTION(frameEmbeddingLevel, baseLevel)) {
return aFrame ? aFrame->GetNextSibling() : mFirstChild;
} else {
return aFrame ? aFrame->GetPrevSibling() : LastChild();

View File

@ -876,11 +876,11 @@ nsFrameSelection::MoveCaret(uint32_t aKeycode,
switch (aKeycode){
case nsIDOMKeyEvent::DOM_VK_RIGHT :
InvalidateDesiredX();
pos.mDirection = (baseLevel & 1) ? eDirPrevious : eDirNext;
pos.mDirection = IS_LEVEL_RTL(baseLevel) ? eDirPrevious : eDirNext;
break;
case nsIDOMKeyEvent::DOM_VK_LEFT :
InvalidateDesiredX();
pos.mDirection = (baseLevel & 1) ? eDirNext : eDirPrevious;
pos.mDirection = IS_LEVEL_RTL(baseLevel) ? eDirNext : eDirPrevious;
break;
case nsIDOMKeyEvent::DOM_VK_DELETE :
InvalidateDesiredX();
@ -5833,7 +5833,7 @@ Selection::Modify(const nsAString& aAlter, const nsAString& aDirection,
if (NS_SUCCEEDED(rv) && frame) {
nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(frame);
if (baseLevel & 1) {
if (IS_LEVEL_RTL(baseLevel)) {
if (!visual && keycode == nsIDOMKeyEvent::DOM_VK_RIGHT) {
keycode = nsIDOMKeyEvent::DOM_VK_LEFT;
}
@ -5908,14 +5908,14 @@ Selection::SelectionLanguageChange(bool aLangRTL)
levelAfter = levels.mLevelAfter;
}
if ((levelBefore & 1) == (levelAfter & 1)) {
if (IS_SAME_DIRECTION(levelBefore, levelAfter)) {
// if cursor is between two characters with the same orientation, changing the keyboard language
// must toggle the cursor level between the level of the character with the lowest level
// (if the new language corresponds to the orientation of that character) and this level plus 1
// (if the new language corresponds to the opposite orientation)
if ((level != levelBefore) && (level != levelAfter))
level = std::min(levelBefore, levelAfter);
if ((level & 1) == aLangRTL)
if (IS_LEVEL_RTL(level) == aLangRTL)
mFrameSelection->SetCaretBidiLevel(level);
else
mFrameSelection->SetCaretBidiLevel(level + 1);
@ -5923,7 +5923,7 @@ Selection::SelectionLanguageChange(bool aLangRTL)
else {
// if cursor is between characters with opposite orientations, changing the keyboard language must change
// the cursor level to that of the adjacent character with the orientation corresponding to the new language.
if ((levelBefore & 1) == aLangRTL)
if (IS_LEVEL_RTL(levelBefore) == aLangRTL)
mFrameSelection->SetCaretBidiLevel(levelBefore);
else
mFrameSelection->SetCaretBidiLevel(levelAfter);

View File

@ -2059,7 +2059,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
if (textFlags & nsTextFrameUtils::TEXT_HAS_SHY) {
textFlags |= gfxTextRunFactory::TEXT_ENABLE_HYPHEN_BREAKS;
}
if (mBidiEnabled && (NS_GET_EMBEDDING_LEVEL(firstFrame) & 1)) {
if (mBidiEnabled && (IS_LEVEL_RTL(NS_GET_EMBEDDING_LEVEL(firstFrame)))) {
textFlags |= gfxTextRunFactory::TEXT_IS_RTL;
}
if (mNextRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) {