mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-13 03:24:26 +00:00
Backed out changeset 00c2df3df22f (bug 1157727)
--HG-- extra : rebase_source : d717285c96315da10facb20b157b1a9fa4967b9a
This commit is contained in:
parent
30966e0b67
commit
6c15811d8a
@ -138,6 +138,9 @@ static Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) };
|
||||
nsBidi::nsBidi()
|
||||
{
|
||||
Init();
|
||||
|
||||
mMayAllocateText=true;
|
||||
mMayAllocateRuns=true;
|
||||
}
|
||||
|
||||
nsBidi::~nsBidi()
|
||||
@ -171,11 +174,14 @@ void nsBidi::Init()
|
||||
mLevelsMemory=nullptr;
|
||||
mRunsMemory=nullptr;
|
||||
mIsolatesMemory=nullptr;
|
||||
|
||||
mMayAllocateText=false;
|
||||
mMayAllocateRuns=false;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are allowed to allocate memory if aMemory==nullptr
|
||||
* for each array that we need.
|
||||
* We are allowed to allocate memory if aMemory==nullptr or
|
||||
* aMayAllocate==true for each array that we need.
|
||||
* We also try to grow and shrink memory as needed if we
|
||||
* allocate it.
|
||||
*
|
||||
@ -186,22 +192,29 @@ void nsBidi::Init()
|
||||
* which we know we don't need any more;
|
||||
* is this the best way to do this??
|
||||
*/
|
||||
bool nsBidi::GetMemory(void **aMemory, size_t *aSize, size_t aSizeNeeded)
|
||||
bool nsBidi::GetMemory(void **aMemory, size_t *aSize, bool aMayAllocate, size_t aSizeNeeded)
|
||||
{
|
||||
/* check for existing memory */
|
||||
if(*aMemory==nullptr) {
|
||||
/* we need to allocate memory */
|
||||
*aMemory=malloc(aSizeNeeded);
|
||||
if (*aMemory!=nullptr) {
|
||||
*aSize=aSizeNeeded;
|
||||
return true;
|
||||
} else {
|
||||
*aSize=0;
|
||||
if(!aMayAllocate) {
|
||||
return false;
|
||||
} else {
|
||||
*aMemory=malloc(aSizeNeeded);
|
||||
if (*aMemory!=nullptr) {
|
||||
*aSize=aSizeNeeded;
|
||||
return true;
|
||||
} else {
|
||||
*aSize=0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* there is some memory, is it enough or too much? */
|
||||
if(aSizeNeeded!=*aSize) {
|
||||
if(aSizeNeeded>*aSize && !aMayAllocate) {
|
||||
/* not enough memory, and we must not allocate */
|
||||
return false;
|
||||
} else if(aSizeNeeded!=*aSize && aMayAllocate) {
|
||||
/* we may try to grow or shrink */
|
||||
void *memory=realloc(*aMemory, aSizeNeeded);
|
||||
|
||||
@ -235,7 +248,7 @@ void nsBidi::Free()
|
||||
/* SetPara ------------------------------------------------------------ */
|
||||
|
||||
nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength,
|
||||
nsBidiLevel aParaLevel)
|
||||
nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels)
|
||||
{
|
||||
nsBidiDirection direction;
|
||||
|
||||
@ -289,12 +302,22 @@ nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength,
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* determine explicit levels according to the (Xn) rules */
|
||||
if(GETLEVELSMEMORY(aLength)) {
|
||||
mLevels=mLevelsMemory;
|
||||
ResolveExplicitLevels(&direction);
|
||||
/* are explicit levels specified? */
|
||||
if(aEmbeddingLevels==nullptr) {
|
||||
/* no: determine explicit levels according to the (Xn) rules */\
|
||||
if(GETLEVELSMEMORY(aLength)) {
|
||||
mLevels=mLevelsMemory;
|
||||
ResolveExplicitLevels(&direction);
|
||||
} else {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
/* set BN for all explicit codes, check that all levels are aParaLevel..NSBIDI_MAX_EXPLICIT_LEVEL */
|
||||
mLevels=aEmbeddingLevels;
|
||||
nsresult rv = CheckExplicitLevels(&direction);
|
||||
if(NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate isolate memory */
|
||||
@ -304,7 +327,7 @@ nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength,
|
||||
if (mIsolateCount * sizeof(Isolate) <= mIsolatesSize) {
|
||||
mIsolates = mIsolatesMemory;
|
||||
} else {
|
||||
if (GETISOLATESMEMORY(mIsolateCount)) {
|
||||
if (GETINITIALISOLATESMEMORY(mIsolateCount)) {
|
||||
mIsolates = mIsolatesMemory;
|
||||
} else {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
@ -345,7 +368,7 @@ nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength,
|
||||
* Examples for "insignificant" ones are empty embeddings
|
||||
* LRE-PDF, LRE-RLE-PDF-PDF, etc.
|
||||
*/
|
||||
if(!(mFlags&DIRPROP_FLAG_MULTI_RUNS)) {
|
||||
if(aEmbeddingLevels==nullptr && !(mFlags&DIRPROP_FLAG_MULTI_RUNS)) {
|
||||
ResolveImplicitLevels(0, aLength,
|
||||
GET_LR_FROM_LEVEL(mParaLevel),
|
||||
GET_LR_FROM_LEVEL(mParaLevel));
|
||||
@ -827,6 +850,63 @@ void nsBidi::ResolveExplicitLevels(nsBidiDirection *aDirection)
|
||||
*aDirection = direction;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a pre-specified embedding levels array:
|
||||
*
|
||||
* Adjust the directional properties for overrides (->LEVEL_OVERRIDE),
|
||||
* ignore all explicit codes (X9),
|
||||
* and check all the preset levels.
|
||||
*
|
||||
* Recalculate the flags to have them reflect the real properties
|
||||
* after taking the explicit embeddings into account.
|
||||
*/
|
||||
nsresult nsBidi::CheckExplicitLevels(nsBidiDirection *aDirection)
|
||||
{
|
||||
const DirProp *dirProps=mDirProps;
|
||||
DirProp dirProp;
|
||||
nsBidiLevel *levels=mLevels;
|
||||
int32_t isolateCount = 0;
|
||||
|
||||
int32_t i, length=mLength;
|
||||
Flags flags=0; /* collect all directionalities in the text */
|
||||
nsBidiLevel level, paraLevel=mParaLevel;
|
||||
mIsolateCount = 0;
|
||||
|
||||
for(i=0; i<length; ++i) {
|
||||
level=levels[i];
|
||||
dirProp = dirProps[i];
|
||||
if (dirProp == LRI || dirProp == RLI) {
|
||||
isolateCount++;
|
||||
if (isolateCount > mIsolateCount) {
|
||||
mIsolateCount = isolateCount;
|
||||
}
|
||||
} else if (dirProp == PDI) {
|
||||
isolateCount--;
|
||||
}
|
||||
if(level&NSBIDI_LEVEL_OVERRIDE) {
|
||||
/* keep the override flag in levels[i] but adjust the flags */
|
||||
level&=~NSBIDI_LEVEL_OVERRIDE; /* make the range check below simpler */
|
||||
flags|=DIRPROP_FLAG_O(level);
|
||||
} else {
|
||||
/* set the flags */
|
||||
flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG(dirProp);
|
||||
}
|
||||
if(level<paraLevel || NSBIDI_MAX_EXPLICIT_LEVEL<level) {
|
||||
/* level out of bounds */
|
||||
*aDirection = NSBIDI_LTR;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
if(flags&MASK_EMBEDDING) {
|
||||
flags|=DIRPROP_FLAG_LR(mParaLevel);
|
||||
}
|
||||
|
||||
/* determine if the text is mixed-directional or single-directional */
|
||||
mFlags=flags;
|
||||
*aDirection = DirectionFromFlags(flags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* determine if the text is mixed-directional or single-directional */
|
||||
nsBidiDirection nsBidi::DirectionFromFlags(Flags aFlags)
|
||||
{
|
||||
@ -1254,6 +1334,252 @@ nsresult nsBidi::GetParaLevel(nsBidiLevel* aParaLevel)
|
||||
*aParaLevel = mParaLevel;
|
||||
return NS_OK;
|
||||
}
|
||||
#ifdef FULL_BIDI_ENGINE
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
nsresult nsBidi::GetLength(int32_t* aLength)
|
||||
{
|
||||
*aLength = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* General remarks about the functions in this section:
|
||||
*
|
||||
* These functions deal with the aspects of potentially mixed-directional
|
||||
* text in a single paragraph or in a line of a single paragraph
|
||||
* which has already been processed according to
|
||||
* the Unicode 6.3 Bidi algorithm as defined in
|
||||
* http://www.unicode.org/unicode/reports/tr9/ , version 28,
|
||||
* also described in The Unicode Standard, Version 6.3.0 .
|
||||
*
|
||||
* This means that there is a nsBidi object with a levels
|
||||
* and a dirProps array.
|
||||
* paraLevel and direction are also set.
|
||||
* Only if the length of the text is zero, then levels==dirProps==nullptr.
|
||||
*
|
||||
* The overall directionality of the paragraph
|
||||
* or line is used to bypass the reordering steps if possible.
|
||||
* Even purely RTL text does not need reordering there because
|
||||
* the getLogical/VisualIndex() functions can compute the
|
||||
* index on the fly in such a case.
|
||||
*
|
||||
* The implementation of the access to same-level-runs and of the reordering
|
||||
* do attempt to provide better performance and less memory usage compared to
|
||||
* a direct implementation of especially rule (L2) with an array of
|
||||
* one (32-bit) integer per text character.
|
||||
*
|
||||
* Here, the levels array is scanned as soon as necessary, and a vector of
|
||||
* same-level-runs is created. Reordering then is done on this vector.
|
||||
* For each run of text positions that were resolved to the same level,
|
||||
* only 8 bytes are stored: the first text position of the run and the visual
|
||||
* position behind the run after reordering.
|
||||
* One sign bit is used to hold the directionality of the run.
|
||||
* This is inefficient if there are many very short runs. If the average run
|
||||
* length is <2, then this uses more memory.
|
||||
*
|
||||
* In a further attempt to save memory, the levels array is never changed
|
||||
* after all the resolution rules (Xn, Wn, Nn, In).
|
||||
* Many functions have to consider the field trailingWSStart:
|
||||
* if it is less than length, then there is an implicit trailing run
|
||||
* at the paraLevel,
|
||||
* which is not reflected in the levels array.
|
||||
* This allows a line nsBidi object to use the same levels array as
|
||||
* its paragraph parent object.
|
||||
*
|
||||
* When a nsBidi object is created for a line of a paragraph, then the
|
||||
* paragraph's levels and dirProps arrays are reused by way of setting
|
||||
* a pointer into them, not by copying. This again saves memory and forbids to
|
||||
* change the now shared levels for (L1).
|
||||
*/
|
||||
nsresult nsBidi::SetLine(const nsBidi* aParaBidi, int32_t aStart, int32_t aLimit)
|
||||
{
|
||||
nsBidi* pParent = (nsBidi*)aParaBidi;
|
||||
int32_t length;
|
||||
|
||||
/* check the argument values */
|
||||
if(pParent==nullptr) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
} else if(aStart < 0 || aStart >= aLimit || aLimit > pParent->mLength) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* set members from our aParaBidi parent */
|
||||
length = mLength = aLimit - aStart;
|
||||
mParaLevel=pParent->mParaLevel;
|
||||
|
||||
mRuns=nullptr;
|
||||
mFlags=0;
|
||||
|
||||
mDirProps=pParent->mDirProps+aStart;
|
||||
mLevels=pParent->mLevels+aStart;
|
||||
mRunCount=-1;
|
||||
|
||||
if(pParent->mDirection!=NSBIDI_MIXED) {
|
||||
/* the parent is already trivial */
|
||||
mDirection=pParent->mDirection;
|
||||
|
||||
/*
|
||||
* The parent's levels are all either
|
||||
* implicitly or explicitly ==paraLevel;
|
||||
* do the same here.
|
||||
*/
|
||||
if(pParent->mTrailingWSStart<=aStart) {
|
||||
mTrailingWSStart=0;
|
||||
} else if(pParent->mTrailingWSStart<aLimit) {
|
||||
mTrailingWSStart=pParent->mTrailingWSStart-aStart;
|
||||
} else {
|
||||
mTrailingWSStart=length;
|
||||
}
|
||||
} else {
|
||||
const nsBidiLevel *levels=mLevels;
|
||||
int32_t i, trailingWSStart;
|
||||
nsBidiLevel level;
|
||||
|
||||
SetTrailingWSStart();
|
||||
trailingWSStart=mTrailingWSStart;
|
||||
|
||||
/* recalculate pLineBidi->direction */
|
||||
if(trailingWSStart==0) {
|
||||
/* all levels are at paraLevel */
|
||||
mDirection=(nsBidiDirection)(mParaLevel&1);
|
||||
} else {
|
||||
/* get the level of the first character */
|
||||
level=levels[0]&1;
|
||||
|
||||
/* if there is anything of a different level, then the line is mixed */
|
||||
if(trailingWSStart<length && (mParaLevel&1)!=level) {
|
||||
/* the trailing WS is at paraLevel, which differs from levels[0] */
|
||||
mDirection=NSBIDI_MIXED;
|
||||
} else {
|
||||
/* see if levels[1..trailingWSStart-1] have the same direction as levels[0] and paraLevel */
|
||||
i=1;
|
||||
for(;;) {
|
||||
if(i==trailingWSStart) {
|
||||
/* the direction values match those in level */
|
||||
mDirection=(nsBidiDirection)level;
|
||||
break;
|
||||
} else if((levels[i]&1)!=level) {
|
||||
mDirection=NSBIDI_MIXED;
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(mDirection) {
|
||||
case NSBIDI_LTR:
|
||||
/* make sure paraLevel is even */
|
||||
mParaLevel=(mParaLevel+1)&~1;
|
||||
|
||||
/* all levels are implicitly at paraLevel (important for GetLevels()) */
|
||||
mTrailingWSStart=0;
|
||||
break;
|
||||
case NSBIDI_RTL:
|
||||
/* make sure paraLevel is odd */
|
||||
mParaLevel|=1;
|
||||
|
||||
/* all levels are implicitly at paraLevel (important for GetLevels()) */
|
||||
mTrailingWSStart=0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* handle trailing WS (L1) -------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* SetTrailingWSStart() sets the start index for a trailing
|
||||
* run of WS in the line. This is necessary because we do not modify
|
||||
* the paragraph's levels array that we just point into.
|
||||
* Using trailingWSStart is another form of performing (L1).
|
||||
*
|
||||
* To make subsequent operations easier, we also include the run
|
||||
* before the WS if it is at the paraLevel - we merge the two here.
|
||||
*/
|
||||
void nsBidi::SetTrailingWSStart() {
|
||||
/* mDirection!=NSBIDI_MIXED */
|
||||
|
||||
const DirProp *dirProps=mDirProps;
|
||||
nsBidiLevel *levels=mLevels;
|
||||
int32_t start=mLength;
|
||||
nsBidiLevel paraLevel=mParaLevel;
|
||||
|
||||
/* go backwards across all WS, BN, explicit codes */
|
||||
while(start>0 && DIRPROP_FLAG(dirProps[start-1])&MASK_WS) {
|
||||
--start;
|
||||
}
|
||||
|
||||
/* if the WS run can be merged with the previous run then do so here */
|
||||
while(start>0 && levels[start-1]==paraLevel) {
|
||||
--start;
|
||||
}
|
||||
|
||||
mTrailingWSStart=start;
|
||||
}
|
||||
|
||||
nsresult nsBidi::GetLevelAt(int32_t aCharIndex, nsBidiLevel* aLevel)
|
||||
{
|
||||
/* return paraLevel if in the trailing WS run, otherwise the real level */
|
||||
if(aCharIndex<0 || mLength<=aCharIndex) {
|
||||
*aLevel = 0;
|
||||
} else if(mDirection!=NSBIDI_MIXED || aCharIndex>=mTrailingWSStart) {
|
||||
*aLevel = mParaLevel;
|
||||
} else {
|
||||
*aLevel = mLevels[aCharIndex];
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBidi::GetLevels(nsBidiLevel** aLevels)
|
||||
{
|
||||
int32_t start, length;
|
||||
|
||||
length = mLength;
|
||||
if(length<=0) {
|
||||
*aLevels = nullptr;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
start = mTrailingWSStart;
|
||||
if(start==length) {
|
||||
/* the current levels array reflects the WS run */
|
||||
*aLevels = mLevels;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* After the previous if(), we know that the levels array
|
||||
* has an implicit trailing WS run and therefore does not fully
|
||||
* reflect itself all the levels.
|
||||
* This must be a nsBidi object for a line, and
|
||||
* we need to create a new levels array.
|
||||
*/
|
||||
|
||||
if(GETLEVELSMEMORY(length)) {
|
||||
nsBidiLevel *levels=mLevelsMemory;
|
||||
|
||||
if(start>0 && levels!=mLevels) {
|
||||
memcpy(levels, mLevels, start);
|
||||
}
|
||||
memset(levels+start, mParaLevel, length-start);
|
||||
|
||||
/* this new levels array is set for the line and reflects the WS run */
|
||||
mTrailingWSStart=length;
|
||||
*aLevels=mLevels=levels;
|
||||
return NS_OK;
|
||||
} else {
|
||||
/* out of memory */
|
||||
*aLevels = nullptr;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
#endif // FULL_BIDI_ENGINE
|
||||
|
||||
nsresult nsBidi::GetCharTypeAt(int32_t aCharIndex, nsCharType* pType)
|
||||
{
|
||||
@ -1712,3 +2038,454 @@ bool nsBidi::PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef FULL_BIDI_ENGINE
|
||||
/* API functions for logical<->visual mapping ------------------------------- */
|
||||
|
||||
nsresult nsBidi::GetVisualIndex(int32_t aLogicalIndex, int32_t* aVisualIndex) {
|
||||
int32_t visualIndex = NSBIDI_MAP_NOWHERE;
|
||||
|
||||
if(aLogicalIndex<0 || mLength<=aLogicalIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
} else {
|
||||
/* we can do the trivial cases without the runs array */
|
||||
switch(mDirection) {
|
||||
case NSBIDI_LTR:
|
||||
*aVisualIndex = aLogicalIndex;
|
||||
return NS_OK;
|
||||
case NSBIDI_RTL:
|
||||
*aVisualIndex = mLength-aLogicalIndex-1;
|
||||
return NS_OK;
|
||||
default:
|
||||
if(mRunCount<0 && !GetRuns()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
} else {
|
||||
Run *runs=mRuns;
|
||||
int32_t i, visualStart=0, offset, length;
|
||||
|
||||
/* linear search for the run, search on the visual runs */
|
||||
for (i = 0; i < mRunCount; ++i) {
|
||||
length=runs[i].visualLimit-visualStart;
|
||||
offset=aLogicalIndex-GET_INDEX(runs[i].logicalStart);
|
||||
if(offset>=0 && offset<length) {
|
||||
if(IS_EVEN_RUN(runs[i].logicalStart)) {
|
||||
/* LTR */
|
||||
visualIndex = visualStart + offset;
|
||||
} else {
|
||||
/* RTL */
|
||||
visualIndex = visualStart + length - offset - 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
visualStart+=length;
|
||||
}
|
||||
if (i >= mRunCount) {
|
||||
*aVisualIndex = NSBIDI_MAP_NOWHERE;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*aVisualIndex = visualIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBidi::GetLogicalIndex(int32_t aVisualIndex, int32_t *aLogicalIndex)
|
||||
{
|
||||
if(aVisualIndex<0 || mLength<=aVisualIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* we can do the trivial cases without the runs array */
|
||||
if (mDirection == NSBIDI_LTR) {
|
||||
*aLogicalIndex = aVisualIndex;
|
||||
return NS_OK;
|
||||
} else if (mDirection == NSBIDI_RTL) {
|
||||
*aLogicalIndex = mLength - aVisualIndex - 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if(mRunCount<0 && !GetRuns()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
Run *runs=mRuns;
|
||||
int32_t i, runCount=mRunCount, start;
|
||||
|
||||
if(runCount<=10) {
|
||||
/* linear search for the run */
|
||||
for(i=0; aVisualIndex>=runs[i].visualLimit; ++i) {}
|
||||
} else {
|
||||
/* binary search for the run */
|
||||
int32_t start=0, limit=runCount;
|
||||
|
||||
/* the middle if() will guaranteed find the run, we don't need a loop limit */
|
||||
for(;;) {
|
||||
i=(start+limit)/2;
|
||||
if(aVisualIndex>=runs[i].visualLimit) {
|
||||
start=i+1;
|
||||
} else if(i==0 || aVisualIndex>=runs[i-1].visualLimit) {
|
||||
break;
|
||||
} else {
|
||||
limit=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start=runs[i].logicalStart;
|
||||
if(IS_EVEN_RUN(start)) {
|
||||
/* LTR */
|
||||
/* the offset in runs[i] is aVisualIndex-runs[i-1].visualLimit */
|
||||
if(i>0) {
|
||||
aVisualIndex-=runs[i-1].visualLimit;
|
||||
}
|
||||
*aLogicalIndex = GET_INDEX(start)+aVisualIndex;
|
||||
return NS_OK;
|
||||
} else {
|
||||
/* RTL */
|
||||
*aLogicalIndex = GET_INDEX(start)+runs[i].visualLimit-aVisualIndex-1;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsBidi::GetLogicalMap(int32_t *aIndexMap)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
/* CountRuns() checks for VALID_PARA_OR_LINE */
|
||||
rv = CountRuns(nullptr);
|
||||
if(NS_FAILED(rv)) {
|
||||
return rv;
|
||||
} else if(aIndexMap==nullptr) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
} else {
|
||||
/* fill a logical-to-visual index map using the runs[] */
|
||||
int32_t visualStart, visualLimit, j;
|
||||
int32_t logicalStart;
|
||||
Run *runs = mRuns;
|
||||
if (mLength <= 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
visualStart = 0;
|
||||
for (j = 0; j < mRunCount; ++j) {
|
||||
logicalStart = GET_INDEX(runs[j].logicalStart);
|
||||
visualLimit = runs[j].visualLimit;
|
||||
if (IS_EVEN_RUN(runs[j].logicalStart)) {
|
||||
do { /* LTR */
|
||||
aIndexMap[logicalStart++] = visualStart++;
|
||||
} while (visualStart < visualLimit);
|
||||
} else {
|
||||
logicalStart += visualLimit-visualStart; /* logicalLimit */
|
||||
do { /* RTL */
|
||||
aIndexMap[--logicalStart] = visualStart++;
|
||||
} while (visualStart < visualLimit);
|
||||
}
|
||||
/* visualStart==visualLimit; */
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBidi::GetVisualMap(int32_t *aIndexMap)
|
||||
{
|
||||
int32_t* runCount=nullptr;
|
||||
nsresult rv;
|
||||
|
||||
if(aIndexMap==nullptr) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* CountRuns() checks all of its and our arguments */
|
||||
rv = CountRuns(runCount);
|
||||
if(NS_FAILED(rv)) {
|
||||
return rv;
|
||||
} else {
|
||||
/* fill a visual-to-logical index map using the runs[] */
|
||||
Run *runs=mRuns, *runsLimit=runs+mRunCount;
|
||||
int32_t logicalStart, visualStart, visualLimit;
|
||||
|
||||
visualStart=0;
|
||||
for(; runs<runsLimit; ++runs) {
|
||||
logicalStart=runs->logicalStart;
|
||||
visualLimit=runs->visualLimit;
|
||||
if(IS_EVEN_RUN(logicalStart)) {
|
||||
do { /* LTR */
|
||||
*aIndexMap++ = logicalStart++;
|
||||
} while(++visualStart<visualLimit);
|
||||
} else {
|
||||
REMOVE_ODD_BIT(logicalStart);
|
||||
logicalStart+=visualLimit-visualStart; /* logicalLimit */
|
||||
do { /* RTL */
|
||||
*aIndexMap++ = --logicalStart;
|
||||
} while(++visualStart<visualLimit);
|
||||
}
|
||||
/* visualStart==visualLimit; */
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* reorder a line based on a levels array (L2) ------------------------------ */
|
||||
|
||||
nsresult nsBidi::ReorderLogical(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap)
|
||||
{
|
||||
int32_t start, limit, sumOfSosEos;
|
||||
nsBidiLevel minLevel, maxLevel;
|
||||
|
||||
if(aIndexMap==nullptr ||
|
||||
!PrepareReorder(aLevels, aLength, aIndexMap, &minLevel, &maxLevel)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nothing to do? */
|
||||
if(minLevel==maxLevel && (minLevel&1)==0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* reorder only down to the lowest odd level */
|
||||
minLevel|=1;
|
||||
|
||||
/* loop maxLevel..minLevel */
|
||||
do {
|
||||
start=0;
|
||||
|
||||
/* loop for all sequences of levels to reorder at the current maxLevel */
|
||||
for(;;) {
|
||||
/* look for a sequence of levels that are all at >=maxLevel */
|
||||
/* look for the first index of such a sequence */
|
||||
while(start<aLength && aLevels[start]<maxLevel) {
|
||||
++start;
|
||||
}
|
||||
if(start>=aLength) {
|
||||
break; /* no more such sequences */
|
||||
}
|
||||
|
||||
/* look for the limit of such a sequence (the index behind it) */
|
||||
for(limit=start; ++limit<aLength && aLevels[limit]>=maxLevel;) {}
|
||||
|
||||
/*
|
||||
* sos=start of sequence, eos=end of sequence
|
||||
*
|
||||
* The closed (inclusive) interval from sos to eos includes all the logical
|
||||
* and visual indexes within this sequence. They are logically and
|
||||
* visually contiguous and in the same range.
|
||||
*
|
||||
* For each run, the new visual index=sos+eos-old visual index;
|
||||
* we pre-add sos+eos into sumOfSosEos ->
|
||||
* new visual index=sumOfSosEos-old visual index;
|
||||
*/
|
||||
sumOfSosEos=start+limit-1;
|
||||
|
||||
/* reorder each index in the sequence */
|
||||
do {
|
||||
aIndexMap[start]=sumOfSosEos-aIndexMap[start];
|
||||
} while(++start<limit);
|
||||
|
||||
/* start==limit */
|
||||
if(limit==aLength) {
|
||||
break; /* no more such sequences */
|
||||
} else {
|
||||
start=limit+1;
|
||||
}
|
||||
}
|
||||
} while(--maxLevel>=minLevel);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBidi::InvertMap(const int32_t *aSrcMap, int32_t *aDestMap, int32_t aLength)
|
||||
{
|
||||
if(aSrcMap!=nullptr && aDestMap!=nullptr && aLength > 0) {
|
||||
const int32_t *pi;
|
||||
int32_t destLength = -1, count = 0;
|
||||
/* find highest value and count positive indexes in srcMap */
|
||||
pi = aSrcMap + aLength;
|
||||
while (pi > aSrcMap) {
|
||||
if (*--pi > destLength) {
|
||||
destLength = *pi;
|
||||
}
|
||||
if (*pi >= 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
destLength++; /* add 1 for origin 0 */
|
||||
if (count < destLength) {
|
||||
/* we must fill unmatched destMap entries with -1 */
|
||||
memset(aDestMap, 0xFF, destLength * sizeof(int32_t));
|
||||
}
|
||||
pi = aSrcMap + aLength;
|
||||
while (aLength > 0) {
|
||||
if (*--pi >= 0) {
|
||||
aDestMap[*pi] = --aLength;
|
||||
} else {
|
||||
--aLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t nsBidi::doWriteReverse(const char16_t *src, int32_t srcLength,
|
||||
char16_t *dest, uint16_t options) {
|
||||
/*
|
||||
* RTL run -
|
||||
*
|
||||
* RTL runs need to be copied to the destination in reverse order
|
||||
* of code points, not code units, to keep Unicode characters intact.
|
||||
*
|
||||
* The general strategy for this is to read the source text
|
||||
* in backward order, collect all code units for a code point
|
||||
* (and optionally following combining characters, see below),
|
||||
* and copy all these code units in ascending order
|
||||
* to the destination for this run.
|
||||
*
|
||||
* Several options request whether combining characters
|
||||
* should be kept after their base characters,
|
||||
* whether Bidi control characters should be removed, and
|
||||
* whether characters should be replaced by their mirror-image
|
||||
* equivalent Unicode characters.
|
||||
*/
|
||||
int32_t i, j, destSize;
|
||||
uint32_t c;
|
||||
|
||||
/* optimize for several combinations of options */
|
||||
switch(options&(NSBIDI_REMOVE_BIDI_CONTROLS|NSBIDI_DO_MIRRORING|NSBIDI_KEEP_BASE_COMBINING)) {
|
||||
case 0:
|
||||
/*
|
||||
* With none of the "complicated" options set, the destination
|
||||
* run will have the same length as the source run,
|
||||
* and there is no mirroring and no keeping combining characters
|
||||
* with their base characters.
|
||||
*/
|
||||
destSize=srcLength;
|
||||
|
||||
/* preserve character integrity */
|
||||
do {
|
||||
/* i is always after the last code unit known to need to be kept in this segment */
|
||||
i=srcLength;
|
||||
|
||||
/* collect code units for one base character */
|
||||
UTF_BACK_1(src, 0, srcLength);
|
||||
|
||||
/* copy this base character */
|
||||
j=srcLength;
|
||||
do {
|
||||
*dest++=src[j++];
|
||||
} while(j<i);
|
||||
} while(srcLength>0);
|
||||
break;
|
||||
case NSBIDI_KEEP_BASE_COMBINING:
|
||||
/*
|
||||
* Here, too, the destination
|
||||
* run will have the same length as the source run,
|
||||
* and there is no mirroring.
|
||||
* We do need to keep combining characters with their base characters.
|
||||
*/
|
||||
destSize=srcLength;
|
||||
|
||||
/* preserve character integrity */
|
||||
do {
|
||||
/* i is always after the last code unit known to need to be kept in this segment */
|
||||
i=srcLength;
|
||||
|
||||
/* collect code units and modifier letters for one base character */
|
||||
do {
|
||||
UTF_PREV_CHAR(src, 0, srcLength, c);
|
||||
} while(srcLength>0 && GetBidiCat(c) == eCharType_DirNonSpacingMark);
|
||||
|
||||
/* copy this "user character" */
|
||||
j=srcLength;
|
||||
do {
|
||||
*dest++=src[j++];
|
||||
} while(j<i);
|
||||
} while(srcLength>0);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* With several "complicated" options set, this is the most
|
||||
* general and the slowest copying of an RTL run.
|
||||
* We will do mirroring, remove Bidi controls, and
|
||||
* keep combining characters with their base characters
|
||||
* as requested.
|
||||
*/
|
||||
if(!(options&NSBIDI_REMOVE_BIDI_CONTROLS)) {
|
||||
i=srcLength;
|
||||
} else {
|
||||
/* we need to find out the destination length of the run,
|
||||
which will not include the Bidi control characters */
|
||||
int32_t length=srcLength;
|
||||
char16_t ch;
|
||||
|
||||
i=0;
|
||||
do {
|
||||
ch=*src++;
|
||||
if (!IsBidiControl((uint32_t)ch)) {
|
||||
++i;
|
||||
}
|
||||
} while(--length>0);
|
||||
src-=srcLength;
|
||||
}
|
||||
destSize=i;
|
||||
|
||||
/* preserve character integrity */
|
||||
do {
|
||||
/* i is always after the last code unit known to need to be kept in this segment */
|
||||
i=srcLength;
|
||||
|
||||
/* collect code units for one base character */
|
||||
UTF_PREV_CHAR(src, 0, srcLength, c);
|
||||
if(options&NSBIDI_KEEP_BASE_COMBINING) {
|
||||
/* collect modifier letters for this base character */
|
||||
while(srcLength>0 && GetBidiCat(c) == eCharType_DirNonSpacingMark) {
|
||||
UTF_PREV_CHAR(src, 0, srcLength, c);
|
||||
}
|
||||
}
|
||||
|
||||
if(options&NSBIDI_REMOVE_BIDI_CONTROLS && IsBidiControl(c)) {
|
||||
/* do not copy this Bidi control character */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy this "user character" */
|
||||
j=srcLength;
|
||||
if(options&NSBIDI_DO_MIRRORING) {
|
||||
/* mirror only the base character */
|
||||
c = GetMirroredChar(c);
|
||||
|
||||
int32_t k=0;
|
||||
UTF_APPEND_CHAR_UNSAFE(dest, k, c);
|
||||
dest+=k;
|
||||
j+=k;
|
||||
}
|
||||
while(j<i) {
|
||||
*dest++=src[j++];
|
||||
}
|
||||
} while(srcLength>0);
|
||||
break;
|
||||
} /* end of switch */
|
||||
return destSize;
|
||||
}
|
||||
|
||||
nsresult nsBidi::WriteReverse(const char16_t *aSrc, int32_t aSrcLength, char16_t *aDest, uint16_t aOptions, int32_t *aDestSize)
|
||||
{
|
||||
if( aSrc==nullptr || aSrcLength<0 ||
|
||||
aDest==nullptr
|
||||
) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* do input and output overlap? */
|
||||
if( aSrc>=aDest && aSrc<aDest+aSrcLength ||
|
||||
aDest>=aSrc && aDest<aSrc+aSrcLength
|
||||
) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if(aSrcLength>0) {
|
||||
*aDestSize = doWriteReverse(aSrc, aSrcLength, aDest, aOptions);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif // FULL_BIDI_ENGINE
|
||||
|
@ -49,6 +49,14 @@
|
||||
* It holds an embedding level and indicates the visual direction
|
||||
* by its bit 0 (even/odd value).<p>
|
||||
*
|
||||
* It can also hold non-level values for the
|
||||
* <code>aParaLevel</code> and <code>aEmbeddingLevels</code>
|
||||
* arguments of <code>SetPara</code>; there:
|
||||
* <ul>
|
||||
* <li>bit 7 of an <code>aEmbeddingLevels[]</code>
|
||||
* value indicates whether the using application is
|
||||
* specifying the level of a character to <i>override</i> whatever the
|
||||
* Bidi implementation would resolve it to.</li>
|
||||
* <li><code>aParaLevel</code> can be set to the
|
||||
* pseudo-level values <code>NSBIDI_DEFAULT_LTR</code>
|
||||
* and <code>NSBIDI_DEFAULT_RTL</code>.</li></ul>
|
||||
@ -122,23 +130,61 @@ enum nsBidiDirection {
|
||||
typedef enum nsBidiDirection nsBidiDirection;
|
||||
|
||||
/* miscellaneous definitions ------------------------------------------------ */
|
||||
/** option flags for WriteReverse() */
|
||||
/**
|
||||
* option bit for WriteReverse():
|
||||
* keep combining characters after their base characters in RTL runs
|
||||
*
|
||||
* @see WriteReverse
|
||||
*/
|
||||
#define NSBIDI_KEEP_BASE_COMBINING 1
|
||||
|
||||
/**
|
||||
* option bit for WriteReverse():
|
||||
* replace characters with the "mirrored" property in RTL runs
|
||||
* by their mirror-image mappings
|
||||
*
|
||||
* @see WriteReverse
|
||||
*/
|
||||
#define NSBIDI_DO_MIRRORING 2
|
||||
|
||||
/**
|
||||
* option bit for WriteReverse():
|
||||
* remove Bidi control characters
|
||||
*
|
||||
* @see WriteReverse
|
||||
*/
|
||||
#define NSBIDI_REMOVE_BIDI_CONTROLS 8
|
||||
|
||||
/* helper macros for each allocated array member */
|
||||
#define GETDIRPROPSMEMORY(length) \
|
||||
GetMemory((void **)&mDirPropsMemory, &mDirPropsSize, \
|
||||
(length))
|
||||
mMayAllocateText, (length))
|
||||
|
||||
#define GETLEVELSMEMORY(length) \
|
||||
GetMemory((void **)&mLevelsMemory, &mLevelsSize, \
|
||||
(length))
|
||||
mMayAllocateText, (length))
|
||||
|
||||
#define GETRUNSMEMORY(length) \
|
||||
GetMemory((void **)&mRunsMemory, &mRunsSize, \
|
||||
(length)*sizeof(Run))
|
||||
mMayAllocateRuns, (length)*sizeof(Run))
|
||||
|
||||
#define GETISOLATESMEMORY(length) \
|
||||
GetMemory((void **)&mIsolatesMemory, &mIsolatesSize, \
|
||||
(length)*sizeof(Isolate))
|
||||
/* additional macros used by constructor - always allow allocation */
|
||||
#define GETINITIALDIRPROPSMEMORY(length) \
|
||||
GetMemory((void **)&mDirPropsMemory, &mDirPropsSize, \
|
||||
true, (length))
|
||||
|
||||
#define GETINITIALLEVELSMEMORY(length) \
|
||||
GetMemory((void **)&mLevelsMemory, &mLevelsSize, \
|
||||
true, (length))
|
||||
|
||||
#define GETINITIALRUNSMEMORY(length) \
|
||||
GetMemory((void **)&mRunsMemory, &mRunsSize, \
|
||||
true, (length)*sizeof(Run))
|
||||
|
||||
#define GETINITIALISOLATESMEMORY(length) \
|
||||
GetMemory((void **)&mIsolatesMemory, &mIsolatesSize, \
|
||||
true, (length)*sizeof(Isolate))
|
||||
|
||||
/*
|
||||
* Sometimes, bit values are more appropriate
|
||||
@ -459,8 +505,28 @@ public:
|
||||
* the desired default is used (0 for LTR or 1 for RTL).
|
||||
* Any other value between 0 and <code>NSBIDI_MAX_EXPLICIT_LEVEL</code> is also valid,
|
||||
* with odd levels indicating RTL.
|
||||
*
|
||||
* @param aEmbeddingLevels (in) may be used to preset the embedding and override levels,
|
||||
* ignoring characters like LRE and PDF in the text.
|
||||
* A level overrides the directional property of its corresponding
|
||||
* (same index) character if the level has the
|
||||
* <code>NSBIDI_LEVEL_OVERRIDE</code> bit set.<p>
|
||||
* Except for that bit, it must be
|
||||
* <code>aParaLevel<=aEmbeddingLevels[]<=NSBIDI_MAX_EXPLICIT_LEVEL</code>.<p>
|
||||
* <strong>Caution: </strong>A copy of this pointer, not of the levels,
|
||||
* will be stored in the <code>nsBidi</code> object;
|
||||
* the <code>aEmbeddingLevels</code> array must not be
|
||||
* deallocated before the <code>nsBidi</code> object is destroyed or reused,
|
||||
* and the <code>aEmbeddingLevels</code>
|
||||
* should not be modified to avoid unexpected results on subsequent Bidi operations.
|
||||
* However, the <code>SetPara</code> and
|
||||
* <code>SetLine</code> functions may modify some or all of the levels.<p>
|
||||
* After the <code>nsBidi</code> object is reused or destroyed, the caller
|
||||
* must take care of the deallocation of the <code>aEmbeddingLevels</code> array.<p>
|
||||
* <strong>The <code>aEmbeddingLevels</code> array must be
|
||||
* at least <code>aLength</code> long.</strong>
|
||||
*/
|
||||
nsresult SetPara(const char16_t *aText, int32_t aLength, nsBidiLevel aParaLevel);
|
||||
nsresult SetPara(const char16_t *aText, int32_t aLength, nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels);
|
||||
|
||||
/**
|
||||
* Get the directionality of the text.
|
||||
@ -482,6 +548,73 @@ public:
|
||||
*/
|
||||
nsresult GetParaLevel(nsBidiLevel* aParaLevel);
|
||||
|
||||
#ifdef FULL_BIDI_ENGINE
|
||||
/**
|
||||
* <code>SetLine</code> sets an <code>nsBidi</code> to
|
||||
* contain the reordering information, especially the resolved levels,
|
||||
* for all the characters in a line of text. This line of text is
|
||||
* specified by referring to an <code>nsBidi</code> object representing
|
||||
* this information for a paragraph of text, and by specifying
|
||||
* a range of indexes in this paragraph.<p>
|
||||
* In the new line object, the indexes will range from 0 to <code>aLimit-aStart</code>.<p>
|
||||
*
|
||||
* This is used after calling <code>SetPara</code>
|
||||
* for a paragraph, and after line-breaking on that paragraph.
|
||||
* It is not necessary if the paragraph is treated as a single line.<p>
|
||||
*
|
||||
* After line-breaking, rules (L1) and (L2) for the treatment of
|
||||
* trailing WS and for reordering are performed on
|
||||
* an <code>nsBidi</code> object that represents a line.<p>
|
||||
*
|
||||
* <strong>Important:</strong> the line <code>nsBidi</code> object shares data with
|
||||
* <code>aParaBidi</code>.
|
||||
* You must destroy or reuse this object before <code>aParaBidi</code>.
|
||||
* In other words, you must destroy or reuse the <code>nsBidi</code> object for a line
|
||||
* before the object for its parent paragraph.
|
||||
*
|
||||
* @param aParaBidi is the parent paragraph object.
|
||||
*
|
||||
* @param aStart is the line's first index into the paragraph text.
|
||||
*
|
||||
* @param aLimit is just behind the line's last index into the paragraph text
|
||||
* (its last index +1).<br>
|
||||
* It must be <code>0<=aStart<=aLimit<=</code>paragraph length.
|
||||
*
|
||||
* @see SetPara
|
||||
*/
|
||||
nsresult SetLine(const nsBidi* aParaBidi, int32_t aStart, int32_t aLimit);
|
||||
|
||||
/**
|
||||
* Get the length of the text.
|
||||
*
|
||||
* @param aLength receives the length of the text that the nsBidi object was created for.
|
||||
*/
|
||||
nsresult GetLength(int32_t* aLength);
|
||||
|
||||
/**
|
||||
* Get the level for one character.
|
||||
*
|
||||
* @param aCharIndex the index of a character.
|
||||
*
|
||||
* @param aLevel receives the level for the character at aCharIndex.
|
||||
*
|
||||
* @see nsBidiLevel
|
||||
*/
|
||||
nsresult GetLevelAt(int32_t aCharIndex, nsBidiLevel* aLevel);
|
||||
|
||||
/**
|
||||
* Get an array of levels for each character.<p>
|
||||
*
|
||||
* Note that this function may allocate memory under some
|
||||
* circumstances, unlike <code>GetLevelAt</code>.
|
||||
*
|
||||
* @param aLevels receives a pointer to the levels array for the text,
|
||||
* or <code>nullptr</code> if an error occurs.
|
||||
*
|
||||
* @see nsBidiLevel
|
||||
*/
|
||||
nsresult GetLevels(nsBidiLevel** aLevels);
|
||||
#endif // FULL_BIDI_ENGINE
|
||||
/**
|
||||
* Get the bidirectional type for one character.
|
||||
*
|
||||
@ -574,6 +707,92 @@ public:
|
||||
*/
|
||||
nsresult GetVisualRun(int32_t aRunIndex, int32_t* aLogicalStart, int32_t* aLength, nsBidiDirection* aDirection);
|
||||
|
||||
#ifdef FULL_BIDI_ENGINE
|
||||
/**
|
||||
* Get the visual position from a logical text position.
|
||||
* If such a mapping is used many times on the same
|
||||
* <code>nsBidi</code> object, then calling
|
||||
* <code>GetLogicalMap</code> is more efficient.<p>
|
||||
*
|
||||
* Note that in right-to-left runs, this mapping places
|
||||
* modifier letters before base characters and second surrogates
|
||||
* before first ones.
|
||||
*
|
||||
* @param aLogicalIndex is the index of a character in the text.
|
||||
*
|
||||
* @param aVisualIndex will receive the visual position of this character.
|
||||
*
|
||||
* @see GetLogicalMap
|
||||
* @see GetLogicalIndex
|
||||
*/
|
||||
nsresult GetVisualIndex(int32_t aLogicalIndex, int32_t* aVisualIndex);
|
||||
|
||||
/**
|
||||
* Get the logical text position from a visual position.
|
||||
* If such a mapping is used many times on the same
|
||||
* <code>nsBidi</code> object, then calling
|
||||
* <code>GetVisualMap</code> is more efficient.<p>
|
||||
*
|
||||
* This is the inverse function to <code>GetVisualIndex</code>.
|
||||
*
|
||||
* @param aVisualIndex is the visual position of a character.
|
||||
*
|
||||
* @param aLogicalIndex will receive the index of this character in the text.
|
||||
*
|
||||
* @see GetVisualMap
|
||||
* @see GetVisualIndex
|
||||
*/
|
||||
nsresult GetLogicalIndex(int32_t aVisualIndex, int32_t* aLogicalIndex);
|
||||
|
||||
/**
|
||||
* Get a logical-to-visual index map (array) for the characters in the nsBidi
|
||||
* (paragraph or line) object.
|
||||
*
|
||||
* @param aIndexMap is a pointer to an array of <code>GetLength</code>
|
||||
* indexes which will reflect the reordering of the characters.
|
||||
* The array does not need to be initialized.<p>
|
||||
* The index map will result in <code>aIndexMap[aLogicalIndex]==aVisualIndex</code>.<p>
|
||||
*
|
||||
* @see GetVisualMap
|
||||
* @see GetVisualIndex
|
||||
*/
|
||||
nsresult GetLogicalMap(int32_t *aIndexMap);
|
||||
|
||||
/**
|
||||
* Get a visual-to-logical index map (array) for the characters in the nsBidi
|
||||
* (paragraph or line) object.
|
||||
*
|
||||
* @param aIndexMap is a pointer to an array of <code>GetLength</code>
|
||||
* indexes which will reflect the reordering of the characters.
|
||||
* The array does not need to be initialized.<p>
|
||||
* The index map will result in <code>aIndexMap[aVisualIndex]==aLogicalIndex</code>.<p>
|
||||
*
|
||||
* @see GetLogicalMap
|
||||
* @see GetLogicalIndex
|
||||
*/
|
||||
nsresult GetVisualMap(int32_t *aIndexMap);
|
||||
|
||||
/**
|
||||
* This is a convenience function that does not use a nsBidi object.
|
||||
* It is intended to be used for when an application has determined the levels
|
||||
* of objects (character sequences) and just needs to have them reordered (L2).
|
||||
* This is equivalent to using <code>GetLogicalMap</code> on a
|
||||
* <code>nsBidi</code> object.
|
||||
*
|
||||
* @param aLevels is an array with <code>aLength</code> levels that have been determined by
|
||||
* the application.
|
||||
*
|
||||
* @param aLength is the number of levels in the array, or, semantically,
|
||||
* the number of objects to be reordered.
|
||||
* It must be <code>aLength>0</code>.
|
||||
*
|
||||
* @param aIndexMap is a pointer to an array of <code>aLength</code>
|
||||
* indexes which will reflect the reordering of the characters.
|
||||
* The array does not need to be initialized.<p>
|
||||
* The index map will result in <code>aIndexMap[aLogicalIndex]==aVisualIndex</code>.
|
||||
*/
|
||||
static nsresult ReorderLogical(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap);
|
||||
#endif // FULL_BIDI_ENGINE
|
||||
/**
|
||||
* This is a convenience function that does not use a nsBidi object.
|
||||
* It is intended to be used for when an application has determined the levels
|
||||
@ -595,6 +814,22 @@ public:
|
||||
*/
|
||||
static nsresult ReorderVisual(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap);
|
||||
|
||||
#ifdef FULL_BIDI_ENGINE
|
||||
/**
|
||||
* Invert an index map.
|
||||
* The one-to-one index mapping of the first map is inverted and written to
|
||||
* the second one.
|
||||
*
|
||||
* @param aSrcMap is an array with <code>aLength</code> indexes
|
||||
* which define the original mapping.
|
||||
*
|
||||
* @param aDestMap is an array with <code>aLength</code> indexes
|
||||
* which will be filled with the inverse mapping.
|
||||
*
|
||||
* @param aLength is the length of each array.
|
||||
*/
|
||||
nsresult InvertMap(const int32_t *aSrcMap, int32_t *aDestMap, int32_t aLength);
|
||||
#endif // FULL_BIDI_ENGINE
|
||||
/**
|
||||
* Reverse a Right-To-Left run of Unicode text.
|
||||
*
|
||||
@ -648,6 +883,9 @@ protected:
|
||||
Run* mRunsMemory;
|
||||
Isolate* mIsolatesMemory;
|
||||
|
||||
/** indicators for whether memory may be allocated after construction */
|
||||
bool mMayAllocateText, mMayAllocateRuns;
|
||||
|
||||
DirProp* mDirProps;
|
||||
nsBidiLevel* mLevels;
|
||||
|
||||
@ -686,7 +924,7 @@ private:
|
||||
|
||||
void Init();
|
||||
|
||||
bool GetMemory(void **aMemory, size_t* aSize, size_t aSizeNeeded);
|
||||
bool GetMemory(void **aMemory, size_t* aSize, bool aMayAllocate, size_t aSizeNeeded);
|
||||
|
||||
void Free();
|
||||
|
||||
@ -694,6 +932,8 @@ private:
|
||||
|
||||
void ResolveExplicitLevels(nsBidiDirection *aDirection);
|
||||
|
||||
nsresult CheckExplicitLevels(nsBidiDirection *aDirection);
|
||||
|
||||
nsBidiDirection DirectionFromFlags(Flags aFlags);
|
||||
|
||||
void ProcessPropertySeq(LevState *pLevState, uint8_t _prop, int32_t start, int32_t limit);
|
||||
@ -711,6 +951,10 @@ private:
|
||||
void ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel);
|
||||
|
||||
static bool PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength, int32_t *aIndexMap, nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel);
|
||||
|
||||
int32_t doWriteReverse(const char16_t *src, int32_t srcLength,
|
||||
char16_t *dest, uint16_t options);
|
||||
|
||||
};
|
||||
|
||||
#endif // _nsBidi_h_
|
||||
|
@ -208,7 +208,7 @@ struct BidiParagraphData {
|
||||
nsresult SetPara()
|
||||
{
|
||||
return mBidiEngine->SetPara(mBuffer.get(), BufferLength(),
|
||||
mParaLevel);
|
||||
mParaLevel, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2012,7 +2012,7 @@ nsresult nsBidiPresUtils::ProcessText(const char16_t* aText,
|
||||
|
||||
nsAutoString textBuffer(aText, aLength);
|
||||
|
||||
nsresult rv = aBidiEngine->SetPara(aText, aLength, aBaseLevel);
|
||||
nsresult rv = aBidiEngine->SetPara(aText, aLength, aBaseLevel, nullptr);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user