From: Simon Montagu Experiment using ICU ubidi to replace nsBidi. Bug 924851 diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -49,17 +49,17 @@ #include "gfxImageSurface.h" #include "gfxPlatform.h" #include "gfxFont.h" #include "gfxBlur.h" #include "gfxUtils.h" #include "nsFrameManager.h" #include "nsFrameLoader.h" -#include "nsBidi.h" +#include "unicode/ubidi.h" #include "nsBidiPresUtils.h" #include "Layers.h" #include "CanvasUtils.h" #include "nsIMemoryReporter.h" #include "nsStyleUtil.h" #include "CanvasImageCache.h" #include @@ -2351,24 +2351,24 @@ CanvasRenderingContext2D::MeasureText(co /** * Used for nsBidiPresUtils::ProcessText */ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcessor { typedef CanvasRenderingContext2D::ContextState ContextState; - virtual void SetText(const char16_t* text, int32_t length, nsBidiDirection direction) + virtual void SetText(const char16_t* text, int32_t length, UBiDiDirection direction) { mFontgrp->UpdateFontList(); // ensure user font generation is current mTextRun = mFontgrp->MakeTextRun(text, length, mThebes, mAppUnitsPerDevPixel, - direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0); + direction==UBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0); } virtual nscoord GetWidth() { gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0, mTextRun->GetLength(), mDoMeasureBoundingBox ? gfxFont::TIGHT_INK_EXTENTS : @@ -2656,38 +2656,39 @@ CanvasRenderingContext2D::DrawOrMeasureT processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid; processor.mState = &CurrentState(); processor.mFontgrp = currentFontStyle; nscoord totalWidthCoord; // calls bidi algo twice since it needs the full text width and the // bounding boxes before rendering anything - nsBidi bidiEngine; + UBiDi* bidiPara = ubidi_open(); rv = nsBidiPresUtils::ProcessText(textToDraw.get(), textToDraw.Length(), - isRTL ? NSBIDI_RTL : NSBIDI_LTR, + isRTL ? UBIDI_RTL : UBIDI_LTR, presShell->GetPresContext(), processor, nsBidiPresUtils::MODE_MEASURE, nullptr, 0, &totalWidthCoord, - &bidiEngine); + bidiPara); if (NS_FAILED(rv)) { return rv; } float totalWidth = float(totalWidthCoord) / processor.mAppUnitsPerDevPixel; if (aWidth) { *aWidth = totalWidth; } // if only measuring, don't need to do any more work if (aOp==TEXT_DRAW_OPERATION_MEASURE) { + ubidi_close(bidiPara); return NS_OK; } // offset pt.x based on text align gfxFloat anchorX; if (state.textAlign == TEXT_ALIGN_CENTER) { anchorX = .5; @@ -2760,25 +2761,25 @@ CanvasRenderingContext2D::DrawOrMeasureT // save the previous bounding box gfxRect boundingBox = processor.mBoundingBox; // don't ever need to measure the bounding box twice processor.mDoMeasureBoundingBox = false; rv = nsBidiPresUtils::ProcessText(textToDraw.get(), textToDraw.Length(), - isRTL ? NSBIDI_RTL : NSBIDI_LTR, + isRTL ? UBIDI_RTL : UBIDI_LTR, presShell->GetPresContext(), processor, nsBidiPresUtils::MODE_DRAW, nullptr, 0, nullptr, - &bidiEngine); - + bidiPara); + ubidi_close(bidiPara); mTarget->SetTransform(oldTransform); if (aOp == CanvasRenderingContext2D::TEXT_DRAW_OPERATION_FILL && !doDrawShadow) { RedrawUser(boundingBox); return NS_OK; } diff --git a/content/canvas/src/Makefile.in b/content/canvas/src/Makefile.in --- a/content/canvas/src/Makefile.in +++ b/content/canvas/src/Makefile.in @@ -2,8 +2,12 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. include $(topsrcdir)/config/rules.mk CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS) +LOCAL_INCLUDES += \ + -I$(topsrcdir)/intl/icu/source/common \ + -I$(topsrcdir)/intl/icu/source/i18n \ + $(NULL) diff --git a/intl/unicharutil/util/nsBidiUtils.h b/intl/unicharutil/util/nsBidiUtils.h --- a/intl/unicharutil/util/nsBidiUtils.h +++ b/intl/unicharutil/util/nsBidiUtils.h @@ -44,21 +44,21 @@ enum nsCharType { * This specifies the language directional property of a character set. */ typedef enum nsCharType nsCharType; /** * definitions of bidirection character types by category */ -#define CHARTYPE_IS_RTL(val) ( ( (val) == eCharType_RightToLeft) || ( (val) == eCharType_RightToLeftArabic) ) +#define CHARDIRECTION_IS_RTL(val) ( ( (val) == U_RIGHT_TO_LEFT) || ( (val) == U_RIGHT_TO_LEFT_ARABIC) ) -#define CHARTYPE_IS_WEAK(val) ( ( (val) == eCharType_EuropeanNumberSeparator) \ - || ( (val) == eCharType_EuropeanNumberTerminator) \ - || ( ( (val) > eCharType_ArabicNumber) && ( (val) != eCharType_RightToLeftArabic) ) ) +#define CHARDIRECTION_IS_WEAK(val) ( ( (val) == U_EUROPEAN_NUMBER_SEPARATOR) \ + || ( (val) == U_EUROPEAN_NUMBER_TERMINATOR) \ + || ( ( (val) > U_ARABIC_NUMBER) && ( (val) != U_RIGHT_TO_LEFT_ARABIC) ) ) /** * Inspects a Unichar, converting numbers to Arabic or Hindi forms and returning them * @param aChar is the character * @param aPrevCharArabic is true if the previous character in the string is an Arabic char * @param aNumFlag specifies the conversion to perform: * IBMBIDI_NUMERAL_NOMINAL: don't do any conversion * IBMBIDI_NUMERAL_HINDI: convert to Hindi forms (Unicode 0660-0669) diff --git a/layout/base/Makefile.in b/layout/base/Makefile.in --- a/layout/base/Makefile.in +++ b/layout/base/Makefile.in @@ -1,8 +1,13 @@ # # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. include $(topsrcdir)/config/rules.mk CXXFLAGS += $(MOZ_CAIRO_CFLAGS) + +LOCAL_INCLUDES += \ + -I$(topsrcdir)/intl/icu/source/common \ + -I$(topsrcdir)/intl/icu/source/i18n \ + $(NULL) diff --git a/layout/base/moz.build b/layout/base/moz.build --- a/layout/base/moz.build +++ b/layout/base/moz.build @@ -5,17 +5,16 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. XPIDL_SOURCES += [ 'nsIStyleSheetService.idl', ] if CONFIG['IBMBIDI']: UNIFIED_SOURCES += [ - 'nsBidi.cpp', 'nsBidiPresUtils.cpp', ] if CONFIG['MOZ_DEBUG']: UNIFIED_SOURCES += [ 'nsAutoLayoutPhase.cpp', ] @@ -23,17 +22,16 @@ XPIDL_MODULE = 'layout_base' EXPORTS += [ 'ActiveLayerTracker.h', 'DisplayItemClip.h', 'DisplayListClipState.h', 'FrameLayerBuilder.h', 'FramePropertyTable.h', 'nsArenaMemoryStats.h', - 'nsBidi.h', 'nsBidiPresUtils.h', 'nsCaret.h', 'nsChangeHint.h', 'nsCompatibility.h', 'nsCSSFrameConstructor.h', 'nsDisplayItemTypes.h', 'nsDisplayItemTypesList.h', 'nsDisplayList.h', diff --git a/layout/base/nsBidi.cpp b/layout/base/nsBidi.cpp deleted file mode 100644 --- a/layout/base/nsBidi.cpp +++ /dev/null @@ -1,2224 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifdef IBMBIDI - -#include "nsBidi.h" -#include "nsUnicodeProperties.h" -#include "nsCRTGlue.h" - -using namespace mozilla::unicode; - -// These are #defined in under Solaris 10 x86 -#undef CS -#undef ES - -/* Comparing the description of the Bidi algorithm with this implementation - is easier with the same names for the Bidi types in the code as there. -*/ -enum { - L = eCharType_LeftToRight, - R = eCharType_RightToLeft, - EN = eCharType_EuropeanNumber, - ES = eCharType_EuropeanNumberSeparator, - ET = eCharType_EuropeanNumberTerminator, - AN = eCharType_ArabicNumber, - CS = eCharType_CommonNumberSeparator, - B = eCharType_BlockSeparator, - S = eCharType_SegmentSeparator, - WS = eCharType_WhiteSpaceNeutral, - O_N = eCharType_OtherNeutral, - LRE = eCharType_LeftToRightEmbedding, - LRO = eCharType_LeftToRightOverride, - AL = eCharType_RightToLeftArabic, - RLE = eCharType_RightToLeftEmbedding, - RLO = eCharType_RightToLeftOverride, - PDF = eCharType_PopDirectionalFormat, - NSM = eCharType_DirNonSpacingMark, - BN = eCharType_BoundaryNeutral, - dirPropCount -}; - -/* to avoid some conditional statements, use tiny constant arrays */ -static Flags flagLR[2]={ DIRPROP_FLAG(L), DIRPROP_FLAG(R) }; -static Flags flagE[2]={ DIRPROP_FLAG(LRE), DIRPROP_FLAG(RLE) }; -static Flags flagO[2]={ DIRPROP_FLAG(LRO), DIRPROP_FLAG(RLO) }; - -#define DIRPROP_FLAG_LR(level) flagLR[(level)&1] -#define DIRPROP_FLAG_E(level) flagE[(level)&1] -#define DIRPROP_FLAG_O(level) flagO[(level)&1] - -/* - * General implementation notes: - * - * Throughout the implementation, there are comments like (W2) that refer to - * rules of the Bidi algorithm in its version 5, in this example to the second - * rule of the resolution of weak types. - * - * For handling surrogate pairs, where two UChar's form one "abstract" (or UTF-32) - * character according to UTF-16, the second UChar gets the directional property of - * the entire character assigned, while the first one gets a BN, a boundary - * neutral, type, which is ignored by most of the algorithm according to - * rule (X9) and the implementation suggestions of the Bidi algorithm. - * - * Later, AdjustWSLevels() will set the level for each BN to that of the - * following character (UChar), which results in surrogate pairs getting the - * same level on each of their surrogates. - * - * In a UTF-8 implementation, the same thing could be done: the last byte of - * a multi-byte sequence would get the "real" property, while all previous - * bytes of that sequence would get BN. - * - * It is not possible to assign all those parts of a character the same real - * property because this would fail in the resolution of weak types with rules - * that look at immediately surrounding types. - * - * As a related topic, this implementation does not remove Boundary Neutral - * types from the input, but ignores them whenever this is relevant. - * For example, the loop for the resolution of the weak types reads - * types until it finds a non-BN. - * Also, explicit embedding codes are neither changed into BN nor removed. - * They are only treated the same way real BNs are. - * As stated before, AdjustWSLevels() takes care of them at the end. - * For the purpose of conformance, the levels of all these codes - * do not matter. - * - * Note that this implementation never modifies the dirProps - * after the initial setup. - * - * - * In this implementation, the resolution of weak types (Wn), - * neutrals (Nn), and the assignment of the resolved level (In) - * are all done in one single loop, in ResolveImplicitLevels(). - * Changes of dirProp values are done on the fly, without writing - * them back to the dirProps array. - * - * - * This implementation contains code that allows to bypass steps of the - * algorithm that are not needed on the specific paragraph - * in order to speed up the most common cases considerably, - * like text that is entirely LTR, or RTL text without numbers. - * - * Most of this is done by setting a bit for each directional property - * in a flags variable and later checking for whether there are - * any LTR characters or any RTL characters, or both, whether - * there are any explicit embedding codes, etc. - * - * If the (Xn) steps are performed, then the flags are re-evaluated, - * because they will then not contain the embedding codes any more - * and will be adjusted for override codes, so that subsequently - * more bypassing may be possible than what the initial flags suggested. - * - * If the text is not mixed-directional, then the - * algorithm steps for the weak type resolution are not performed, - * and all levels are set to the paragraph level. - * - * If there are no explicit embedding codes, then the (Xn) steps - * are not performed. - * - * If embedding levels are supplied as a parameter, then all - * explicit embedding codes are ignored, and the (Xn) steps - * are not performed. - * - * White Space types could get the level of the run they belong to, - * and are checked with a test of (flags&MASK_EMBEDDING) to - * consider if the paragraph direction should be considered in - * the flags variable. - * - * If there are no White Space types in the paragraph, then - * (L1) is not necessary in AdjustWSLevels(). - */ -nsBidi::nsBidi() -{ - Init(); - - mMayAllocateText=true; - mMayAllocateRuns=true; -} - -nsBidi::~nsBidi() -{ - Free(); -} - -void nsBidi::Init() -{ - /* reset the object, all pointers nullptr, all flags false, all sizes 0 */ - mLength = 0; - mParaLevel = 0; - mFlags = 0; - mDirection = NSBIDI_LTR; - mTrailingWSStart = 0; - - mDirPropsSize = 0; - mLevelsSize = 0; - mRunsSize = 0; - mRunCount = -1; - - mDirProps=nullptr; - mLevels=nullptr; - mRuns=nullptr; - - mDirPropsMemory=nullptr; - mLevelsMemory=nullptr; - mRunsMemory=nullptr; - - mMayAllocateText=false; - mMayAllocateRuns=false; - -} - -/* - * 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. - * - * Assume aSizeNeeded>0. - * If *aMemory!=nullptr, then assume *aSize>0. - * - * ### this realloc() may unnecessarily copy the old data, - * 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, bool aMayAllocate, size_t aSizeNeeded) -{ - /* check for existing memory */ - if(*aMemory==nullptr) { - /* we need to allocate memory */ - if(!aMayAllocate) { - return false; - } else { - *aMemory=moz_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 && !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=moz_realloc(*aMemory, aSizeNeeded); - - if(memory!=nullptr) { - *aMemory=memory; - *aSize=aSizeNeeded; - return true; - } else { - /* we failed to grow */ - return false; - } - } else { - /* we have at least enough memory and must not allocate */ - return true; - } - } -} - -void nsBidi::Free() -{ - moz_free(mDirPropsMemory); - mDirPropsMemory = nullptr; - moz_free(mLevelsMemory); - mLevelsMemory = nullptr; - moz_free(mRunsMemory); - mRunsMemory = nullptr; -} - -/* SetPara ------------------------------------------------------------ */ - -nsresult nsBidi::SetPara(const char16_t *aText, int32_t aLength, - nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels) -{ - nsBidiDirection direction; - - /* check the argument values */ - if(aText==nullptr || - ((NSBIDI_MAX_EXPLICIT_LEVEL=NSBIDI_MAX_EXPLICIT_LEVEL */ - uint32_t countOver60=0, countOver61=0; /* count overflows of explicit levels */ - - /* recalculate the flags */ - flags=0; - - /* since we assume that this is a single paragraph, we ignore (X8) */ - for(i=0; i0) { - --countOver61; - } else if(countOver60>0 && (embeddingLevel&~NSBIDI_LEVEL_OVERRIDE)!=NSBIDI_MAX_EXPLICIT_LEVEL) { - /* handle LRx overflows from level 60 */ - --countOver60; - } else if(stackTop>0) { - /* this is the pop operation; it also pops level 61 while countOver60>0 */ - --stackTop; - embeddingLevel=stack[stackTop]; - /* } else { (underflow) */ - } - flags|=DIRPROP_FLAG(BN); - break; - case B: - /* - * We do not really expect to see a paragraph separator (B), - * but we should do something reasonable with it, - * especially at the end of the text. - */ - stackTop=0; - countOver60=countOver61=0; - embeddingLevel=level=mParaLevel; - flags|=DIRPROP_FLAG(B); - break; - case BN: - /* BN, LRE, RLE, and PDF are supposed to be removed (X9) */ - /* they will get their levels set correctly in AdjustWSLevels() */ - flags|=DIRPROP_FLAG(BN); - break; - default: - /* all other types get the "real" level */ - if(level!=embeddingLevel) { - level=embeddingLevel; - if(level&NSBIDI_LEVEL_OVERRIDE) { - flags|=DIRPROP_FLAG_O(level)|DIRPROP_FLAG_MULTI_RUNS; - } else { - flags|=DIRPROP_FLAG_E(level)|DIRPROP_FLAG_MULTI_RUNS; - } - } - if(!(level&NSBIDI_LEVEL_OVERRIDE)) { - flags|=DIRPROP_FLAG(dirProp); - } - break; - } - - /* - * We need to set reasonable levels even on BN codes and - * explicit codes because we will later look at same-level runs (X10). - */ - levels[i]=level; - } - if(flags&MASK_EMBEDDING) { - flags|=DIRPROP_FLAG_LR(mParaLevel); - } - - /* subsequently, ignore the explicit codes and BN (X9) */ - - /* again, determine if the text is mixed-directional or single-directional */ - mFlags=flags; - direction=DirectionFromFlags(flags); - } - return 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; - nsBidiLevel *levels=mLevels; - - int32_t i, length=mLength; - Flags flags=0; /* collect all directionalities in the text */ - nsBidiLevel level, paraLevel=mParaLevel; - - for(i=0; i>=EN_SHIFT; - /* - * Technically, this should be done before the switch() in the form - * if(nextDirProp==NSM) { - * dirProps[next]=nextDirProp=dirProp; - * } - * - * - effectively one iteration ahead. - * However, whether the next dirProp is NSM or is equal to the current dirProp - * does not change the outcome of any condition in (W2)..(W7). - */ - break; - default: - break; - } - - /* here, it is always [prev,this,next]dirProp!=BN; it may be next>i+1 */ - - /* perform (Nn) - here, only L, R, EN, AN, and neutrals are left */ - /* this is one iteration late for the neutrals */ - if(DIRPROP_FLAG(dirProp)&MASK_N) { - if(neutralStart<0) { - /* start of a sequence of neutrals */ - neutralStart=i; - beforeNeutral=prevDirProp; - } - } else /* not a neutral, can be only one of { L, R, EN, AN } */ { - /* - * Note that all levels[] values are still the same at this - * point because this function is called for an entire - * same-level run. - * Therefore, we need to read only one actual level. - */ - nsBidiLevel level=levels[i]; - - if(neutralStart>=0) { - nsBidiLevel final; - /* end of a sequence of neutrals (dirProp is "afterNeutral") */ - if(beforeNeutral==L) { - if(dirProp==L) { - final=0; /* make all neutrals L (N1) */ - } else { - final=level; /* make all neutrals "e" (N2) */ - } - } else /* beforeNeutral is one of { R, EN, AN } */ { - if(dirProp==L) { - final=level; /* make all neutrals "e" (N2) */ - } else { - final=1; /* make all neutrals R (N1) */ - } - } - /* perform (In) on the sequence of neutrals */ - if((level^final)&1) { - /* do something only if we need to _change_ the level */ - do { - ++levels[neutralStart]; - } while(++neutralStart=0) { - /* - * Note that all levels[] values are still the same at this - * point because this function is called for an entire - * same-level run. - * Therefore, we need to read only one actual level. - */ - nsBidiLevel level=levels[neutralStart], final; - - /* end of a sequence of neutrals (aEOR is "afterNeutral") */ - if(beforeNeutral==L) { - if(aEOR==L) { - final=0; /* make all neutrals L (N1) */ - } else { - final=level; /* make all neutrals "e" (N2) */ - } - } else /* beforeNeutral is one of { R, EN, AN } */ { - if(aEOR==L) { - final=level; /* make all neutrals "e" (N2) */ - } else { - final=1; /* make all neutrals R (N1) */ - } - } - /* perform (In) on the sequence of neutrals */ - if((level^final)&1) { - /* do something only if we need to _change_ the level */ - do { - ++levels[neutralStart]; - } while(++neutralStart0) { - /* reset a sequence of WS/BN before eop and B/S to the paragraph paraLevel */ - while(i>0 && DIRPROP_FLAG(dirProps[--i])&MASK_WS) { - levels[i]=paraLevel; - } - - /* reset BN to the next character's paraLevel until B/S, which restarts above loop */ - /* here, i+1 is guaranteed to be 0) { - flag=DIRPROP_FLAG(dirProps[--i]); - if(flag&MASK_BN_EXPLICIT) { - levels[i]=levels[i+1]; - } else if(flag&MASK_B_S) { - levels[i]=paraLevel; - break; - } - } - } - } - - /* now remove the NSBIDI_LEVEL_OVERRIDE flags, if any */ - /* (a separate loop can be optimized more easily by a compiler) */ - if(mFlags&MASK_OVERRIDE) { - for(i=mTrailingWSStart; i>0;) { - levels[--i]&=~NSBIDI_LEVEL_OVERRIDE; - } - } -} - -nsresult nsBidi::GetDirection(nsBidiDirection* aDirection) -{ - *aDirection = mDirection; - return NS_OK; -} - -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 3.0 Bidi algorithm as defined in - * http://www.unicode.org/unicode/reports/tr9/ , version 5, - * also described in The Unicode Standard, Version 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(nsIBidi* 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; - - if(length>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->mTrailingWSStartmTrailingWSStart-aStart; - } else { - mTrailingWSStart=length; - } - } else { - const nsBidiLevel *levels=mLevels; - int32_t i, trailingWSStart; - nsBidiLevel level; - Flags flags=0; - - 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(trailingWSStart0 && 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) -{ - if(aCharIndex<0 || mLength<=aCharIndex) { - return NS_ERROR_INVALID_ARG; - } - *pType = (nsCharType)mDirProps[aCharIndex]; - return NS_OK; -} - -nsresult nsBidi::GetLogicalRun(int32_t aLogicalStart, int32_t *aLogicalLimit, nsBidiLevel *aLevel) -{ - int32_t length = mLength; - - if(aLogicalStart<0 || length<=aLogicalStart) { - return NS_ERROR_INVALID_ARG; - } - - if(mDirection!=NSBIDI_MIXED || aLogicalStart>=mTrailingWSStart) { - if(aLogicalLimit!=nullptr) { - *aLogicalLimit=length; - } - if(aLevel!=nullptr) { - *aLevel=mParaLevel; - } - } else { - nsBidiLevel *levels=mLevels; - nsBidiLevel level=levels[aLogicalStart]; - - /* search for the end of the run */ - length=mTrailingWSStart; - while(++aLogicalStart=mRunCount - ) { - *aDirection = NSBIDI_LTR; - return NS_OK; - } else { - int32_t start=mRuns[aRunIndex].logicalStart; - if(aLogicalStart!=nullptr) { - *aLogicalStart=GET_INDEX(start); - } - if(aLength!=nullptr) { - if(aRunIndex>0) { - *aLength=mRuns[aRunIndex].visualLimit- - mRuns[aRunIndex-1].visualLimit; - } else { - *aLength=mRuns[0].visualLimit; - } - } - *aDirection = (nsBidiDirection)GET_ODD_BIT(start); - return NS_OK; - } -} - -/* compute the runs array --------------------------------------------------- */ - -/* - * Compute the runs array from the levels array. - * After GetRuns() returns true, runCount is guaranteed to be >0 - * and the runs are reordered. - * Odd-level runs have visualStart on their visual right edge and - * they progress visually to the left. - */ -bool nsBidi::GetRuns() -{ - if(mDirection!=NSBIDI_MIXED) { - /* simple, single-run case - this covers length==0 */ - GetSingleRun(mParaLevel); - } else /* NSBIDI_MIXED, length>0 */ { - /* mixed directionality */ - int32_t length=mLength, limit=length; - - /* - * If there are WS characters at the end of the line - * and the run preceding them has a level different from - * paraLevel, then they will form their own run at paraLevel (L1). - * Count them separately. - * We need some special treatment for this in order to not - * modify the levels array which a line nsBidi object shares - * with its paragraph parent and its other line siblings. - * In other words, for the trailing WS, it may be - * levels[]!=paraLevel but we have to treat it like it were so. - */ - limit=mTrailingWSStart; - if(limit==0) { - /* there is only WS on this line */ - GetSingleRun(mParaLevel); - } else { - nsBidiLevel *levels=mLevels; - int32_t i, runCount; - nsBidiLevel level=NSBIDI_DEFAULT_LTR; /* initialize with no valid level */ - - /* count the runs, there is at least one non-WS run, and limit>0 */ - runCount=0; - for(i=0; i1 || limit1 */ - if(GETRUNSMEMORY(runCount)) { - runs=mRunsMemory; - } else { - return false; - } - - /* set the runs */ - /* this could be optimized, e.g.: 464->444, 484->444, 575->555, 595->555 */ - /* however, that would take longer and make other functions more complicated */ - runIndex=0; - - /* search for the run ends */ - start=0; - level=levels[0]; - if(levelmaxLevel) { - maxLevel=level; - } - - /* initialize visualLimit values with the run lengths */ - for(i=1; imaxLevel) { - maxLevel=level; - } - ++runIndex; - } - } - - /* finish the last run at i==limit */ - runs[runIndex].logicalStart=start; - runs[runIndex].visualLimit=limit-start; - ++runIndex; - - if(limit1 and maxLevel>=minLevel>=paraLevel. - * All the visualStart fields=logical start before reordering. - * The "odd" bits are not set yet. - * - * Reordering with this data structure lends itself to some handy shortcuts: - * - * Since each run is moved but not modified, and since at the initial maxLevel - * each sequence of same-level runs consists of only one run each, we - * don't need to do anything there and can predecrement maxLevel. - * In many simple cases, the reordering is thus done entirely in the - * index mapping. - * Also, reordering occurs only down to the lowest odd level that occurs, - * which is minLevel|1. However, if the lowest level itself is odd, then - * in the last reordering the sequence of the runs at this level or higher - * will be all runs, and we don't need the elaborate loop to search for them. - * This is covered by ++minLevel instead of minLevel|=1 followed - * by an extra reorder-all after the reorder-some loop. - * About a trailing WS run: - * Such a run would need special treatment because its level is not - * reflected in levels[] if this is not a paragraph object. - * Instead, all characters from trailingWSStart on are implicitly at - * paraLevel. - * However, for all maxLevel>paraLevel, this run will never be reordered - * and does not need to be taken into account. maxLevel==paraLevel is only reordered - * if minLevel==paraLevel is odd, which is done in the extra segment. - * This means that for the main reordering loop we don't need to consider - * this run and can --runCount. If it is later part of the all-runs - * reordering, then runCount is adjusted accordingly. - */ -void nsBidi::ReorderLine(nsBidiLevel aMinLevel, nsBidiLevel aMaxLevel) -{ - Run *runs; - nsBidiLevel *levels; - int32_t firstRun, endRun, limitRun, runCount, temp; - - /* nothing to do? */ - if(aMaxLevel<=(aMinLevel|1)) { - return; - } - - /* - * Reorder only down to the lowest odd level - * and reorder at an odd aMinLevel in a separate, simpler loop. - * See comments above for why aMinLevel is always incremented. - */ - ++aMinLevel; - - runs=mRuns; - levels=mLevels; - runCount=mRunCount; - - /* do not include the WS run at paraLevel<=old aMinLevel except in the simple loop */ - if(mTrailingWSStart=aMinLevel) { - firstRun=0; - - /* loop for all sequences of runs */ - for(;;) { - /* look for a sequence of runs that are all at >=aMaxLevel */ - /* look for the first run of such a sequence */ - while(firstRun=runCount) { - break; /* no more such runs */ - } - - /* look for the limit run of such a sequence (the run behind it) */ - for(limitRun=firstRun; ++limitRun=aMaxLevel;) {} - - /* Swap the entire sequence of runs from firstRun to limitRun-1. */ - endRun=limitRun-1; - while(firstRun=maxLevel */ - /* look for the first index of such a sequence */ - while(start=aLength) { - break; /* no more such runs */ - } - - /* look for the limit of such a sequence (the index behind it) */ - for(limit=start; ++limit=maxLevel;) {} - - /* - * Swap the entire interval of indexes from start to limit-1. - * We don't need to swap the levels for the purpose of this - * algorithm: the sequence of levels that we look at does not - * move anyway. - */ - end=limit-1; - while(start=minLevel); - - return NS_OK; -} - -bool nsBidi::PrepareReorder(const nsBidiLevel *aLevels, int32_t aLength, - int32_t *aIndexMap, - nsBidiLevel *aMinLevel, nsBidiLevel *aMaxLevel) -{ - int32_t start; - nsBidiLevel level, minLevel, maxLevel; - - if(aLevels==nullptr || aLength<=0) { - return false; - } - - /* determine minLevel and maxLevel */ - minLevel=NSBIDI_MAX_EXPLICIT_LEVEL+1; - maxLevel=0; - for(start=aLength; start>0;) { - level=aLevels[--start]; - if(level>NSBIDI_MAX_EXPLICIT_LEVEL+1) { - return false; - } - if(levelmaxLevel) { - maxLevel=level; - } - } - *aMinLevel=minLevel; - *aMaxLevel=maxLevel; - - /* initialize the index map */ - for(start=aLength; start>0;) { - --start; - aIndexMap[start]=start; - } - - return true; -} - -#ifdef FULL_BIDI_ENGINE -/* API functions for logical<->visual mapping ------------------------------- */ - -nsresult nsBidi::GetVisualIndex(int32_t aLogicalIndex, int32_t* aVisualIndex) { - 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) { - length=runs[i].visualLimit-visualStart; - offset=aLogicalIndex-GET_INDEX(runs[i].logicalStart); - if(offset>=0 && offset=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) -{ - nsBidiLevel *levels; - nsresult rv; - - /* GetLevels() checks all of its and our arguments */ - rv = GetLevels(&levels); - if(NS_FAILED(rv)) { - return rv; - } else if(aIndexMap==nullptr) { - return NS_ERROR_INVALID_ARG; - } else { - return ReorderLogical(levels, mLength, aIndexMap); - } -} - -nsresult nsBidi::GetVisualMap(int32_t *aIndexMap) -{ - int32_t* runCount=nullptr; - nsresult rv; - - /* CountRuns() checks all of its and our arguments */ - rv = CountRuns(runCount); - if(NS_FAILED(rv)) { - return rv; - } else if(aIndexMap==nullptr) { - return NS_ERROR_INVALID_ARG; - } 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(; runslogicalStart; - visualLimit=runs->visualLimit; - if(IS_EVEN_RUN(logicalStart)) { - do { /* LTR */ - *aIndexMap++ = logicalStart++; - } while(++visualStart=maxLevel */ - /* look for the first index of such a sequence */ - while(start=aLength) { - break; /* no more such sequences */ - } - - /* look for the limit of such a sequence (the index behind it) */ - for(limit=start; ++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=minLevel); - - return NS_OK; -} - -nsresult nsBidi::InvertMap(const int32_t *aSrcMap, int32_t *aDestMap, int32_t aLength) -{ - if(aSrcMap!=nullptr && aDestMap!=nullptr) { - aSrcMap+=aLength; - while(aLength>0) { - aDestMap[*--aSrcMap]=--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(j0); - 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 && IsBidiCategory(c, eBidiCat_NSM)); - - /* copy this "user character" */ - j=srcLength; - do { - *dest++=src[j++]; - } while(j0); - 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 && IsBidiCategory(c, eBidiCat_NSM)) { - 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 = SymmSwap(c); - - int32_t k=0; - UTF_APPEND_CHAR_UNSAFE(dest, k, c); - dest+=k; - j+=k; - } - while(j0); - 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=aSrc && aDest0) { - *aDestSize = doWriteReverse(aSrc, aSrcLength, aDest, aOptions); - } - return NS_OK; -} -#endif // FULL_BIDI_ENGINE -#endif // IBMBIDI diff --git a/layout/base/nsBidi.h b/layout/base/nsBidi.h deleted file mode 100644 --- a/layout/base/nsBidi.h +++ /dev/null @@ -1,892 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsBidi_h__ -#define nsBidi_h__ - -#include "nsBidiUtils.h" - -// Bidi reordering engine from ICU -/* - * javadoc-style comments are intended to be transformed into HTML - * using DOC++ - see - * http://www.zib.de/Visual/software/doc++/index.html . - * - * The HTML documentation is created with - * doc++ -H nsIBidi.h - */ - -/** - * @mainpage BIDI algorithm for Mozilla (from ICU) - * - *

BIDI algorithm for Mozilla

- * - * This is an implementation of the Unicode Bidirectional algorithm. - * The algorithm is defined in the - * Unicode Technical Report 9, - * version 5, also described in The Unicode Standard, Version 3.0 .

- * - *

General remarks about the API:

- * - * The limit of a sequence of characters is the position just after their - * last character, i.e., one more than that position.

- * - * Some of the API functions provide access to runs. - * Such a run is defined as a sequence of characters - * that are at the same embedding level - * after performing the BIDI algorithm.

- * - * @author Markus W. Scherer. Ported to Mozilla by Simon Montagu - * @version 1.0 - */ - -/** - * nsBidiLevel is the type of the level values in this - * Bidi implementation. - * It holds an embedding level and indicates the visual direction - * by its bit 0 (even/odd value).

- * - * It can also hold non-level values for the - * aParaLevel and aEmbeddingLevels - * arguments of SetPara; there: - *

    - *
  • bit 7 of an aEmbeddingLevels[] - * value indicates whether the using application is - * specifying the level of a character to override whatever the - * Bidi implementation would resolve it to.
  • - *
  • aParaLevel can be set to the - * pseudo-level values NSBIDI_DEFAULT_LTR - * and NSBIDI_DEFAULT_RTL.
- * - * @see nsIBidi::SetPara - * - *

The related constants are not real, valid level values. - * NSBIDI_DEFAULT_XXX can be used to specify - * a default for the paragraph level for - * when the SetPara function - * shall determine it but there is no - * strongly typed character in the input.

- * - * Note that the value for NSBIDI_DEFAULT_LTR is even - * and the one for NSBIDI_DEFAULT_RTL is odd, - * just like with normal LTR and RTL level values - - * these special values are designed that way. Also, the implementation - * assumes that NSBIDI_MAX_EXPLICIT_LEVEL is odd. - * - * @see NSBIDI_DEFAULT_LTR - * @see NSBIDI_DEFAULT_RTL - * @see NSBIDI_LEVEL_OVERRIDE - * @see NSBIDI_MAX_EXPLICIT_LEVEL - */ -typedef uint8_t nsBidiLevel; - -/** Paragraph level setting. - * If there is no strong character, then set the paragraph level to 0 (left-to-right). - */ -#define NSBIDI_DEFAULT_LTR 0xfe - -/** Paragraph level setting. - * If there is no strong character, then set the paragraph level to 1 (right-to-left). - */ -#define NSBIDI_DEFAULT_RTL 0xff - -/** - * Maximum explicit embedding level. - * (The maximum resolved level can be up to NSBIDI_MAX_EXPLICIT_LEVEL+1). - * - */ -#define NSBIDI_MAX_EXPLICIT_LEVEL 61 - -/** Bit flag for level input. - * Overrides directional properties. - */ -#define NSBIDI_LEVEL_OVERRIDE 0x80 - -/** - * nsBidiDirection values indicate the text direction. - */ -enum nsBidiDirection { - /** All left-to-right text This is a 0 value. */ - NSBIDI_LTR, - /** All right-to-left text This is a 1 value. */ - NSBIDI_RTL, - /** Mixed-directional text. */ - NSBIDI_MIXED -}; - -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, \ - mMayAllocateText, (length)) - -#define GETLEVELSMEMORY(length) \ - GetMemory((void **)&mLevelsMemory, &mLevelsSize, \ - mMayAllocateText, (length)) - -#define GETRUNSMEMORY(length) \ - GetMemory((void **)&mRunsMemory, &mRunsSize, \ - mMayAllocateRuns, (length)*sizeof(Run)) - -/* 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)) - -/* - * Sometimes, bit values are more appropriate - * to deal with directionality properties. - * Abbreviations in these macro names refer to names - * used in the Bidi algorithm. - */ -typedef uint8_t DirProp; - -#define DIRPROP_FLAG(dir) (1UL<<(dir)) - -/* special flag for multiple runs from explicit embedding codes */ -#define DIRPROP_FLAG_MULTI_RUNS (1UL<<31) - -/* are there any characters that are LTR or RTL? */ -#define MASK_LTR (DIRPROP_FLAG(L)|DIRPROP_FLAG(EN)|DIRPROP_FLAG(AN)|DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO)) -#define MASK_RTL (DIRPROP_FLAG(R)|DIRPROP_FLAG(AL)|DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO)) - -/* explicit embedding codes */ -#define MASK_LRX (DIRPROP_FLAG(LRE)|DIRPROP_FLAG(LRO)) -#define MASK_RLX (DIRPROP_FLAG(RLE)|DIRPROP_FLAG(RLO)) -#define MASK_OVERRIDE (DIRPROP_FLAG(LRO)|DIRPROP_FLAG(RLO)) - -#define MASK_EXPLICIT (MASK_LRX|MASK_RLX|DIRPROP_FLAG(PDF)) -#define MASK_BN_EXPLICIT (DIRPROP_FLAG(BN)|MASK_EXPLICIT) - -/* paragraph and segment separators */ -#define MASK_B_S (DIRPROP_FLAG(B)|DIRPROP_FLAG(S)) - -/* all types that are counted as White Space or Neutral in some steps */ -#define MASK_WS (MASK_B_S|DIRPROP_FLAG(WS)|MASK_BN_EXPLICIT) -#define MASK_N (DIRPROP_FLAG(O_N)|MASK_WS) - -/* all types that are included in a sequence of European Terminators for (W5) */ -#define MASK_ET_NSM_BN (DIRPROP_FLAG(ET)|DIRPROP_FLAG(NSM)|MASK_BN_EXPLICIT) - -/* types that are neutrals or could becomes neutrals in (Wn) */ -#define MASK_POSSIBLE_N (DIRPROP_FLAG(CS)|DIRPROP_FLAG(ES)|DIRPROP_FLAG(ET)|MASK_N) - -/* - * These types may be changed to "e", - * the embedding type (L or R) of the run, - * in the Bidi algorithm (N2) - */ -#define MASK_EMBEDDING (DIRPROP_FLAG(NSM)|MASK_POSSIBLE_N) - -/* the dirProp's L and R are defined to 0 and 1 values in nsCharType */ -#define GET_LR_FROM_LEVEL(level) ((DirProp)((level)&1)) - -#define IS_DEFAULT_LEVEL(level) (((level)&0xfe)==0xfe) - -/* handle surrogate pairs --------------------------------------------------- */ - -#define IS_FIRST_SURROGATE(uchar) (((uchar)&0xfc00)==0xd800) -#define IS_SECOND_SURROGATE(uchar) (((uchar)&0xfc00)==0xdc00) - -/* get the UTF-32 value directly from the surrogate pseudo-characters */ -#define SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) -#define GET_UTF_32(first, second) (((first)<<10UL)+(second)-SURROGATE_OFFSET) - - -#define UTF_ERROR_VALUE 0xffff -/* definitions with forward iteration --------------------------------------- */ - -/* - * all the macros that go forward assume that - * the initial offset is 0<=i>10)+0xd7c0; \ - (s)[(i)++]=(char16_t)(c)&0x3ff|0xdc00; \ - } \ -} - -/* safe versions with error-checking and optional regularity-checking */ - -#define UTF16_APPEND_CHAR_SAFE(s, i, length, c) { \ - if((PRUInt32)(c)<=0xffff) { \ - (s)[(i)++]=(char16_t)(c); \ - } else if((PRUInt32)(c)<=0x10ffff) { \ - if((i)+1<(length)) { \ - (s)[(i)++]=(char16_t)((c)>>10)+0xd7c0; \ - (s)[(i)++]=(char16_t)(c)&0x3ff|0xdc00; \ - } else /* not enough space */ { \ - (s)[(i)++]=UTF_ERROR_VALUE; \ - } \ - } else /* c>0x10ffff, write error value */ { \ - (s)[(i)++]=UTF_ERROR_VALUE; \ - } \ -} - -/* definitions with backward iteration -------------------------------------- */ - -/* - * all the macros that go backward assume that - * the valid buffer range starts at offset 0 - * and that the initial offset is 00) { \ - UTF16_BACK_1_UNSAFE(s, i); \ - --__N; \ - } \ -} - -/* safe versions with error-checking and optional regularity-checking */ - -#define UTF16_PREV_CHAR_SAFE(s, start, i, c, strict) { \ - (c)=(s)[--(i)]; \ - if(IS_SECOND_SURROGATE(c)) { \ - char16_t __c2; \ - if((i)>(start) && IS_FIRST_SURROGATE(__c2=(s)[(i)-1])) { \ - --(i); \ - (c)=GET_UTF_32(__c2, (c)); \ - /* strict: ((c)&0xfffe)==0xfffe is caught by UTF_IS_ERROR() */ \ - } else if(strict) {\ - /* unmatched second surrogate */ \ - (c)=UTF_ERROR_VALUE; \ - } \ - } else if(strict && IS_FIRST_SURROGATE(c)) { \ - /* unmatched first surrogate */ \ - (c)=UTF_ERROR_VALUE; \ - /* else strict: (c)==0xfffe is caught by UTF_IS_ERROR() */ \ - } \ -} - -#define UTF16_BACK_1_SAFE(s, start, i) { \ - if(IS_SECOND_SURROGATE((s)[--(i)]) && (i)>(start) && IS_FIRST_SURROGATE((s)[(i)-1])) { \ - --(i); \ - } \ -} - -#define UTF16_BACK_N_SAFE(s, start, i, n) { \ - int32_t __N=(n); \ - while(__N>0 && (i)>(start)) { \ - UTF16_BACK_1_SAFE(s, start, i); \ - --__N; \ - } \ -} - -#define UTF_PREV_CHAR_UNSAFE(s, i, c) UTF16_PREV_CHAR_UNSAFE(s, i, c) -#define UTF_PREV_CHAR_SAFE(s, start, i, c, strict) UTF16_PREV_CHAR_SAFE(s, start, i, c, strict) -#define UTF_BACK_1_UNSAFE(s, i) UTF16_BACK_1_UNSAFE(s, i) -#define UTF_BACK_1_SAFE(s, start, i) UTF16_BACK_1_SAFE(s, start, i) -#define UTF_BACK_N_UNSAFE(s, i, n) UTF16_BACK_N_UNSAFE(s, i, n) -#define UTF_BACK_N_SAFE(s, start, i, n) UTF16_BACK_N_SAFE(s, start, i, n) -#define UTF_APPEND_CHAR_UNSAFE(s, i, c) UTF16_APPEND_CHAR_UNSAFE(s, i, c) -#define UTF_APPEND_CHAR_SAFE(s, i, length, c) UTF16_APPEND_CHAR_SAFE(s, i, length, c) - -#define UTF_PREV_CHAR(s, start, i, c) UTF_PREV_CHAR_SAFE(s, start, i, c, false) -#define UTF_BACK_1(s, start, i) UTF_BACK_1_SAFE(s, start, i) -#define UTF_BACK_N(s, start, i, n) UTF_BACK_N_SAFE(s, start, i, n) -#define UTF_APPEND_CHAR(s, i, length, c) UTF_APPEND_CHAR_SAFE(s, i, length, c) - -/* Run structure for reordering --------------------------------------------- */ - -typedef struct Run { - int32_t logicalStart, /* first character of the run; b31 indicates even/odd level */ - visualLimit; /* last visual position of the run +1 */ -} Run; - -/* in a Run, logicalStart will get this bit set if the run level is odd */ -#define INDEX_ODD_BIT (1UL<<31) - -#define MAKE_INDEX_ODD_PAIR(index, level) (index|((uint32_t)level<<31)) -#define ADD_ODD_BIT_FROM_LEVEL(x, level) ((x)|=((uint32_t)level<<31)) -#define REMOVE_ODD_BIT(x) ((x)&=~INDEX_ODD_BIT) - -#define GET_INDEX(x) (x&~INDEX_ODD_BIT) -#define GET_ODD_BIT(x) ((uint32_t)x>>31) -#define IS_ODD_RUN(x) ((x&INDEX_ODD_BIT)!=0) -#define IS_EVEN_RUN(x) ((x&INDEX_ODD_BIT)==0) - -typedef uint32_t Flags; - -/** - * This class holds information about a paragraph of text - * with Bidi-algorithm-related details, or about one line of - * such a paragraph.

- * Reordering can be done on a line, or on a paragraph which is - * then interpreted as one single line.

- * - * On construction, the class is initially empty. It is assigned - * the Bidi properties of a paragraph by SetPara - * or the Bidi properties of a line of a paragraph by - * SetLine.

- * A Bidi class can be reused for as long as it is not deallocated - * by calling its destructor.

- * SetPara will allocate additional memory for - * internal structures as necessary. - */ -class nsBidi -{ -public: - /** @brief Default constructor. - * - * The nsBidi object is initially empty. It is assigned - * the Bidi properties of a paragraph by SetPara() - * or the Bidi properties of a line of a paragraph by - * GetLine().

- * This object can be reused for as long as it is not destroyed.

- * SetPara() will allocate additional memory for - * internal structures as necessary. - * - */ - nsBidi(); - - /** @brief Destructor. */ - virtual ~nsBidi(); - - - /** - * Perform the Unicode Bidi algorithm. It is defined in the - * Unicode Technical Report 9, - * version 5, - * also described in The Unicode Standard, Version 3.0 .

- * - * This function takes a single plain text paragraph with or without - * externally specified embedding levels from styled text - * and computes the left-right-directionality of each character.

- * - * If the entire paragraph consists of text of only one direction, then - * the function may not perform all the steps described by the algorithm, - * i.e., some levels may not be the same as if all steps were performed. - * This is not relevant for unidirectional text.
- * For example, in pure LTR text with numbers the numbers would get - * a resolved level of 2 higher than the surrounding text according to - * the algorithm. This implementation may set all resolved levels to - * the same value in such a case.

- * - * The text must be externally split into separate paragraphs (rule P1). - * Paragraph separators (B) should appear at most at the very end. - * - * @param aText is a pointer to the single-paragraph text that the - * Bidi algorithm will be performed on - * (step (P1) of the algorithm is performed externally). - * The text must be (at least) aLength long. - * - * @param aLength is the length of the text; if aLength==-1 then - * the text must be zero-terminated. - * - * @param aParaLevel specifies the default level for the paragraph; - * it is typically 0 (LTR) or 1 (RTL). - * If the function shall determine the paragraph level from the text, - * then aParaLevel can be set to - * either NSBIDI_DEFAULT_LTR - * or NSBIDI_DEFAULT_RTL; - * if there is no strongly typed character, then - * the desired default is used (0 for LTR or 1 for RTL). - * Any other value between 0 and NSBIDI_MAX_EXPLICIT_LEVEL 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 - * NSBIDI_LEVEL_OVERRIDE bit set.

- * Except for that bit, it must be - * aParaLevel<=aEmbeddingLevels[]<=NSBIDI_MAX_EXPLICIT_LEVEL.

- * Caution: A copy of this pointer, not of the levels, - * will be stored in the nsBidi object; - * the aEmbeddingLevels array must not be - * deallocated before the nsBidi object is destroyed or reused, - * and the aEmbeddingLevels - * should not be modified to avoid unexpected results on subsequent Bidi operations. - * However, the SetPara and - * SetLine functions may modify some or all of the levels.

- * After the nsBidi object is reused or destroyed, the caller - * must take care of the deallocation of the aEmbeddingLevels array.

- * The aEmbeddingLevels array must be - * at least aLength long. - */ - nsresult SetPara(const char16_t *aText, int32_t aLength, nsBidiLevel aParaLevel, nsBidiLevel *aEmbeddingLevels); - - /** - * Get the directionality of the text. - * - * @param aDirection receives a NSBIDI_XXX value that indicates if the entire text - * represented by this object is unidirectional, - * and which direction, or if it is mixed-directional. - * - * @see nsBidiDirection - */ - nsresult GetDirection(nsBidiDirection* aDirection); - - /** - * Get the paragraph level of the text. - * - * @param aParaLevel receives a NSBIDI_XXX value indicating the paragraph level - * - * @see nsBidiLevel - */ - nsresult GetParaLevel(nsBidiLevel* aParaLevel); - -#ifdef FULL_BIDI_ENGINE - /** - * SetLine sets an nsBidi 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 nsBidi object representing - * this information for a paragraph of text, and by specifying - * a range of indexes in this paragraph.

- * In the new line object, the indexes will range from 0 to aLimit-aStart.

- * - * This is used after calling SetPara - * for a paragraph, and after line-breaking on that paragraph. - * It is not necessary if the paragraph is treated as a single line.

- * - * After line-breaking, rules (L1) and (L2) for the treatment of - * trailing WS and for reordering are performed on - * an nsBidi object that represents a line.

- * - * Important: the line nsBidi object shares data with - * aParaBidi. - * You must destroy or reuse this object before aParaBidi. - * In other words, you must destroy or reuse the nsBidi 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).
- * It must be 0<=aStart<=aLimit<=paragraph length. - * - * @see SetPara - */ - nsresult SetLine(nsIBidi* 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.

- * - * Note that this function may allocate memory under some - * circumstances, unlike GetLevelAt. - * - * @param aLevels receives a pointer to the levels array for the text, - * or nullptr if an error occurs. - * - * @see nsBidiLevel - */ - nsresult GetLevels(nsBidiLevel** aLevels); -#endif // FULL_BIDI_ENGINE - /** - * Get the bidirectional type for one character. - * - * @param aCharIndex the index of a character. - * - * @param aType receives the bidirectional type of the character at aCharIndex. - */ - nsresult GetCharTypeAt(int32_t aCharIndex, nsCharType* aType); - - /** - * Get a logical run. - * This function returns information about a run and is used - * to retrieve runs in logical order.

- * This is especially useful for line-breaking on a paragraph. - * - * @param aLogicalStart is the first character of the run. - * - * @param aLogicalLimit will receive the limit of the run. - * The l-value that you point to here may be the - * same expression (variable) as the one for - * aLogicalStart. - * This pointer can be nullptr if this - * value is not necessary. - * - * @param aLevel will receive the level of the run. - * This pointer can be nullptr if this - * value is not necessary. - */ - nsresult GetLogicalRun(int32_t aLogicalStart, int32_t* aLogicalLimit, nsBidiLevel* aLevel); - - /** - * Get the number of runs. - * This function may invoke the actual reordering on the - * nsBidi object, after SetPara - * may have resolved only the levels of the text. Therefore, - * CountRuns may have to allocate memory, - * and may fail doing so. - * - * @param aRunCount will receive the number of runs. - */ - nsresult CountRuns(int32_t* aRunCount); - - /** - * Get one run's logical start, length, and directionality, - * which can be 0 for LTR or 1 for RTL. - * In an RTL run, the character at the logical start is - * visually on the right of the displayed run. - * The length is the number of characters in the run.

- * CountRuns should be called - * before the runs are retrieved. - * - * @param aRunIndex is the number of the run in visual order, in the - * range [0..CountRuns-1]. - * - * @param aLogicalStart is the first logical character index in the text. - * The pointer may be nullptr if this index is not needed. - * - * @param aLength is the number of characters (at least one) in the run. - * The pointer may be nullptr if this is not needed. - * - * @param aDirection will receive the directionality of the run, - * NSBIDI_LTR==0 or NSBIDI_RTL==1, - * never NSBIDI_MIXED. - * - * @see CountRuns

- * - * Example: - * @code - * int32_t i, count, logicalStart, visualIndex=0, length; - * nsBidiDirection dir; - * pBidi->CountRuns(&count); - * for(i=0; iGetVisualRun(i, &logicalStart, &length, &dir); - * if(NSBIDI_LTR==dir) { - * do { // LTR - * show_char(text[logicalStart++], visualIndex++); - * } while(--length>0); - * } else { - * logicalStart+=length; // logicalLimit - * do { // RTL - * show_char(text[--logicalStart], visualIndex++); - * } while(--length>0); - * } - * } - * @endcode - * - * Note that in right-to-left runs, code like this places - * modifier letters before base characters and second surrogates - * before first ones. - */ - 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 - * nsBidi object, then calling - * GetLogicalMap is more efficient.

- * - * 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 - * nsBidi object, then calling - * GetVisualMap is more efficient.

- * - * This is the inverse function to GetVisualIndex. - * - * @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 GetLength - * indexes which will reflect the reordering of the characters. - * The array does not need to be initialized.

- * The index map will result in aIndexMap[aLogicalIndex]==aVisualIndex.

- * - * @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 GetLength - * indexes which will reflect the reordering of the characters. - * The array does not need to be initialized.

- * The index map will result in aIndexMap[aVisualIndex]==aLogicalIndex.

- * - * @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 GetLogicalMap on a - * nsBidi object. - * - * @param aLevels is an array with aLength 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 aLength>0. - * - * @param aIndexMap is a pointer to an array of aLength - * indexes which will reflect the reordering of the characters. - * The array does not need to be initialized.

- * The index map will result in aIndexMap[aLogicalIndex]==aVisualIndex. - */ - 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 - * of objects (character sequences) and just needs to have them reordered (L2). - * This is equivalent to using GetVisualMap on a - * nsBidi object. - * - * @param aLevels is an array with aLength 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 aLength>0. - * - * @param aIndexMap is a pointer to an array of aLength - * indexes which will reflect the reordering of the characters. - * The array does not need to be initialized.

- * The index map will result in aIndexMap[aVisualIndex]==aLogicalIndex. - */ - 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 aLength indexes - * which define the original mapping. - * - * @param aDestMap is an array with aLength 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. - * - * This function preserves the integrity of characters with multiple - * code units and (optionally) modifier letters. - * Characters can be replaced by mirror-image characters - * in the destination buffer. Note that "real" mirroring has - * to be done in a rendering engine by glyph selection - * and that for many "mirrored" characters there are no - * Unicode characters as mirror-image equivalents. - * There are also options to insert or remove Bidi control - * characters; see the description of the aDestSize - * and aOptions parameters and of the option bit flags. - * - * Since no Bidi controls are inserted here, this function will never - * write more than aSrcLength characters to aDest. - * - * @param aSrc A pointer to the RTL run text. - * - * @param aSrcLength The length of the RTL run. - * If the NSBIDI_REMOVE_BIDI_CONTROLS option - * is set, then the destination length may be less than - * aSrcLength. - * If this option is not set, then the destination length - * will be exactly aSrcLength. - * - * @param aDest A pointer to where the reordered text is to be copied. - * aSrc[aSrcLength] and aDest[aSrcLength] - * must not overlap. - * - * @param aOptions A bit set of options for the reordering that control - * how the reordered text is written. - * - * @param aDestSize will receive the number of characters that were written to aDest. - */ - nsresult WriteReverse(const char16_t *aSrc, int32_t aSrcLength, char16_t *aDest, uint16_t aOptions, int32_t *aDestSize); - -protected: - friend class nsBidiPresUtils; - - /** length of the current text */ - int32_t mLength; - - /** memory sizes in bytes */ - size_t mDirPropsSize, mLevelsSize, mRunsSize; - - /** allocated memory */ - DirProp* mDirPropsMemory; - nsBidiLevel* mLevelsMemory; - Run* mRunsMemory; - - /** indicators for whether memory may be allocated after construction */ - bool mMayAllocateText, mMayAllocateRuns; - - const DirProp* mDirProps; - nsBidiLevel* mLevels; - - /** the paragraph level */ - nsBidiLevel mParaLevel; - - /** flags is a bit set for which directional properties are in the text */ - Flags mFlags; - - /** the overall paragraph or line directionality - see nsBidiDirection */ - nsBidiDirection mDirection; - - /** characters after trailingWSStart are WS and are */ - /* implicitly at the paraLevel (rule (L1)) - levels may not reflect that */ - int32_t mTrailingWSStart; - - /** fields for line reordering */ - int32_t mRunCount; /* ==-1: runs not set up yet */ - Run* mRuns; - - /** for non-mixed text, we only need a tiny array of runs (no malloc()) */ - Run mSimpleRuns[1]; - -private: - - void Init(); - - bool GetMemory(void **aMemory, size_t* aSize, bool aMayAllocate, size_t aSizeNeeded); - - void Free(); - - void GetDirProps(const char16_t *aText); - - nsBidiDirection ResolveExplicitLevels(); - - nsresult CheckExplicitLevels(nsBidiDirection *aDirection); - - nsBidiDirection DirectionFromFlags(Flags aFlags); - - void ResolveImplicitLevels(int32_t aStart, int32_t aLimit, DirProp aSOR, DirProp aEOR); - - void AdjustWSLevels(); - - void SetTrailingWSStart(); - - bool GetRuns(); - - void GetSingleRun(nsBidiLevel aLevel); - - 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_ diff --git a/layout/base/nsBidiPresUtils.cpp b/layout/base/nsBidiPresUtils.cpp --- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -16,17 +16,17 @@ #include "nsPlaceholderFrame.h" #include "nsFirstLetterFrame.h" #include "nsUnicodeProperties.h" #include "nsTextFrame.h" #include "nsBlockFrame.h" #include "nsIFrameInlines.h" #include -#undef NOISY_BIDI +#define NOISY_BIDI #undef REALLY_NOISY_BIDI using namespace mozilla; static const char16_t kSpace = 0x0020; static const char16_t kZWSP = 0x200B; static const char16_t kLineSeparator = 0x2028; static const char16_t kObjectSubstitute = 0xFFFC; @@ -41,26 +41,31 @@ static const char16_t kPDF struct BidiParagraphData { nsString mBuffer; nsAutoTArray mEmbeddingStack; nsTArray mLogicalFrames; nsTArray mLinePerFrame; nsDataHashtable mContentToFrameIndex; bool mIsVisual; bool mReset; - nsBidiLevel mParaLevel; + UBiDiLevel mParaLevel; nsIContent* mPrevContent; - nsAutoPtr mBidiEngine; + UBiDi* mBidi; nsIFrame* mPrevFrame; nsAutoPtr mSubParagraph; uint8_t mParagraphDepth; + ~BidiParagraphData() + { + ubidi_close(mBidi); + } + void Init(nsBlockFrame *aBlockFrame) { - mBidiEngine = new nsBidi(); + mBidi = ubidi_open(); mPrevContent = nullptr; mParagraphDepth = 0; mParaLevel = nsBidiPresUtils::BidiLevelFromStyle(aBlockFrame->StyleContext()); mIsVisual = aBlockFrame->PresContext()->IsVisualMode(); if (mIsVisual) { /** @@ -96,17 +101,17 @@ struct BidiParagraphData { } return mSubParagraph; } // Initialise a sub-paragraph from its containing paragraph void Init(BidiParagraphData *aBpd) { - mBidiEngine = new nsBidi(); + mBidi = ubidi_open(); mPrevContent = nullptr; mIsVisual = aBpd->mIsVisual; mReset = false; } void Reset(nsIFrame* aBDIFrame, BidiParagraphData *aBpd) { mReset = true; @@ -117,17 +122,17 @@ struct BidiParagraphData { mPrevFrame = aBpd->mPrevFrame; mParagraphDepth = aBpd->mParagraphDepth + 1; const nsStyleTextReset* text = aBDIFrame->StyleTextReset(); bool isRTL = (NS_STYLE_DIRECTION_RTL == aBDIFrame->StyleVisibility()->mDirection); if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT) { - mParaLevel = NSBIDI_DEFAULT_LTR; + mParaLevel = UBIDI_DEFAULT_LTR; } else { mParaLevel = mParagraphDepth * 2; if (isRTL) ++mParaLevel; } if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) { PushBidiControl(isRTL ? kRLO : kLRO); } @@ -135,52 +140,65 @@ struct BidiParagraphData { void EmptyBuffer() { mBuffer.SetLength(0); } nsresult SetPara() { - return mBidiEngine->SetPara(mBuffer.get(), BufferLength(), - mParaLevel, nullptr); + UErrorCode errorCode = U_ZERO_ERROR; + ubidi_setPara(mBidi, (UChar*)mBuffer.get(), BufferLength(), + mParaLevel, nullptr, &errorCode); + + // XXX need some mapping from ICU error codes to nsresults +#ifdef DEBUG +#ifdef REALLY_NOISY_BIDI + if (U_FAILURE(errorCode)) { + printf("ubidi_setPara returns %x\n", errorCode); + } +#endif +#endif + + return U_SUCCESS(errorCode) ? NS_OK : NS_ERROR_FAILURE; } /** - * mParaLevel can be NSBIDI_DEFAULT_LTR as well as NSBIDI_LTR or NSBIDI_RTL. + * mParaLevel can be UBIDI_DEFAULT_LTR as well as UBIDI_LTR or UBIDI_RTL. * GetParaLevel() returns the actual (resolved) paragraph level which is - * always either NSBIDI_LTR or NSBIDI_RTL + * always either UBIDI_LTR or UBIDI_RTL */ - nsBidiLevel GetParaLevel() + UBiDiLevel GetParaLevel() { - nsBidiLevel paraLevel = mParaLevel; - if (IS_DEFAULT_LEVEL(paraLevel)) { - mBidiEngine->GetParaLevel(¶Level); + UBiDiLevel paraLevel = mParaLevel; + if (paraLevel >= UBIDI_DEFAULT_LTR) { + paraLevel = ubidi_getParaLevel(mBidi); } return paraLevel; } - nsBidiDirection GetDirection() + UBiDiDirection GetDirection() { - nsBidiDirection dir; - mBidiEngine->GetDirection(&dir); - return dir; + return ubidi_getDirection(mBidi); } - nsresult CountRuns(int32_t *runCount){ return mBidiEngine->CountRuns(runCount); } + nsresult CountRuns(int32_t *runCount){ + UErrorCode errorCode = U_ZERO_ERROR; + *runCount = ubidi_countRuns(mBidi, &errorCode); + return U_SUCCESS(errorCode) ? NS_OK : NS_ERROR_FAILURE; + } - nsresult GetLogicalRun(int32_t aLogicalStart, - int32_t* aLogicalLimit, - nsBidiLevel* aLevel) + void GetLogicalRun(int32_t aLogicalStart, + int32_t* aLogicalLimit, + UBiDiLevel* aLevel) { - nsresult rv = mBidiEngine->GetLogicalRun(aLogicalStart, - aLogicalLimit, aLevel); - if (mIsVisual || NS_FAILED(rv)) + ubidi_getLogicalRun(mBidi, aLogicalStart, aLogicalLimit, aLevel); + if (mIsVisual) { *aLevel = GetParaLevel(); - return rv; + } } void ResetData() { mLogicalFrames.Clear(); mLinePerFrame.Clear(); mContentToFrameIndex.Clear(); mBuffer.SetLength(0); @@ -349,18 +367,17 @@ struct BidiLineData { mLevels.AppendElement(level); mIndexMap.AppendElement(0); if (level & 1) { hasRTLFrames = true; } } // Reorder the line - nsBidi::ReorderVisual(mLevels.Elements(), FrameCount(), - mIndexMap.Elements()); + ubidi_reorderVisual(mLevels.Elements(), FrameCount(), mIndexMap.Elements()); for (int32_t i = 0; i < FrameCount(); i++) { mVisualFrames.AppendElement(LogicalFrameAt(mIndexMap[i])); if (i != mIndexMap[i]) { isReordered = true; } } @@ -564,20 +581,19 @@ CreateContinuation(nsIFrame* aFrame, * will make the Unicode Bidi Algorithm give the correct results. * Bidi embeddings and overrides set by CSS or elements are * represented by the corresponding Unicode control characters. *
elements are represented by U+2028 LINE SEPARATOR * Other inline elements are represented by U+FFFC OBJECT REPLACEMENT * CHARACTER * * Then pass mBuffer to the Bidi engine for resolving of embedding levels - * by nsBidi::SetPara() and division into directional runs by - * nsBidi::CountRuns(). + * by ubidi_setPara() and division into directional runs by ubidi_countRuns(). * - * Finally, walk these runs in logical order using nsBidi::GetLogicalRun() and + * Finally, walk these runs in logical order using ubidi_getLogicalRun() and * correlate them with the frames indexed in mLogicalFrames, setting the * baseLevel and embeddingLevel properties according to the results returned * by the Bidi engine. * * The rendering layer requires each text frame to contain text in only one * direction, so we may need to call EnsureBidiContinuation() to split frames. * We may also need to call RemoveBidiContinuation() to convert frames created * by EnsureBidiContinuation() in previous reflows into fluid continuations. @@ -669,17 +685,17 @@ nsBidiPresUtils::ResolveParagraph(nsBloc #ifdef REALLY_NOISY_BIDI printf(" block frame tree=:\n"); aBlockFrame->List(stdout, 0); #endif #endif #endif if (runCount == 1 && frameCount == 1 && - aBpd->mParagraphDepth == 0 && aBpd->GetDirection() == NSBIDI_LTR && + aBpd->mParagraphDepth == 0 && aBpd->GetDirection() == UBIDI_LTR && aBpd->GetParaLevel() == 0) { // We have a single left-to-right frame in a left-to-right paragraph, // without bidi isolation from the surrounding text. // Make sure that the embedding level and base level frame properties aren't // set (because if they are this frame used to have some other direction, // so we can't do this optimization), and we're done. nsIFrame* frame = aBpd->FrameAt(0); if (frame != NS_BIDI_CONTROL_FRAME && @@ -749,20 +765,17 @@ nsBidiPresUtils::ResolveParagraph(nsBloc } // if (fragmentLength <= 0) if (runLength <= 0) { // Get the next run of text from the Bidi engine if (++numRun >= runCount) { break; } lineOffset = logicalLimit; - if (NS_FAILED(aBpd->GetLogicalRun( - lineOffset, &logicalLimit, &embeddingLevel) ) ) { - break; - } + aBpd->GetLogicalRun(lineOffset, &logicalLimit, &embeddingLevel); runLength = logicalLimit - lineOffset; } // if (runLength <= 0) if (frame == NS_BIDI_CONTROL_FRAME) { frame = nullptr; ++lineOffset; } else { @@ -1236,30 +1249,30 @@ nsBidiPresUtils::GetFirstLeaf(nsIFrame* nsIFrame* firstChild = firstLeaf->GetFirstPrincipalChild(); nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(firstChild); firstLeaf = (realFrame->GetType() == nsGkAtoms::letterFrame) ? realFrame : firstChild; } return firstLeaf; } -nsBidiLevel +UBiDiLevel nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame) { return NS_GET_EMBEDDING_LEVEL(nsBidiPresUtils::GetFirstLeaf(aFrame)); } uint8_t nsBidiPresUtils::GetParagraphDepth(nsIFrame* aFrame) { return NS_GET_PARAGRAPH_DEPTH(nsBidiPresUtils::GetFirstLeaf(aFrame)); } -nsBidiLevel +UBiDiLevel nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame) { nsIFrame* firstLeaf = aFrame; while (!IsBidiLeaf(firstLeaf)) { firstLeaf = firstLeaf->GetFirstPrincipalChild(); } return NS_GET_BASE_LEVEL(firstLeaf); } @@ -1581,20 +1594,20 @@ nsBidiPresUtils::EnsureBidiContinuation( void nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd, nsIFrame* aFrame, int32_t aFirstIndex, int32_t aLastIndex, int32_t& aOffset) { FrameProperties props = aFrame->Properties(); - nsBidiLevel embeddingLevel = - (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty())); - nsBidiLevel baseLevel = - (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty())); + UBiDiLevel embeddingLevel = + (UBiDiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty())); + UBiDiLevel baseLevel = + (UBiDiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty())); uint8_t paragraphDepth = NS_PTR_TO_INT32(props.Get(nsIFrame::ParagraphDepthProperty())); for (int32_t index = aFirstIndex + 1; index <= aLastIndex; index++) { nsIFrame* frame = aBpd->FrameAt(index); if (frame == NS_BIDI_CONTROL_FRAME) { ++aOffset; } @@ -1631,17 +1644,17 @@ nsBidiPresUtils::RemoveBidiContinuation( next->SetPrevContinuation(lastFrame); } } nsresult nsBidiPresUtils::FormatUnicodeText(nsPresContext* aPresContext, char16_t* aText, int32_t& aTextLength, - nsCharType aCharType, + UCharDirection aCharDirection, bool aIsOddLevel) { nsresult rv = NS_OK; // ahmed //adjusted for correct numeral shaping uint32_t bidiOptions = aPresContext->GetBidi(); switch (GET_BIDI_OPTION_NUMERAL(bidiOptions)) { @@ -1654,42 +1667,42 @@ nsBidiPresUtils::FormatUnicodeText(nsPre break; case IBMBIDI_NUMERAL_PERSIAN: HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_PERSIAN); break; case IBMBIDI_NUMERAL_REGULAR: - switch (aCharType) { + switch (aCharDirection) { - case eCharType_EuropeanNumber: + case U_EUROPEAN_NUMBER: HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC); break; - case eCharType_ArabicNumber: + case U_ARABIC_NUMBER: HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_HINDI); break; default: break; } break; case IBMBIDI_NUMERAL_HINDICONTEXT: - if ( ( (aIsOddLevel) && (IS_ARABIC_DIGIT (aText[0])) ) || (eCharType_ArabicNumber == aCharType) ) + if ( ( (aIsOddLevel) && (IS_ARABIC_DIGIT (aText[0])) ) || (U_ARABIC_NUMBER == aCharDirection) ) HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_HINDI); - else if (eCharType_EuropeanNumber == aCharType) + else if (U_EUROPEAN_NUMBER == aCharDirection) HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC); break; case IBMBIDI_NUMERAL_PERSIANCONTEXT: - if ( ( (aIsOddLevel) && (IS_ARABIC_DIGIT (aText[0])) ) || (eCharType_ArabicNumber == aCharType) ) + if ( ( (aIsOddLevel) && (IS_ARABIC_DIGIT (aText[0])) ) || (U_ARABIC_NUMBER == aCharDirection) ) HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_PERSIAN); - else if (eCharType_EuropeanNumber == aCharType) + else if (U_EUROPEAN_NUMBER == aCharDirection) HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC); break; case IBMBIDI_NUMERAL_NOMINAL: default: break; } @@ -1737,168 +1750,165 @@ RemoveDiacritics(char16_t* aText, } aTextLength = i - offset; aText[aTextLength] = 0; } } #endif void -nsBidiPresUtils::CalculateCharType(nsBidi* aBidiEngine, - const char16_t* aText, - int32_t& aOffset, - int32_t aCharTypeLimit, - int32_t& aRunLimit, - int32_t& aRunLength, - int32_t& aRunCount, - uint8_t& aCharType, - uint8_t& aPrevCharType) +nsBidiPresUtils::CalculateCharDirection(UBiDi* aBidiPara, + const char16_t* aText, + int32_t& aOffset, + int32_t aCharDirectionLimit, + int32_t& aRunLimit, + int32_t& aRunLength, + int32_t& aRunCount, + UCharDirection& aCharDirection, + UCharDirection& aPrevCharDirection) { - bool strongTypeFound = false; + bool strongDirectionFound = false; int32_t offset; - nsCharType charType; + UCharDirection charDirection; - aCharType = eCharType_OtherNeutral; + aCharDirection = U_OTHER_NEUTRAL; - for (offset = aOffset; offset < aCharTypeLimit; offset++) { - // Make sure we give RTL chartype to all characters that would be classified - // as Right-To-Left by a bidi platform. - // (May differ from the UnicodeData, eg we set RTL chartype to some NSMs.) + for (offset = aOffset; offset < aCharDirectionLimit; offset++) { + // Make sure we give RTL direction to all characters that would be + // classified as Right-To-Left by a bidi platform. + // (May differ from the UnicodeData, eg we set RTL direction to some NSMs.) if (IS_HEBREW_CHAR(aText[offset]) ) { - charType = eCharType_RightToLeft; + charDirection = U_RIGHT_TO_LEFT; } else if (IS_ARABIC_ALPHABETIC(aText[offset]) ) { - charType = eCharType_RightToLeftArabic; + charDirection = U_RIGHT_TO_LEFT_ARABIC; } else { - aBidiEngine->GetCharTypeAt(offset, &charType); + charDirection = ubidi_getCustomizedClass(aBidiPara, aText[offset]); } - if (!CHARTYPE_IS_WEAK(charType) ) { + if (!CHARDIRECTION_IS_WEAK(charDirection) ) { - if (strongTypeFound - && (charType != aPrevCharType) - && (CHARTYPE_IS_RTL(charType) || CHARTYPE_IS_RTL(aPrevCharType) ) ) { + if (strongDirectionFound + && (charDirection != aPrevCharDirection) + && (CHARDIRECTION_IS_RTL(charDirection) || + CHARDIRECTION_IS_RTL(aPrevCharDirection))) { // Stop at this point to ensure uni-directionality of the text // (from platform's point of view). // Also, don't mix Arabic and Hebrew content (since platform may // provide BIDI support to one of them only). aRunLength = offset - aOffset; aRunLimit = offset; ++aRunCount; break; } - if ( (eCharType_RightToLeftArabic == aPrevCharType - || eCharType_ArabicNumber == aPrevCharType) - && eCharType_EuropeanNumber == charType) { - charType = eCharType_ArabicNumber; + if ( (U_RIGHT_TO_LEFT_ARABIC == aPrevCharDirection + || U_ARABIC_NUMBER == aPrevCharDirection) + && U_EUROPEAN_NUMBER == charDirection) { + charDirection = U_ARABIC_NUMBER; } - // Set PrevCharType to the last strong type in this frame + // Set PrevCharDirection to the last strong direction in this frame // (for correct numeric shaping) - aPrevCharType = charType; + aPrevCharDirection = charDirection; - strongTypeFound = true; - aCharType = charType; + strongDirectionFound = true; + aCharDirection = charDirection; } } aOffset = offset; } nsresult nsBidiPresUtils::ProcessText(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, BidiProcessor& aprocessor, Mode aMode, nsBidiPositionResolve* aPosResolve, int32_t aPosResolveCount, nscoord* aWidth, - nsBidi* aBidiEngine) + UBiDi* aBidiPara) { NS_ASSERTION((aPosResolve == nullptr) != (aPosResolveCount > 0), "Incorrect aPosResolve / aPosResolveCount arguments"); - int32_t runCount; - nsAutoString textBuffer(aText, aLength); - nsresult rv = aBidiEngine->SetPara(aText, aLength, aBaseLevel, nullptr); - if (NS_FAILED(rv)) - return rv; + UErrorCode errorCode = U_ZERO_ERROR; + ubidi_setPara(aBidiPara, (UChar*)aText, aLength, aBaseLevel, + nullptr, &errorCode); + if (U_FAILURE(errorCode)) + return NS_ERROR_FAILURE; - rv = aBidiEngine->CountRuns(&runCount); - if (NS_FAILED(rv)) - return rv; + int32_t runCount = ubidi_countRuns(aBidiPara, &errorCode); + if (U_FAILURE(errorCode)) + return NS_ERROR_FAILURE; nscoord xOffset = 0; nscoord width, xEndRun = 0; nscoord totalWidth = 0; int32_t i, start, limit, length; uint32_t visualStart = 0; - uint8_t charType; - uint8_t prevType = eCharType_LeftToRight; - nsBidiLevel level; - + UCharDirection charDirection; + UCharDirection prevDirection = U_LEFT_TO_RIGHT; + UBiDiLevel level; + for(int nPosResolve=0; nPosResolve < aPosResolveCount; ++nPosResolve) { aPosResolve[nPosResolve].visualIndex = kNotFound; aPosResolve[nPosResolve].visualLeftTwips = kNotFound; aPosResolve[nPosResolve].visualWidth = kNotFound; } for (i = 0; i < runCount; i++) { - nsBidiDirection dir; - rv = aBidiEngine->GetVisualRun(i, &start, &length, &dir); - if (NS_FAILED(rv)) - return rv; - - rv = aBidiEngine->GetLogicalRun(start, &limit, &level); - if (NS_FAILED(rv)) - return rv; + ubidi_getVisualRun(aBidiPara, i, &start, &length); + ubidi_getLogicalRun(aBidiPara, start, &limit, &level); int32_t subRunLength = limit - start; int32_t lineOffset = start; - int32_t typeLimit = std::min(limit, aLength); + int32_t directionLimit = std::min(limit, aLength); int32_t subRunCount = 1; - int32_t subRunLimit = typeLimit; + int32_t subRunLimit = directionLimit; /* * If |level| is even, i.e. the direction of the run is left-to-right, we * render the subruns from left to right and increment the x-coordinate * |xOffset| by the width of each subrun after rendering. * * If |level| is odd, i.e. the direction of the run is right-to-left, we * render the subruns from right to left. We begin by incrementing |xOffset| by * the width of the whole run, and then decrement it by the width of each * subrun before rendering. After rendering all the subruns, we restore the * 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)); + aprocessor.SetText(aText + start, subRunLength, UBiDiDirection(level & 1)); width = aprocessor.GetWidth(); xOffset += width; xEndRun = xOffset; } while (subRunCount > 0) { - // CalculateCharType can increment subRunCount if the run + // CalculateCharDirection can increment subRunCount if the run // contains mixed character types - CalculateCharType(aBidiEngine, aText, lineOffset, typeLimit, subRunLimit, subRunLength, subRunCount, charType, prevType); - + CalculateCharDirection(aBidiPara, aText, lineOffset, directionLimit, + subRunLimit, subRunLength, subRunCount, + charDirection, prevDirection); + 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); + charDirection, level & 1); - aprocessor.SetText(runVisualText.get(), subRunLength, nsBidiDirection(level & 1)); + aprocessor.SetText(runVisualText.get(), subRunLength, UBiDiDirection(level & 1)); width = aprocessor.GetWidth(); totalWidth += width; if (level & 1) { xOffset -= width; } if (aMode == MODE_DRAW) { aprocessor.DrawText(xOffset, width); } @@ -1962,49 +1972,49 @@ nsresult nsBidiPresUtils::ProcessText(co * ^^^^^^ (subWidth) * ^^^^^^^^ (aprocessor.GetWidth() -- with visualRightSide) * ^^ (posResolve->visualWidth) */ nscoord subWidth; // The position in the text where this run's "left part" begins. const char16_t* visualLeftPart, *visualRightSide; if (level & 1) { - // One day, son, this could all be replaced with mBidiEngine.GetVisualIndex ... + // One day, son, this could all be replaced with ubidi_getVisualIndex ... posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start)); // Skipping to the "left part". visualLeftPart = aText + posResolve->logicalIndex + 1; // Skipping to the right side of the current character visualRightSide = visualLeftPart - 1; } else { posResolve->visualIndex = visualStart + (posResolve->logicalIndex - start); // Skipping to the "left part". visualLeftPart = aText + start; // In LTR mode this is the same as visualLeftPart visualRightSide = visualLeftPart; } // 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, UBiDiDirection(level & 1)); subWidth = aprocessor.GetWidth(); - aprocessor.SetText(visualRightSide, visualLeftLength + 1, nsBidiDirection(level & 1)); + aprocessor.SetText(visualRightSide, visualLeftLength + 1, UBiDiDirection(level & 1)); posResolve->visualLeftTwips = xOffset + subWidth; posResolve->visualWidth = aprocessor.GetWidth() - subWidth; } } } if (!(level & 1)) { xOffset += width; } --subRunCount; start = lineOffset; - subRunLimit = typeLimit; - subRunLength = typeLimit - lineOffset; + subRunLimit = directionLimit; + subRunLength = directionLimit - lineOffset; } // while if (level & 1) { xOffset = xEndRun; } visualStart += length; } // for @@ -2023,19 +2033,19 @@ public: ~nsIRenderingContextBidiProcessor() { mCtx->SetTextRunRTL(false); } virtual void SetText(const char16_t* aText, int32_t aLength, - nsBidiDirection aDirection) + UBiDiDirection aDirection) { - mTextRunConstructionContext->SetTextRunRTL(aDirection==NSBIDI_RTL); + mTextRunConstructionContext->SetTextRunRTL(aDirection==UBIDI_RTL); mText = aText; mLength = aLength; } virtual nscoord GetWidth() { return mTextRunConstructionContext->GetWidth(mText, mLength); } @@ -2052,31 +2062,34 @@ private: nsRenderingContext* mTextRunConstructionContext; nsPoint mPt; const char16_t* mText; int32_t mLength; }; nsresult nsBidiPresUtils::ProcessTextForRenderingContext(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsRenderingContext& aTextRunConstructionContext, Mode aMode, nscoord aX, nscoord aY, nsBidiPositionResolve* aPosResolve, int32_t aPosResolveCount, nscoord* aWidth) { nsIRenderingContextBidiProcessor processor(&aRenderingContext, &aTextRunConstructionContext, nsPoint(aX, aY)); - nsBidi bidiEngine; - return ProcessText(aText, aLength, aBaseLevel, aPresContext, processor, - aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine); + UBiDi* bidiPara = ubidi_open(); + nsresult rv = ProcessText(aText, aLength, aBaseLevel, aPresContext, + processor, aMode, aPosResolve, aPosResolveCount, + aWidth, bidiPara); + ubidi_close(bidiPara); + return rv; } /* static */ void nsBidiPresUtils::WriteReverse(const char16_t* aSrc, uint32_t aSrcLength, char16_t* aDest) { char16_t* dest = aDest + aSrcLength; @@ -2095,50 +2108,47 @@ void nsBidiPresUtils::WriteReverse(const NS_ASSERTION(dest == aDest, "Whole string not copied"); } /* static */ bool nsBidiPresUtils::WriteLogicalToVisual(const char16_t* aSrc, uint32_t aSrcLength, char16_t* aDest, - nsBidiLevel aBaseDirection, - nsBidi* aBidiEngine) + UBiDiLevel aBaseDirection, + UBiDi* aBidiPara) { const char16_t* src = aSrc; - nsresult rv = aBidiEngine->SetPara(src, aSrcLength, aBaseDirection, nullptr); - if (NS_FAILED(rv)) { + UErrorCode errorCode = U_ZERO_ERROR; + ubidi_setPara(aBidiPara, (UChar*)src, aSrcLength, aBaseDirection, + nullptr, &errorCode); + if (U_FAILURE(errorCode)) { return false; } - nsBidiDirection dir; - rv = aBidiEngine->GetDirection(&dir); - // NSBIDI_LTR returned from GetDirection means the whole text is LTR - if (NS_FAILED(rv) || dir == NSBIDI_LTR) { + UBiDiDirection dir = ubidi_getDirection(aBidiPara); + // UBIDI_LTR returned from GetDirection means the whole text is LTR + if (dir == UBIDI_LTR) { return false; } - int32_t runCount; - rv = aBidiEngine->CountRuns(&runCount); - if (NS_FAILED(rv)) { + int32_t runCount = ubidi_countRuns(aBidiPara, &errorCode); + if (U_FAILURE(errorCode)) { return false; } int32_t runIndex, start, length; char16_t* dest = aDest; for (runIndex = 0; runIndex < runCount; ++runIndex) { - rv = aBidiEngine->GetVisualRun(runIndex, &start, &length, &dir); - if (NS_FAILED(rv)) { - return false; - } + dir = ubidi_getVisualRun(aBidiPara, runIndex, &start, &length); src = aSrc + start; - if (dir == NSBIDI_RTL) { + if (dir == UBIDI_RTL) { WriteReverse(src, length, dest); dest += length; } else { do { NS_ASSERTION(src >= aSrc && src < aSrc + aSrcLength, "logical index out of range"); NS_ASSERTION(dest < aDest + aSrcLength, "visual index out of range"); *(dest++) = *(src++); @@ -2148,65 +2158,66 @@ bool nsBidiPresUtils::WriteLogicalToVisu NS_ASSERTION(static_cast(dest - aDest) == aSrcLength, "whole string not copied"); return true; } void nsBidiPresUtils::CopyLogicalToVisual(const nsAString& aSource, nsAString& aDest, - nsBidiLevel aBaseDirection, + UBiDiLevel aBaseDirection, bool aOverride) { aDest.SetLength(0); uint32_t srcLength = aSource.Length(); if (srcLength == 0) return; if (!aDest.SetLength(srcLength, fallible_t())) { return; } nsAString::const_iterator fromBegin, fromEnd; nsAString::iterator toBegin; aSource.BeginReading(fromBegin); aSource.EndReading(fromEnd); aDest.BeginWriting(toBegin); if (aOverride) { - if (aBaseDirection == NSBIDI_RTL) { + if (aBaseDirection == UBIDI_RTL) { // no need to use the converter -- just copy the string in reverse order WriteReverse(fromBegin.get(), srcLength, toBegin.get()); } else { - // if aOverride && aBaseDirection == NSBIDI_LTR, fall through to the + // if aOverride && aBaseDirection == UBIDI_LTR, fall through to the // simple copy aDest.SetLength(0); } } else { - nsBidi bidiEngine; + UBiDi* bidiPara = ubidi_open(); if (!WriteLogicalToVisual(fromBegin.get(), srcLength, toBegin.get(), - aBaseDirection, &bidiEngine)) { + aBaseDirection, bidiPara)) { aDest.SetLength(0); } + ubidi_close(bidiPara); } if (aDest.IsEmpty()) { // Either there was an error or the source is unidirectional // left-to-right. In either case, just copy source to dest. CopyUnicodeTo(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd), aDest); } } /* static */ -nsBidiLevel +UBiDiLevel nsBidiPresUtils::BidiLevelFromStyle(nsStyleContext* aStyleContext) { if (aStyleContext->StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT) { - return NSBIDI_DEFAULT_LTR; + return UBIDI_DEFAULT_LTR; } if (aStyleContext->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { - return NSBIDI_RTL; + return UBIDI_RTL; } - return NSBIDI_LTR; + return UBIDI_LTR; } #endif // IBMBIDI diff --git a/layout/base/nsBidiPresUtils.h b/layout/base/nsBidiPresUtils.h --- a/layout/base/nsBidiPresUtils.h +++ b/layout/base/nsBidiPresUtils.h @@ -4,17 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsBidiPresUtils_h___ #define nsBidiPresUtils_h___ #ifdef IBMBIDI -#include "nsBidi.h" +#include "unicode/ubidi.h" #include "nsBidiUtils.h" #include "nsHashKeys.h" #include "nsCoord.h" #ifdef DrawText #undef DrawText #endif @@ -110,17 +110,17 @@ public: * * @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; + UBiDiDirection aDirection) = 0; /** * Returns the measured width of the text given in SetText. If SetText was * not called with valid parameters, the result of this call is undefined. * This call is guaranteed to only be called once between SetText calls. * Will be invoked before DrawText. */ virtual nscoord GetWidth() = 0; @@ -166,61 +166,61 @@ public: * of the platform. The formatting includes: reordering, Arabic shaping, * symmetric and numeric swapping, removing control characters. * * @lina 06/18/2000 */ static nsresult FormatUnicodeText(nsPresContext* aPresContext, char16_t* aText, int32_t& aTextLength, - nsCharType aCharType, + UCharDirection aCharDirection, bool aIsOddLevel); /** * Reorder plain text using the Unicode Bidi algorithm and send it to * a rendering context for rendering. * * @param[in] aText the string to be rendered (in logical order) * @param aLength the number of characters in the string * @param aBaseLevel the base embedding level of the string * odd values are right-to-left; even values are left-to-right, plus special - * constants as follows (defined in nsBidi.h) - * NSBIDI_LTR - left-to-right string - * NSBIDI_RTL - right-to-left string - * NSBIDI_DEFAULT_LTR - auto direction determined by first strong character, + * constants as follows (defined in ubidi.h) + * UBIDI_LTR - left-to-right string + * UBIDI_RTL - right-to-left string + * UBIDI_DEFAULT_LTR - auto direction determined by first strong character, * default is left-to-right - * NSBIDI_DEFAULT_RTL - auto direction determined by first strong character, + * UBIDI_DEFAULT_RTL - auto direction determined by first strong character, * default is right-to-left * * @param aPresContext the presentation context * @param aRenderingContext the rendering context to render to * @param aTextRunConstructionContext the rendering context to be used to construct the textrun (affects font hinting) * @param aX the x-coordinate to render the string * @param aY the y-coordinate to render the string * @param[in,out] aPosResolve array of logical positions to resolve into visual positions; can be nullptr if this functionality is not required * @param aPosResolveCount number of items in the aPosResolve array */ static nsresult RenderText(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsRenderingContext& aTextRunConstructionContext, nscoord aX, nscoord aY, nsBidiPositionResolve* aPosResolve = nullptr, int32_t aPosResolveCount = 0) { return ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext, aRenderingContext, aTextRunConstructionContext, MODE_DRAW, aX, aY, aPosResolve, aPosResolveCount, nullptr); } static nscoord MeasureTextWidth(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, nsRenderingContext& aRenderingContext) { nscoord length; nsresult rv = ProcessTextForRenderingContext(aText, aLength, aBaseLevel, aPresContext, aRenderingContext, aRenderingContext, MODE_MEASURE, 0, 0, nullptr, 0, &length); return NS_SUCCEEDED(rv) ? length : 0; @@ -261,105 +261,105 @@ public: nsIFrame* aFirstFrameOnLine, int32_t aNumFramesOnLine); static nsIFrame* GetFirstLeaf(nsIFrame* aFrame); /** * Get the bidi embedding level of the given (inline) frame. */ - static nsBidiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame); + static UBiDiLevel GetFrameEmbeddingLevel(nsIFrame* aFrame); /** * Get the paragraph depth of the given (inline) frame. */ static uint8_t GetParagraphDepth(nsIFrame* aFrame); /** * Get the bidi base level of the given (inline) frame. */ - static nsBidiLevel GetFrameBaseLevel(nsIFrame* aFrame); + static UBiDiLevel GetFrameBaseLevel(nsIFrame* aFrame); enum Mode { MODE_DRAW, MODE_MEASURE }; /** * Reorder plain text using the Unicode Bidi algorithm and send it to * a processor for rendering or measuring * * @param[in] aText the string to be processed (in logical order) * @param aLength the number of characters in the string * @param aBaseLevel the base embedding level of the string * odd values are right-to-left; even values are left-to-right, plus special - * constants as follows (defined in nsBidi.h) - * NSBIDI_LTR - left-to-right string - * NSBIDI_RTL - right-to-left string - * NSBIDI_DEFAULT_LTR - auto direction determined by first strong character, + * constants as follows (defined in ubidi.h) + * UBIDI_LTR - left-to-right string + * UBIDI_RTL - right-to-left string + * UBIDI_DEFAULT_LTR - auto direction determined by first strong character, * default is left-to-right - * NSBIDI_DEFAULT_RTL - auto direction determined by first strong character, + * UBIDI_DEFAULT_RTL - auto direction determined by first strong character, * default is right-to-left * * @param aPresContext the presentation context * @param aprocessor the bidi processor * @param aMode the operation to process * MODE_DRAW - invokes DrawText on the processor for each substring * MODE_MEASURE - does not invoke DrawText on the processor * Note that the string is always measured, regardless of mode * @param[in,out] aPosResolve array of logical positions to resolve into * visual positions; can be nullptr if this functionality is not required * @param aPosResolveCount number of items in the aPosResolve array * @param[out] aWidth Pointer to where the width will be stored (may be null) */ static nsresult ProcessText(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, BidiProcessor& aprocessor, Mode aMode, nsBidiPositionResolve* aPosResolve, int32_t aPosResolveCount, nscoord* aWidth, - nsBidi* aBidiEngine); + UBiDi* aBidiPara); /** * Make a copy of a string, converting from logical to visual order * * @param aSource the source string * @param aDest the destination string * @param aBaseDirection the base direction of the string - * (NSBIDI_LTR or NSBIDI_RTL to force the base direction; - * NSBIDI_DEFAULT_LTR or NSBIDI_DEFAULT_RTL to let the bidi engine + * (UBIDI_LTR or UBIDI_RTL to force the base direction; + * UBIDI_DEFAULT_LTR or UBIDI_DEFAULT_RTL to let the bidi engine * determine the direction from rules P2 and P3 of the bidi algorithm. * @see nsBidi::GetPara * @param aOverride if TRUE, the text has a bidi override, according to * the direction in aDir */ static void CopyLogicalToVisual(const nsAString& aSource, nsAString& aDest, - nsBidiLevel aBaseDirection, + UBiDiLevel aBaseDirection, bool aOverride); /** * Use style attributes to determine the base paragraph level to pass to the * bidi algorithm. * - * If |unicode-bidi| is set to "[-moz-]plaintext", returns NSBIDI_DEFAULT_LTR, + * If |unicode-bidi| is set to "[-moz-]plaintext", returns UBIDI_DEFAULT_LTR, * in other words the direction is determined from the first strong character * in the text according to rules P2 and P3 of the bidi algorithm, or LTR if * there is no strong character. * - * Otherwise returns NSBIDI_LTR or NSBIDI_RTL depending on the value of + * Otherwise returns UBIDI_LTR or UBIDI_RTL depending on the value of * |direction| */ - static nsBidiLevel BidiLevelFromStyle(nsStyleContext* aStyleContext); + static UBiDiLevel BidiLevelFromStyle(nsStyleContext* aStyleContext); private: static nsresult ProcessTextForRenderingContext(const char16_t* aText, int32_t aLength, - nsBidiLevel aBaseLevel, + UBiDiLevel aBaseLevel, nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsRenderingContext& aTextRunConstructionContext, Mode aMode, nscoord aX, // DRAW only nscoord aY, // DRAW only nsBidiPositionResolve* aPosResolve, /* may be null */ int32_t aPosResolveCount, @@ -475,34 +475,34 @@ private: * @see Resolve() * @see EnsureBidiContinuation() */ static void RemoveBidiContinuation(BidiParagraphData* aBpd, nsIFrame* aFrame, int32_t aFirstIndex, int32_t aLastIndex, int32_t& aOffset); - static void CalculateCharType(nsBidi* aBidiEngine, - const char16_t* aText, - int32_t& aOffset, - int32_t aCharTypeLimit, - int32_t& aRunLimit, - int32_t& aRunLength, - int32_t& aRunCount, - uint8_t& aCharType, - uint8_t& aPrevCharType); + static void CalculateCharDirection(UBiDi* aBidiPara, + const char16_t* aText, + int32_t& aOffset, + int32_t aCharDirectionLimit, + int32_t& aRunLimit, + int32_t& aRunLength, + int32_t& aRunCount, + UCharDirection& aCharDirection, + UCharDirection& aPrevCharDirection); static void StripBidiControlCharacters(char16_t* aText, int32_t& aTextLength); static bool WriteLogicalToVisual(const char16_t* aSrc, uint32_t aSrcLength, char16_t* aDest, - nsBidiLevel aBaseDirection, - nsBidi* aBidiEngine); + UBiDiLevel aBaseDirection, + UBiDi* aBidiPara); static void WriteReverse(const char16_t* aSrc, uint32_t aSrcLength, char16_t* aDest); }; #endif // IBMBIDI diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3730,17 +3730,17 @@ nsLayoutUtils::DrawString(const nsIFrame int32_t aLength, nsPoint aPoint, nsStyleContext* aStyleContext) { #ifdef IBMBIDI nsresult rv = NS_ERROR_FAILURE; nsPresContext* presContext = aFrame->PresContext(); if (presContext->BidiEnabled()) { - nsBidiLevel level = + UBiDiLevel level = nsBidiPresUtils::BidiLevelFromStyle(aStyleContext ? aStyleContext : aFrame->StyleContext()); rv = nsBidiPresUtils::RenderText(aString, aLength, level, presContext, *aContext, *aContext, aPoint.x, aPoint.y); } if (NS_FAILED(rv)) #endif // IBMBIDI @@ -3754,17 +3754,17 @@ nscoord nsLayoutUtils::GetStringWidth(const nsIFrame* aFrame, nsRenderingContext* aContext, const char16_t* aString, int32_t aLength) { #ifdef IBMBIDI nsPresContext* presContext = aFrame->PresContext(); if (presContext->BidiEnabled()) { - nsBidiLevel level = + UBiDiLevel level = nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext()); return nsBidiPresUtils::MeasureTextWidth(aString, aLength, level, presContext, *aContext); } #endif // IBMBIDI aContext->SetTextRunRTL(false); return aContext->GetWidth(aString, aLength); } diff --git a/layout/generic/Makefile.in b/layout/generic/Makefile.in --- a/layout/generic/Makefile.in +++ b/layout/generic/Makefile.in @@ -15,10 +15,15 @@ CXXFLAGS += \ ifdef MOZ_WIDGET_GTK CXXFLAGS += $(TK_CFLAGS) endif ifdef MOZ_ENABLE_QT CXXFLAGS += $(MOZ_QT_CFLAGS) endif +LOCAL_INCLUDES += \ + -I$(topsrcdir)/intl/icu/source/common \ + -I$(topsrcdir)/intl/icu/source/i18n \ + $(NULL) + libs:: $(INSTALL) $(RESOURCES_HTML) $(DIST)/bin/res/html diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -6317,17 +6317,17 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* #ifdef IBMBIDI if (aPos->mVisual && PresContext()->BidiEnabled()) { bool lineIsRTL = it->GetDirection(); bool isReordered; nsIFrame *lastFrame; result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame); baseFrame = endOfLine ? lastFrame : firstFrame; if (baseFrame) { - nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(baseFrame); + UBiDiLevel 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) endOfLine = !endOfLine; } } else #endif { @@ -6544,17 +6544,17 @@ nsIFrame::GetFrameFromDirection(nsDirect nsIFrame *lastFrame; #ifdef IBMBIDI if (aVisual && presContext->BidiEnabled()) { bool lineIsRTL = it->GetDirection(); bool isReordered; result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame); nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame; if (*framePtr) { - nsBidiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr); + UBiDiLevel embeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(*framePtr); if ((((embeddingLevel & 1) && lineIsRTL) || (!(embeddingLevel & 1) && !lineIsRTL)) == (aDirection == eDirPrevious)) { nsFrame::GetFirstLeaf(presContext, framePtr); } else { nsFrame::GetLastLeaf(presContext, framePtr); } atLineEdge = *framePtr == traversedFrame; } else { diff --git a/layout/generic/nsFrameList.cpp b/layout/generic/nsFrameList.cpp --- a/layout/generic/nsFrameList.cpp +++ b/layout/generic/nsFrameList.cpp @@ -350,31 +350,31 @@ nsFrameList::GetPrevVisualFor(nsIFrame* { if (!mFirstChild) return nullptr; nsIFrame* parent = mFirstChild->GetParent(); if (!parent) return aFrame ? aFrame->GetPrevSibling() : LastChild(); - nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild); + UBiDiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild); nsAutoLineIterator iter = parent->GetLineIterator(); if (!iter) { // Parent is not a block Frame if (parent->GetType() == nsGkAtoms::lineFrame) { // Line frames are not bidi-splittable, so need to consider bidi reordering - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1); } else { // RTL return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1); } } else { // Just get the next or prev sibling, depending on block and frame direction. - nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild); + UBiDiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild); if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) { return aFrame ? aFrame->GetPrevSibling() : LastChild(); } else { return aFrame ? aFrame->GetNextSibling() : mFirstChild; } } } @@ -394,28 +394,28 @@ nsFrameList::GetPrevVisualFor(nsIFrame* nsIFrame* firstFrameOnLine; int32_t numFramesOnLine; nsRect lineBounds; uint32_t lineFlags; if (aFrame) { iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags); - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine); } else { // RTL frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine); } } if (!frame && thisLine > 0) { // Get the last frame of the previous line iter->GetLine(thisLine - 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags); - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine); } else { // RTL frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine); } } return frame; } @@ -424,31 +424,31 @@ nsFrameList::GetNextVisualFor(nsIFrame* { if (!mFirstChild) return nullptr; nsIFrame* parent = mFirstChild->GetParent(); if (!parent) return aFrame ? aFrame->GetPrevSibling() : mFirstChild; - nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild); + UBiDiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(mFirstChild); nsAutoLineIterator iter = parent->GetLineIterator(); if (!iter) { // Parent is not a block Frame if (parent->GetType() == nsGkAtoms::lineFrame) { // Line frames are not bidi-splittable, so need to consider bidi reordering - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { return nsBidiPresUtils::GetFrameToRightOf(aFrame, mFirstChild, -1); } else { // RTL return nsBidiPresUtils::GetFrameToLeftOf(aFrame, mFirstChild, -1); } } else { // Just get the next or prev sibling, depending on block and frame direction. - nsBidiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild); + UBiDiLevel frameEmbeddingLevel = nsBidiPresUtils::GetFrameEmbeddingLevel(mFirstChild); if ((frameEmbeddingLevel & 1) == (baseLevel & 1)) { return aFrame ? aFrame->GetNextSibling() : mFirstChild; } else { return aFrame ? aFrame->GetPrevSibling() : LastChild(); } } } @@ -468,29 +468,29 @@ nsFrameList::GetNextVisualFor(nsIFrame* nsIFrame* firstFrameOnLine; int32_t numFramesOnLine; nsRect lineBounds; uint32_t lineFlags; if (aFrame) { iter->GetLine(thisLine, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags); - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { frame = nsBidiPresUtils::GetFrameToRightOf(aFrame, firstFrameOnLine, numFramesOnLine); } else { // RTL frame = nsBidiPresUtils::GetFrameToLeftOf(aFrame, firstFrameOnLine, numFramesOnLine); } } int32_t numLines = iter->GetNumLines(); if (!frame && thisLine < numLines - 1) { // Get the first frame of the next line iter->GetLine(thisLine + 1, &firstFrameOnLine, &numFramesOnLine, lineBounds, &lineFlags); - if (baseLevel == NSBIDI_LTR) { + if (baseLevel == UBIDI_LTR) { frame = nsBidiPresUtils::GetFrameToRightOf(nullptr, firstFrameOnLine, numFramesOnLine); } else { // RTL frame = nsBidiPresUtils::GetFrameToLeftOf(nullptr, firstFrameOnLine, numFramesOnLine); } } return frame; } #endif diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1025,22 +1025,22 @@ nsImageFrame::DisplayAltText(nsPresConte aRenderingContext); // Display the text nsresult rv = NS_ERROR_FAILURE; if (aPresContext->BidiEnabled()) { const nsStyleVisibility* vis = StyleVisibility(); if (vis->mDirection == NS_STYLE_DIRECTION_RTL) - rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_RTL, + rv = nsBidiPresUtils::RenderText(str, maxFit, UBIDI_RTL, aPresContext, aRenderingContext, aRenderingContext, aRect.XMost() - strWidth, y + maxAscent); else - rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_LTR, + rv = nsBidiPresUtils::RenderText(str, maxFit, UBIDI_LTR, aPresContext, aRenderingContext, aRenderingContext, aRect.x, y + maxAscent); } if (NS_FAILED(rv)) aRenderingContext.DrawString(str, maxFit, aRect.x, y + maxAscent); // Move to the next line diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -825,17 +825,17 @@ nsFrameSelection::MoveCaret(uint32_t if (NS_FAILED(result) || !frame) return NS_FAILED(result) ? result : NS_ERROR_FAILURE; //set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking //when we hit scrollable views. If no limiter then just let it go ahead nsPeekOffsetStruct pos(aAmount, eDirPrevious, offsetused, desiredX, true, mLimiter != nullptr, true, aVisualMovement); - nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(frame); + UBiDiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(frame); HINT tHint(mHint); //temporary variable so we dont set mHint until it is necessary switch (aKeycode){ case nsIDOMKeyEvent::DOM_VK_RIGHT : InvalidateDesiredX(); pos.mDirection = (baseLevel & 1) ? eDirPrevious : eDirNext; break; case nsIDOMKeyEvent::DOM_VK_LEFT : @@ -5365,17 +5365,17 @@ Selection::Modify(const nsAString& aAlte } // If the base level of the focused frame is odd, we may have to swap the // direction of the keycode. nsIFrame *frame; int32_t offset; rv = GetPrimaryFrameForFocusNode(&frame, &offset, visual); if (NS_SUCCEEDED(rv) && frame) { - nsBidiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(frame); + UBiDiLevel baseLevel = nsBidiPresUtils::GetFrameBaseLevel(frame); if (baseLevel & 1) { if (!visual && keycode == nsIDOMKeyEvent::DOM_VK_RIGHT) { keycode = nsIDOMKeyEvent::DOM_VK_LEFT; } else if (!visual && keycode == nsIDOMKeyEvent::DOM_VK_LEFT) { keycode = nsIDOMKeyEvent::DOM_VK_RIGHT; } diff --git a/layout/xul/Makefile.in b/layout/xul/Makefile.in new file mode 100644 --- /dev/null +++ b/layout/xul/Makefile.in @@ -0,0 +1,10 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +LOCAL_INCLUDES += \ + -I$(topsrcdir)/intl/icu/source/common \ + -I$(topsrcdir)/intl/icu/source/i18n \ + $(NULL) diff --git a/layout/xul/nsTextBoxFrame.cpp b/layout/xul/nsTextBoxFrame.cpp --- a/layout/xul/nsTextBoxFrame.cpp +++ b/layout/xul/nsTextBoxFrame.cpp @@ -503,18 +503,18 @@ nsTextBoxFrame::DrawText(nsRenderingCont CalculateUnderline(*refContext); aRenderingContext.SetColor(aOverrideColor ? *aOverrideColor : StyleColor()->mColor); #ifdef IBMBIDI nsresult rv = NS_ERROR_FAILURE; - nsBidiLevel level = nsBidiPresUtils::BidiLevelFromStyle(StyleContext()); - if (level != NSBIDI_LTR || mState & NS_FRAME_IS_BIDI) { + UBiDiLevel level = nsBidiPresUtils::BidiLevelFromStyle(StyleContext()); + if (level != UBIDI_LTR || mState & NS_FRAME_IS_BIDI) { presContext->SetBidiEnabled(); if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { // We let the RenderText function calculate the mnemonic's // underline position for us. nsBidiPositionResolve posResolve; posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex; rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level, presContext, aRenderingContext,