LCOV - code coverage report
Current view: directory - layout/base - nsBidiPresUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 901 0 0.0 %
Date: 2012-06-02 Functions: 70 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Communicator client code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Uri Bernstein <uriber@gmail.com>
      24                 :  *   Haamed Gheibi <gheibi@metanetworking.com>
      25                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #ifdef IBMBIDI
      42                 : 
      43                 : #include "nsBidiPresUtils.h"
      44                 : #include "nsTextFragment.h"
      45                 : #include "nsGkAtoms.h"
      46                 : #include "nsPresContext.h"
      47                 : #include "nsRenderingContext.h"
      48                 : #include "nsIServiceManager.h"
      49                 : #include "nsFrameManager.h"
      50                 : #include "nsBidiUtils.h"
      51                 : #include "nsCSSFrameConstructor.h"
      52                 : #include "nsContainerFrame.h"
      53                 : #include "nsInlineFrame.h"
      54                 : #include "nsPlaceholderFrame.h"
      55                 : #include "nsFirstLetterFrame.h"
      56                 : #include "nsUnicodeProperties.h"
      57                 : #include "nsTextFrame.h"
      58                 : 
      59                 : #undef NOISY_BIDI
      60                 : #undef REALLY_NOISY_BIDI
      61                 : 
      62                 : using namespace mozilla;
      63                 : 
      64                 : static const PRUnichar kSpace            = 0x0020;
      65                 : static const PRUnichar kZWSP             = 0x200B;
      66                 : static const PRUnichar kLineSeparator    = 0x2028;
      67                 : static const PRUnichar kObjectSubstitute = 0xFFFC;
      68                 : static const PRUnichar kLRE              = 0x202A;
      69                 : static const PRUnichar kRLE              = 0x202B;
      70                 : static const PRUnichar kLRO              = 0x202D;
      71                 : static const PRUnichar kRLO              = 0x202E;
      72                 : static const PRUnichar kPDF              = 0x202C;
      73                 : 
      74                 : #define NS_BIDI_CONTROL_FRAME ((nsIFrame*)0xfffb1d1)
      75                 : 
      76               0 : struct BidiParagraphData {
      77                 :   nsString            mBuffer;
      78                 :   nsAutoTArray<PRUnichar, 16> mEmbeddingStack;
      79                 :   nsTArray<nsIFrame*> mLogicalFrames;
      80                 :   nsTArray<nsLineBox*> mLinePerFrame;
      81                 :   nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
      82                 :   bool                mIsVisual;
      83                 :   bool                mReset;
      84                 :   nsBidiLevel         mParaLevel;
      85                 :   nsIContent*         mPrevContent;
      86                 :   nsAutoPtr<nsBidi>   mBidiEngine;
      87                 :   nsIFrame*           mPrevFrame;
      88                 :   nsAutoPtr<BidiParagraphData> mSubParagraph;
      89                 : 
      90               0 :   void Init(nsBlockFrame *aBlockFrame)
      91                 :   {
      92               0 :     mContentToFrameIndex.Init();
      93               0 :     mBidiEngine = new nsBidi();
      94               0 :     mPrevContent = nsnull;
      95                 : 
      96                 :     bool styleDirectionIsRTL =
      97               0 :       (NS_STYLE_DIRECTION_RTL == aBlockFrame->GetStyleVisibility()->mDirection);
      98               0 :     if (aBlockFrame->GetStyleTextReset()->mUnicodeBidi &
      99                 :         NS_STYLE_UNICODE_BIDI_PLAINTEXT) {
     100                 :       // unicode-bidi: plaintext: the Bidi algorithm will determine the
     101                 :       // directionality of the paragraph according to the first strong
     102                 :       // directional character, defaulting to LTR if there is none.
     103               0 :       mParaLevel = NSBIDI_DEFAULT_LTR;
     104                 :     } else {
     105               0 :       mParaLevel = styleDirectionIsRTL ? NSBIDI_RTL : NSBIDI_LTR;
     106                 :     }
     107                 : 
     108               0 :     mIsVisual = aBlockFrame->PresContext()->IsVisualMode();
     109               0 :     if (mIsVisual) {
     110                 :       /**
     111                 :        * Drill up in content to detect whether this is an element that needs to
     112                 :        * be rendered with logical order even on visual pages.
     113                 :        *
     114                 :        * We always use logical order on form controls, firstly so that text
     115                 :        * entry will be in logical order, but also because visual pages were
     116                 :        * written with the assumption that even if the browser had no support
     117                 :        * for right-to-left text rendering, it would use native widgets with
     118                 :        * bidi support to display form controls.
     119                 :        *
     120                 :        * We also use logical order in XUL elements, since we expect that if a
     121                 :        * XUL element appears in a visual page, it will be generated by an XBL
     122                 :        * binding and contain localized text which will be in logical order.
     123                 :        */
     124               0 :       for (nsIContent* content = aBlockFrame->GetContent() ; content; 
     125               0 :            content = content->GetParent()) {
     126               0 :         if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
     127               0 :             content->IsXUL()) {
     128               0 :           mIsVisual = false;
     129               0 :           break;
     130                 :         }
     131                 :       }
     132                 :     }
     133               0 :   }
     134                 : 
     135               0 :   BidiParagraphData* GetSubParagraph()
     136                 :   {
     137               0 :     if (!mSubParagraph) {
     138               0 :       mSubParagraph = new BidiParagraphData();
     139               0 :       mSubParagraph->Init(this);
     140                 :     }
     141                 : 
     142               0 :     return mSubParagraph;
     143                 :   }
     144                 : 
     145                 :   // Initialise a sub-paragraph from its containing paragraph
     146               0 :   void Init(BidiParagraphData *aBpd)
     147                 :   {
     148               0 :     mContentToFrameIndex.Init();
     149               0 :     mBidiEngine = new nsBidi();
     150               0 :     mPrevContent = nsnull;
     151               0 :     mIsVisual = aBpd->mIsVisual;
     152               0 :     mParaLevel = aBpd->mParaLevel;
     153                 : 
     154                 :     // If the containing paragraph has a level of NSBIDI_DEFAULT_LTR, set
     155                 :     // the sub-paragraph to NSBIDI_LTR (we can't use GetParaLevel to find the
     156                 :     // resolved paragraph level, because the containing paragraph hasn't yet
     157                 :     // been through bidi resolution
     158               0 :     if (mParaLevel == NSBIDI_DEFAULT_LTR) {
     159               0 :       mParaLevel = NSBIDI_LTR;
     160                 :     }
     161               0 :     mReset = false;
     162               0 :   }
     163                 : 
     164               0 :   void Reset(nsIFrame* aFrame, BidiParagraphData *aBpd)
     165                 :   {
     166               0 :     mReset = true;
     167               0 :     mLogicalFrames.Clear();
     168               0 :     mLinePerFrame.Clear();
     169               0 :     mContentToFrameIndex.Clear();
     170               0 :     mBuffer.SetLength(0);
     171               0 :     mPrevFrame = aBpd->mPrevFrame;
     172                 :     // We need to copy in embeddings (but not overrides!) from the containing
     173                 :     // paragraph so that the line(s) including this sub-paragraph will be
     174                 :     // correctly reordered.
     175               0 :     for (PRUint32 i = 0; i < aBpd->mEmbeddingStack.Length(); ++i) {
     176               0 :       switch(aBpd->mEmbeddingStack[i]) {
     177                 :         case kRLE:
     178                 :         case kRLO:
     179               0 :           mParaLevel = NextOddLevel(mParaLevel);
     180               0 :           break;
     181                 : 
     182                 :         case kLRE:
     183                 :         case kLRO:
     184               0 :           mParaLevel = NextEvenLevel(mParaLevel);
     185               0 :           break;
     186                 : 
     187                 :         default:
     188               0 :           break;
     189                 :       }
     190                 :     }
     191                 : 
     192               0 :     nsIFrame* container = aFrame->GetParent();
     193                 :     bool isRTL = (NS_STYLE_DIRECTION_RTL ==
     194               0 :                   container->GetStyleVisibility()->mDirection);
     195               0 :     if ((isRTL & 1) != (mParaLevel & 1)) {
     196               0 :       mParaLevel = isRTL ? NextOddLevel(mParaLevel) : NextEvenLevel(mParaLevel);
     197                 :     }
     198                 : 
     199               0 :     if (container->GetStyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) {
     200               0 :       PushBidiControl(isRTL ? kRLO : kLRO);
     201                 :     } else {
     202               0 :       PushBidiControl(isRTL ? kRLE : kLRE);
     203                 :     }
     204               0 :   }
     205                 : 
     206               0 :   nsresult SetPara()
     207                 :   {
     208                 :     return mBidiEngine->SetPara(mBuffer.get(), BufferLength(),
     209               0 :                                 mParaLevel, nsnull);
     210                 :   }
     211                 : 
     212                 :   /**
     213                 :    * mParaLevel can be NSBIDI_DEFAULT_LTR as well as NSBIDI_LTR or NSBIDI_RTL.
     214                 :    * GetParaLevel() returns the actual (resolved) paragraph level which is
     215                 :    * always either NSBIDI_LTR or NSBIDI_RTL
     216                 :    */
     217               0 :   nsBidiLevel GetParaLevel()
     218                 :   {
     219               0 :     nsBidiLevel paraLevel = mParaLevel;
     220               0 :     if (IS_DEFAULT_LEVEL(paraLevel)) {
     221               0 :       mBidiEngine->GetParaLevel(&paraLevel);
     222                 :     }
     223               0 :     return paraLevel;
     224                 :   }
     225                 : 
     226               0 :   nsresult CountRuns(PRInt32 *runCount){ return mBidiEngine->CountRuns(runCount); }
     227                 : 
     228               0 :   nsresult GetLogicalRun(PRInt32 aLogicalStart, 
     229                 :                          PRInt32* aLogicalLimit,
     230                 :                          nsBidiLevel* aLevel)
     231                 :   {
     232                 :     nsresult rv = mBidiEngine->GetLogicalRun(aLogicalStart,
     233               0 :                                              aLogicalLimit, aLevel);
     234               0 :     if (mIsVisual || NS_FAILED(rv))
     235               0 :       *aLevel = GetParaLevel();
     236               0 :     return rv;
     237                 :   }
     238                 : 
     239               0 :   void ResetData()
     240                 :   {
     241               0 :     mLogicalFrames.Clear();
     242               0 :     mLinePerFrame.Clear();
     243               0 :     mContentToFrameIndex.Clear();
     244               0 :     mBuffer.SetLength(0);
     245               0 :     mPrevContent = nsnull;
     246               0 :     for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
     247               0 :       mBuffer.Append(mEmbeddingStack[i]);
     248               0 :       mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
     249               0 :       mLinePerFrame.AppendElement((nsLineBox*)nsnull);
     250                 :     }
     251               0 :   }
     252                 : 
     253               0 :   void AppendFrame(nsIFrame* aFrame,
     254                 :                    nsBlockInFlowLineIterator* aLineIter,
     255                 :                    nsIContent* aContent = nsnull)
     256                 :   {
     257               0 :     if (aContent) {
     258               0 :       mContentToFrameIndex.Put(aContent, FrameCount());
     259                 :     }
     260               0 :     mLogicalFrames.AppendElement(aFrame);
     261                 : 
     262               0 :     AdvanceLineIteratorToFrame(aFrame, aLineIter, mPrevFrame);
     263               0 :     mLinePerFrame.AppendElement(aLineIter->GetLine().get());
     264               0 :   }
     265                 : 
     266               0 :   void AdvanceAndAppendFrame(nsIFrame** aFrame,
     267                 :                              nsBlockInFlowLineIterator* aLineIter,
     268                 :                              nsIFrame** aNextSibling)
     269                 :   {
     270               0 :     nsIFrame* frame = *aFrame;
     271               0 :     nsIFrame* nextSibling = *aNextSibling;
     272                 : 
     273               0 :     frame = frame->GetNextContinuation();
     274               0 :     if (frame) {
     275               0 :       AppendFrame(frame, aLineIter, nsnull);
     276                 : 
     277                 :       /*
     278                 :        * If we have already overshot the saved next-sibling while
     279                 :        * scanning the frame's continuations, advance it.
     280                 :        */
     281               0 :       if (frame == nextSibling) {
     282               0 :         nextSibling = frame->GetNextSibling();
     283                 :       }
     284                 :     }
     285                 : 
     286               0 :     *aFrame = frame;
     287               0 :     *aNextSibling = nextSibling;
     288               0 :   }
     289                 : 
     290               0 :   PRInt32 GetLastFrameForContent(nsIContent *aContent)
     291                 :   {
     292               0 :     PRInt32 index = 0;
     293               0 :     mContentToFrameIndex.Get(aContent, &index);
     294               0 :     return index;
     295                 :   }
     296                 : 
     297               0 :   PRInt32 FrameCount(){ return mLogicalFrames.Length(); }
     298                 : 
     299               0 :   PRInt32 BufferLength(){ return mBuffer.Length(); }
     300                 : 
     301               0 :   nsIFrame* FrameAt(PRInt32 aIndex){ return mLogicalFrames[aIndex]; }
     302                 : 
     303               0 :   nsLineBox* GetLineForFrameAt(PRInt32 aIndex){ return mLinePerFrame[aIndex]; }
     304                 : 
     305               0 :   void AppendUnichar(PRUnichar aCh){ mBuffer.Append(aCh); }
     306                 : 
     307               0 :   void AppendString(const nsDependentSubstring& aString){ mBuffer.Append(aString); }
     308                 : 
     309               0 :   void AppendControlChar(PRUnichar aCh)
     310                 :   {
     311               0 :     mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
     312               0 :     mLinePerFrame.AppendElement((nsLineBox*)nsnull);
     313               0 :     AppendUnichar(aCh);
     314               0 :   }
     315                 : 
     316               0 :   void PushBidiControl(PRUnichar aCh)
     317                 :   {
     318               0 :     AppendControlChar(aCh);
     319               0 :     mEmbeddingStack.AppendElement(aCh);
     320               0 :   }
     321                 : 
     322               0 :   void PopBidiControl()
     323                 :   {
     324               0 :     AppendControlChar(kPDF);
     325               0 :     NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
     326               0 :     mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
     327               0 :   }
     328                 : 
     329               0 :   void ClearBidiControls()
     330                 :   {
     331               0 :     for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
     332               0 :       AppendControlChar(kPDF);
     333                 :     }
     334               0 :   }
     335                 : 
     336               0 :   nsBidiLevel NextOddLevel(nsBidiLevel aLevel)
     337                 :   {
     338               0 :     return (aLevel + 1) | 1;
     339                 :   }
     340                 : 
     341               0 :   nsBidiLevel NextEvenLevel(nsBidiLevel aLevel)
     342                 :   {
     343               0 :     return (aLevel + 2) & ~1;
     344                 :   }
     345                 : 
     346                 :   static bool
     347               0 :   IsFrameInCurrentLine(nsBlockInFlowLineIterator* aLineIter,
     348                 :                        nsIFrame* aPrevFrame, nsIFrame* aFrame)
     349                 :   {
     350               0 :     nsIFrame* endFrame = aLineIter->IsLastLineInList() ? nsnull :
     351               0 :       aLineIter->GetLine().next()->mFirstChild;
     352               0 :     nsIFrame* startFrame = aPrevFrame ? aPrevFrame : aLineIter->GetLine()->mFirstChild;
     353               0 :     for (nsIFrame* frame = startFrame; frame && frame != endFrame;
     354                 :          frame = frame->GetNextSibling()) {
     355               0 :       if (frame == aFrame)
     356               0 :         return true;
     357                 :     }
     358               0 :     return false;
     359                 :   }
     360                 : 
     361                 :   static void
     362               0 :   AdvanceLineIteratorToFrame(nsIFrame* aFrame,
     363                 :                              nsBlockInFlowLineIterator* aLineIter,
     364                 :                              nsIFrame*& aPrevFrame)
     365                 :   {
     366                 :     // Advance aLine to the line containing aFrame
     367               0 :     nsIFrame* child = aFrame;
     368               0 :     nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
     369               0 :     nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
     370               0 :     while (parent && !nsLayoutUtils::GetAsBlock(parent)) {
     371               0 :       child = parent;
     372               0 :       parent = nsLayoutUtils::GetParentOrPlaceholderFor(frameManager, child);
     373                 :     }
     374               0 :     NS_ASSERTION (parent, "aFrame is not a descendent of aBlockFrame");
     375               0 :     while (!IsFrameInCurrentLine(aLineIter, aPrevFrame, child)) {
     376                 : #ifdef DEBUG
     377                 :       bool hasNext =
     378                 : #endif
     379               0 :         aLineIter->Next();
     380               0 :       NS_ASSERTION(hasNext, "Can't find frame in lines!");
     381               0 :       aPrevFrame = nsnull;
     382                 :     }
     383               0 :     aPrevFrame = child;
     384               0 :   }
     385                 : 
     386                 : };
     387                 : 
     388               0 : struct BidiLineData {
     389                 :   nsTArray<nsIFrame*> mLogicalFrames;
     390                 :   nsTArray<nsIFrame*> mVisualFrames;
     391                 :   nsTArray<PRInt32> mIndexMap;
     392                 :   nsAutoTArray<PRUint8, 18> mLevels;
     393                 :   bool mIsReordered;
     394                 : 
     395               0 :   BidiLineData(nsIFrame* aFirstFrameOnLine, PRInt32   aNumFramesOnLine)
     396               0 :   {
     397                 :     /**
     398                 :      * Initialize the logically-ordered array of frames using the top-level
     399                 :      * frames of a single line
     400                 :      */
     401               0 :     mLogicalFrames.Clear();
     402                 : 
     403               0 :     bool isReordered = false;
     404               0 :     bool hasRTLFrames = false;
     405                 : 
     406               0 :     for (nsIFrame* frame = aFirstFrameOnLine;
     407                 :          frame && aNumFramesOnLine--;
     408                 :          frame = frame->GetNextSibling()) {
     409               0 :       AppendFrame(frame);
     410               0 :       PRUint8 level = nsBidiPresUtils::GetFrameEmbeddingLevel(frame);
     411               0 :       mLevels.AppendElement(level);
     412               0 :       mIndexMap.AppendElement(0);
     413               0 :       if (level & 1) {
     414               0 :         hasRTLFrames = true;
     415                 :       }
     416                 :     }
     417                 : 
     418                 :     // Reorder the line
     419               0 :     nsBidi::ReorderVisual(mLevels.Elements(), FrameCount(),
     420               0 :                           mIndexMap.Elements());
     421                 : 
     422               0 :     for (PRInt32 i = 0; i < FrameCount(); i++) {
     423               0 :       mVisualFrames.AppendElement(LogicalFrameAt(mIndexMap[i]));
     424               0 :       if (i != mIndexMap[i]) {
     425               0 :         isReordered = true;
     426                 :       }
     427                 :     }
     428                 : 
     429                 :     // If there's an RTL frame, assume the line is reordered
     430               0 :     mIsReordered = isReordered || hasRTLFrames;
     431               0 :   }
     432                 : 
     433               0 :   void AppendFrame(nsIFrame* aFrame)
     434                 :   {
     435               0 :     mLogicalFrames.AppendElement(aFrame); 
     436               0 :   }
     437                 : 
     438               0 :   PRInt32 FrameCount(){ return mLogicalFrames.Length(); }
     439                 : 
     440               0 :   nsIFrame* LogicalFrameAt(PRInt32 aIndex){ return mLogicalFrames[aIndex]; }
     441                 : 
     442               0 :   nsIFrame* VisualFrameAt(PRInt32 aIndex){ return mVisualFrames[aIndex]; }
     443                 : };
     444                 : 
     445                 : /* Some helper methods for Resolve() */
     446                 : 
     447                 : // Should this frame be split between text runs?
     448                 : bool
     449               0 : IsBidiSplittable(nsIFrame* aFrame) {
     450               0 :   nsIAtom* frameType = aFrame->GetType();
     451                 :   // Bidi inline containers should be split, unless they're line frames.
     452               0 :   return aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer)
     453               0 :     && frameType != nsGkAtoms::lineFrame;
     454                 : }
     455                 : 
     456                 : static nsresult
     457               0 : SplitInlineAncestors(nsIFrame*     aFrame)
     458                 : {
     459               0 :   nsPresContext *presContext = aFrame->PresContext();
     460               0 :   nsIPresShell *presShell = presContext->PresShell();
     461               0 :   nsIFrame* frame = aFrame;
     462               0 :   nsIFrame* parent = aFrame->GetParent();
     463                 :   nsIFrame* newParent;
     464                 : 
     465               0 :   while (IsBidiSplittable(parent)) {
     466               0 :     nsIFrame* grandparent = parent->GetParent();
     467               0 :     NS_ASSERTION(grandparent, "Couldn't get parent's parent in nsBidiPresUtils::SplitInlineAncestors");
     468                 :     
     469                 :     nsresult rv = presShell->FrameConstructor()->
     470               0 :       CreateContinuingFrame(presContext, parent, grandparent, &newParent, false);
     471               0 :     if (NS_FAILED(rv)) {
     472               0 :       return rv;
     473                 :     }
     474                 :     
     475                 :     // Split the child list after |frame|.
     476               0 :     nsContainerFrame* container = do_QueryFrame(parent);
     477               0 :     nsFrameList tail = container->StealFramesAfter(frame);
     478                 : 
     479                 :     // Reparent views as necessary
     480               0 :     rv = nsContainerFrame::ReparentFrameViewList(presContext, tail, parent, newParent);
     481               0 :     if (NS_FAILED(rv)) {
     482               0 :       return rv;
     483                 :     }
     484                 :     
     485                 :     // The parent's continuation adopts the siblings after the split.
     486               0 :     rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nsnull, tail);
     487               0 :     if (NS_FAILED(rv)) {
     488               0 :       return rv;
     489                 :     }
     490                 :     // The list name kNoReflowPrincipalList would indicate we don't want reflow
     491               0 :     nsFrameList temp(newParent, newParent);
     492               0 :     rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
     493               0 :     if (NS_FAILED(rv)) {
     494               0 :       return rv;
     495                 :     }
     496                 :     
     497               0 :     frame = parent;
     498               0 :     parent = grandparent;
     499                 :   }
     500                 :   
     501               0 :   return NS_OK;
     502                 : }
     503                 : 
     504                 : static void
     505               0 : MakeContinuationFluid(nsIFrame* aFrame, nsIFrame* aNext)
     506                 : {
     507               0 :   NS_ASSERTION (!aFrame->GetNextInFlow() || aFrame->GetNextInFlow() == aNext, 
     508                 :                 "next-in-flow is not next continuation!");
     509               0 :   aFrame->SetNextInFlow(aNext);
     510                 : 
     511               0 :   NS_ASSERTION (!aNext->GetPrevInFlow() || aNext->GetPrevInFlow() == aFrame,
     512                 :                 "prev-in-flow is not prev continuation!");
     513               0 :   aNext->SetPrevInFlow(aFrame);
     514               0 : }
     515                 : 
     516                 : // If aFrame is the last child of its parent, convert bidi continuations to
     517                 : // fluid continuations for all of its inline ancestors.
     518                 : static void
     519               0 : JoinInlineAncestors(nsIFrame* aFrame)
     520                 : {
     521               0 :   if (aFrame->GetNextSibling()) {
     522               0 :     return;
     523                 :   }
     524               0 :   nsIFrame* frame = aFrame->GetParent();
     525               0 :   while (frame && IsBidiSplittable(frame)) {
     526               0 :     nsIFrame* next = frame->GetNextContinuation();
     527               0 :     if (next) {
     528               0 :       MakeContinuationFluid(frame, next);
     529                 :     }
     530                 :     // Join the parent only as long as we're its last child.
     531               0 :     if (frame->GetNextSibling())
     532               0 :       break;
     533               0 :     frame = frame->GetParent();
     534                 :   }
     535                 : }
     536                 : 
     537                 : static nsresult
     538               0 : CreateContinuation(nsIFrame*  aFrame,
     539                 :                    nsIFrame** aNewFrame,
     540                 :                    bool       aIsFluid)
     541                 : {
     542               0 :   NS_PRECONDITION(aNewFrame, "null OUT ptr");
     543               0 :   NS_PRECONDITION(aFrame, "null ptr");
     544                 : 
     545               0 :   *aNewFrame = nsnull;
     546                 : 
     547               0 :   nsPresContext *presContext = aFrame->PresContext();
     548               0 :   nsIPresShell *presShell = presContext->PresShell();
     549               0 :   NS_ASSERTION(presShell, "PresShell must be set on PresContext before calling nsBidiPresUtils::CreateContinuation");
     550                 : 
     551               0 :   nsIFrame* parent = aFrame->GetParent();
     552               0 :   NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateContinuation");
     553                 : 
     554               0 :   nsresult rv = NS_OK;
     555                 :   
     556                 :   // Have to special case floating first letter frames because the continuation
     557                 :   // doesn't go in the first letter frame. The continuation goes with the rest
     558                 :   // of the text that the first letter frame was made out of.
     559               0 :   if (parent->GetType() == nsGkAtoms::letterFrame &&
     560               0 :       parent->GetStyleDisplay()->IsFloating()) {
     561               0 :     nsFirstLetterFrame* letterFrame = do_QueryFrame(parent);
     562                 :     rv = letterFrame->CreateContinuationForFloatingParent(presContext, aFrame,
     563               0 :                                                           aNewFrame, aIsFluid);
     564               0 :     return rv;
     565                 :   }
     566                 : 
     567                 :   rv = presShell->FrameConstructor()->
     568               0 :     CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, aIsFluid);
     569               0 :   if (NS_FAILED(rv)) {
     570               0 :     return rv;
     571                 :   }
     572                 : 
     573                 :   // The list name kNoReflowPrincipalList would indicate we don't want reflow
     574                 :   // XXXbz this needs higher-level framelist love
     575               0 :   nsFrameList temp(*aNewFrame, *aNewFrame);
     576               0 :   rv = parent->InsertFrames(nsIFrame::kNoReflowPrincipalList, aFrame, temp);
     577               0 :   if (NS_FAILED(rv)) {
     578               0 :     return rv;
     579                 :   }
     580                 : 
     581               0 :   if (!aIsFluid) {  
     582                 :     // Split inline ancestor frames
     583               0 :     rv = SplitInlineAncestors(aFrame);
     584               0 :     if (NS_FAILED(rv)) {
     585               0 :       return rv;
     586                 :     }
     587                 :   }
     588                 : 
     589               0 :   return NS_OK;
     590                 : }
     591                 : 
     592                 : /*
     593                 :  * Overview of the implementation of Resolve():
     594                 :  *
     595                 :  *  Walk through the descendants of aBlockFrame and build:
     596                 :  *   * mLogicalFrames: an nsTArray of nsIFrame* pointers in logical order
     597                 :  *   * mBuffer: an nsString containing a representation of
     598                 :  *     the content of the frames.
     599                 :  *     In the case of text frames, this is the actual text context of the
     600                 :  *     frames, but some other elements are represented in a symbolic form which
     601                 :  *     will make the Unicode Bidi Algorithm give the correct results.
     602                 :  *     Bidi embeddings and overrides set by CSS or <bdo> elements are
     603                 :  *     represented by the corresponding Unicode control characters.
     604                 :  *     <br> elements are represented by U+2028 LINE SEPARATOR
     605                 :  *     Other inline elements are represented by U+FFFC OBJECT REPLACEMENT
     606                 :  *     CHARACTER
     607                 :  *
     608                 :  *  Then pass mBuffer to the Bidi engine for resolving of embedding levels
     609                 :  *  by nsBidi::SetPara() and division into directional runs by
     610                 :  *  nsBidi::CountRuns().
     611                 :  *
     612                 :  *  Finally, walk these runs in logical order using nsBidi::GetLogicalRun() and
     613                 :  *  correlate them with the frames indexed in mLogicalFrames, setting the
     614                 :  *  baseLevel and embeddingLevel properties according to the results returned
     615                 :  *  by the Bidi engine.
     616                 :  *
     617                 :  *  The rendering layer requires each text frame to contain text in only one
     618                 :  *  direction, so we may need to call EnsureBidiContinuation() to split frames.
     619                 :  *  We may also need to call RemoveBidiContinuation() to convert frames created
     620                 :  *  by EnsureBidiContinuation() in previous reflows into fluid continuations.
     621                 :  */
     622                 : nsresult
     623               0 : nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
     624                 : {
     625               0 :   BidiParagraphData bpd;
     626               0 :   bpd.Init(aBlockFrame);
     627                 : 
     628                 :   // handle bidi-override being set on the block itself before calling
     629                 :   // TraverseFrames.
     630               0 :   const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
     631               0 :   PRUnichar ch = 0;
     632               0 :   if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) {
     633               0 :     const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
     634               0 :     if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
     635               0 :       ch = kRLO;
     636                 :     }
     637               0 :     else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
     638               0 :       ch = kLRO;
     639                 :     }
     640               0 :     if (ch != 0) {
     641               0 :       bpd.PushBidiControl(ch);
     642                 :     }
     643                 :   }
     644               0 :   for (nsBlockFrame* block = aBlockFrame; block;
     645               0 :        block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
     646               0 :     block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
     647               0 :     nsBlockInFlowLineIterator lineIter(block, block->begin_lines());
     648               0 :     bpd.mPrevFrame = nsnull;
     649               0 :     bpd.GetSubParagraph()->mPrevFrame = nsnull;
     650               0 :     TraverseFrames(aBlockFrame, &lineIter, block->GetFirstPrincipalChild(), &bpd);
     651                 :   }
     652                 : 
     653               0 :   if (ch != 0) {
     654               0 :     bpd.PopBidiControl();
     655                 :   }
     656                 : 
     657               0 :   return ResolveParagraph(aBlockFrame, &bpd);
     658                 : }
     659                 : 
     660                 : nsresult
     661               0 : nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame,
     662                 :                                   BidiParagraphData* aBpd)
     663                 : {
     664               0 :   nsPresContext *presContext = aBlockFrame->PresContext();
     665                 : 
     666               0 :   if (aBpd->BufferLength() < 1) {
     667               0 :     return NS_OK;
     668                 :   }
     669               0 :   aBpd->mBuffer.ReplaceChar("\t\r\n", kSpace);
     670                 : 
     671                 :   PRInt32 runCount;
     672                 : 
     673               0 :   nsresult rv = aBpd->SetPara();
     674               0 :   NS_ENSURE_SUCCESS(rv, rv);
     675                 : 
     676               0 :   PRUint8 embeddingLevel = aBpd->GetParaLevel();
     677                 : 
     678               0 :   rv = aBpd->CountRuns(&runCount);
     679               0 :   NS_ENSURE_SUCCESS(rv, rv);
     680                 : 
     681               0 :   PRInt32     runLength      = 0;   // the length of the current run of text
     682               0 :   PRInt32     lineOffset     = 0;   // the start of the current run
     683               0 :   PRInt32     logicalLimit   = 0;   // the end of the current run + 1
     684               0 :   PRInt32     numRun         = -1;
     685               0 :   PRInt32     fragmentLength = 0;   // the length of the current text frame
     686               0 :   PRInt32     frameIndex     = -1;  // index to the frames in mLogicalFrames
     687               0 :   PRInt32     frameCount     = aBpd->FrameCount();
     688               0 :   PRInt32     contentOffset  = 0;   // offset of current frame in its content node
     689               0 :   bool        isTextFrame    = false;
     690               0 :   nsIFrame*   frame = nsnull;
     691               0 :   nsIContent* content = nsnull;
     692               0 :   PRInt32     contentTextLength = 0;
     693                 : 
     694               0 :   FramePropertyTable *propTable = presContext->PropertyTable();
     695               0 :   nsLineBox* currentLine = nsnull;
     696                 :   
     697                 : #ifdef DEBUG
     698                 : #ifdef NOISY_BIDI
     699                 :   printf("Before Resolve(), aBlockFrame=0x%p, mBuffer='%s', frameCount=%d, runCount=%d\n",
     700                 :          (void*)aBlockFrame, NS_ConvertUTF16toUTF8(aBpd->mBuffer).get(), frameCount, runCount);
     701                 : #ifdef REALLY_NOISY_BIDI
     702                 :   printf(" block frame tree=:\n");
     703                 :   aBlockFrame->List(stdout, 0);
     704                 : #endif
     705                 : #endif
     706                 : #endif
     707                 : 
     708               0 :   for (; ;) {
     709               0 :     if (fragmentLength <= 0) {
     710                 :       // Get the next frame from mLogicalFrames
     711               0 :       if (++frameIndex >= frameCount) {
     712               0 :         break;
     713                 :       }
     714               0 :       frame = aBpd->FrameAt(frameIndex);
     715               0 :       if (frame == NS_BIDI_CONTROL_FRAME ||
     716               0 :           nsGkAtoms::textFrame != frame->GetType()) {
     717                 :         /*
     718                 :          * Any non-text frame corresponds to a single character in the text buffer
     719                 :          * (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
     720                 :          */
     721               0 :         isTextFrame = false;
     722               0 :         fragmentLength = 1;
     723                 :       }
     724                 :       else {
     725               0 :         currentLine = aBpd->GetLineForFrameAt(frameIndex);
     726               0 :         content = frame->GetContent();
     727               0 :         if (!content) {
     728               0 :           rv = NS_OK;
     729               0 :           break;
     730                 :         }
     731               0 :         contentTextLength = content->TextLength();
     732               0 :         if (contentTextLength == 0) {
     733               0 :           frame->AdjustOffsetsForBidi(0, 0);
     734                 :           // Set the base level and embedding level of the current run even
     735                 :           // on an empty frame. Otherwise frame reordering will not be correct.
     736                 :           propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
     737               0 :                          NS_INT32_TO_PTR(embeddingLevel));
     738                 :           propTable->Set(frame, nsIFrame::BaseLevelProperty(),
     739               0 :                          NS_INT32_TO_PTR(aBpd->GetParaLevel()));
     740               0 :           continue;
     741                 :         }
     742                 :         PRInt32 start, end;
     743               0 :         frame->GetOffsets(start, end);
     744               0 :         NS_ASSERTION(!(contentTextLength < end - start),
     745                 :                      "Frame offsets don't fit in content");
     746               0 :         fragmentLength = NS_MIN(contentTextLength, end - start);
     747               0 :         contentOffset = start;
     748               0 :         isTextFrame = true;
     749                 :       }
     750                 :     } // if (fragmentLength <= 0)
     751                 : 
     752               0 :     if (runLength <= 0) {
     753                 :       // Get the next run of text from the Bidi engine
     754               0 :       if (++numRun >= runCount) {
     755               0 :         break;
     756                 :       }
     757               0 :       lineOffset = logicalLimit;
     758               0 :       if (NS_FAILED(aBpd->GetLogicalRun(
     759                 :               lineOffset, &logicalLimit, &embeddingLevel) ) ) {
     760               0 :         break;
     761                 :       }
     762               0 :       runLength = logicalLimit - lineOffset;
     763                 :     } // if (runLength <= 0)
     764                 : 
     765               0 :     if (frame == NS_BIDI_CONTROL_FRAME) {
     766               0 :       frame = nsnull;
     767               0 :       ++lineOffset;
     768                 :     }
     769                 :     else {
     770                 :       propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
     771               0 :                      NS_INT32_TO_PTR(embeddingLevel));
     772                 :       propTable->Set(frame, nsIFrame::BaseLevelProperty(),
     773               0 :                      NS_INT32_TO_PTR(aBpd->GetParaLevel()));
     774               0 :       if (isTextFrame) {
     775               0 :         if ( (runLength > 0) && (runLength < fragmentLength) ) {
     776                 :           /*
     777                 :            * The text in this frame continues beyond the end of this directional run.
     778                 :            * Create a non-fluid continuation frame for the next directional run.
     779                 :            */
     780               0 :           currentLine->MarkDirty();
     781                 :           nsIFrame* nextBidi;
     782               0 :           PRInt32 runEnd = contentOffset + runLength;
     783                 :           rv = EnsureBidiContinuation(frame, &nextBidi, frameIndex,
     784                 :                                       contentOffset,
     785               0 :                                       runEnd);
     786               0 :           if (NS_FAILED(rv)) {
     787               0 :             break;
     788                 :           }
     789                 :           nextBidi->AdjustOffsetsForBidi(runEnd,
     790               0 :                                          contentOffset + fragmentLength);
     791               0 :           frame = nextBidi;
     792               0 :           contentOffset = runEnd;
     793                 :         } // if (runLength < fragmentLength)
     794                 :         else {
     795               0 :           if (contentOffset + fragmentLength == contentTextLength) {
     796                 :             /* 
     797                 :              * We have finished all the text in this content node. Convert any
     798                 :              * further non-fluid continuations to fluid continuations and advance
     799                 :              * frameIndex to the last frame in the content node
     800                 :              */
     801               0 :             PRInt32 newIndex = aBpd->GetLastFrameForContent(content);
     802               0 :             if (newIndex > frameIndex) {
     803                 :               RemoveBidiContinuation(aBpd, frame,
     804               0 :                                      frameIndex, newIndex, lineOffset);
     805               0 :               frameIndex = newIndex;
     806                 :             }
     807               0 :           } else if (fragmentLength > 0 && runLength > fragmentLength) {
     808                 :             /*
     809                 :              * There is more text that belongs to this directional run in the next
     810                 :              * text frame: make sure it is a fluid continuation of the current frame.
     811                 :              * Do not advance frameIndex, because the next frame may contain
     812                 :              * multi-directional text and need to be split
     813                 :              */
     814               0 :             PRInt32 newIndex = frameIndex;
     815               0 :             do {
     816                 :             } while (++newIndex < frameCount &&
     817               0 :                      aBpd->FrameAt(newIndex) == NS_BIDI_CONTROL_FRAME);
     818               0 :             if (newIndex < frameCount) {
     819                 :               RemoveBidiContinuation(aBpd, frame,
     820               0 :                                      frameIndex, newIndex, lineOffset);
     821               0 :             }
     822               0 :           } else if (runLength == fragmentLength) {
     823                 :             /*
     824                 :              * If the directional run ends at the end of the frame, make sure
     825                 :              * that any continuation is non-fluid
     826                 :              */
     827               0 :             nsIFrame* next = frame->GetNextInFlow();
     828               0 :             if (next) {
     829               0 :               frame->SetNextContinuation(next);
     830               0 :               next->SetPrevContinuation(frame);
     831                 :             }
     832                 :           }
     833               0 :           frame->AdjustOffsetsForBidi(contentOffset, contentOffset + fragmentLength);
     834               0 :           currentLine->MarkDirty();
     835                 :         }
     836                 :       } // isTextFrame
     837                 :       else {
     838               0 :         ++lineOffset;
     839                 :       }
     840                 :     } // not bidi control frame
     841               0 :     PRInt32 temp = runLength;
     842               0 :     runLength -= fragmentLength;
     843               0 :     fragmentLength -= temp;
     844                 : 
     845               0 :     if (frame && fragmentLength <= 0) {
     846                 :       // If the frame is at the end of a run, and this is not the end of our
     847                 :       // paragrah, split all ancestor inlines that need splitting.
     848                 :       // To determine whether we're at the end of the run, we check that we've
     849                 :       // finished processing the current run, and that the current frame
     850                 :       // doesn't have a fluid continuation (it could have a fluid continuation
     851                 :       // of zero length, so testing runLength alone is not sufficient).
     852               0 :       if (runLength <= 0 && !frame->GetNextInFlow()) {
     853               0 :         if (numRun + 1 < runCount) {
     854               0 :           nsIFrame* child = frame;
     855               0 :           nsIFrame* parent = frame->GetParent();
     856                 :           // As long as we're on the last sibling, the parent doesn't have to
     857                 :           // be split.
     858                 :           // However, if the parent has a fluid continuation, we do have to make
     859                 :           // it non-fluid. This can happen e.g. when we have a first-letter
     860                 :           // frame and the end of the first-letter coincides with the end of a
     861                 :           // directional run.
     862               0 :           while (parent &&
     863               0 :                  IsBidiSplittable(parent) &&
     864               0 :                  !child->GetNextSibling()) {
     865               0 :             nsIFrame* next = parent->GetNextInFlow();
     866               0 :             if (next) {
     867               0 :               parent->SetNextContinuation(next);
     868               0 :               next->SetPrevContinuation(parent);
     869                 :             }
     870               0 :             child = parent;
     871               0 :             parent = child->GetParent();
     872                 :           }
     873               0 :           if (parent && IsBidiSplittable(parent))
     874               0 :             SplitInlineAncestors(child);
     875                 :         }
     876                 :       }
     877                 :       else {
     878                 :         // We're not at an end of a run. If |frame| is the last child of its
     879                 :         // parent, and its ancestors happen to have bidi continuations, convert
     880                 :         // them into fluid continuations.
     881               0 :         JoinInlineAncestors(frame);
     882                 :       }
     883                 :     }
     884                 :   } // for
     885                 : 
     886                 : #ifdef DEBUG
     887                 : #ifdef REALLY_NOISY_BIDI
     888                 :   printf("---\nAfter Resolve(), frameTree =:\n");
     889                 :   aBlockFrame->List(stdout, 0);
     890                 :   printf("===\n");
     891                 : #endif
     892                 : #endif
     893                 : 
     894               0 :   return rv;
     895                 : }
     896                 : 
     897                 : // Should this frame be treated as a leaf (e.g. when building mLogicalFrames)?
     898               0 : bool IsBidiLeaf(nsIFrame* aFrame) {
     899               0 :   nsIFrame* kid = aFrame->GetFirstPrincipalChild();
     900                 :   return !kid
     901               0 :     || !aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer);
     902                 : }
     903                 : 
     904                 : void
     905               0 : nsBidiPresUtils::TraverseFrames(nsBlockFrame*              aBlockFrame,
     906                 :                                 nsBlockInFlowLineIterator* aLineIter,
     907                 :                                 nsIFrame*                  aCurrentFrame,
     908                 :                                 BidiParagraphData*         aBpd)
     909                 : {
     910               0 :   if (!aCurrentFrame)
     911               0 :     return;
     912                 : 
     913               0 :   nsIFrame* childFrame = aCurrentFrame;
     914               0 :   do {
     915                 :     /*
     916                 :      * It's important to get the next sibling and next continuation *before*
     917                 :      * handling the frame: If we encounter a forced paragraph break and call
     918                 :      * ResolveParagraph within this loop, doing GetNextSibling and
     919                 :      * GetNextContinuation after that could return a bidi continuation that had
     920                 :      * just been split from the original childFrame and we would process it
     921                 :      * twice.
     922                 :      */
     923               0 :     nsIFrame* nextSibling = childFrame->GetNextSibling();
     924               0 :     bool isLastFrame = !childFrame->GetNextContinuation();
     925               0 :     bool isFirstFrame = !childFrame->GetPrevContinuation();
     926                 : 
     927                 :     // If the real frame for a placeholder is a first letter frame, we need to
     928                 :     // drill down into it and include its contents in Bidi resolution.
     929                 :     // If not, we just use the placeholder.
     930               0 :     nsIFrame* frame = childFrame;
     931               0 :     if (nsGkAtoms::placeholderFrame == childFrame->GetType()) {
     932                 :       nsIFrame* realFrame =
     933               0 :         nsPlaceholderFrame::GetRealFrameForPlaceholder(childFrame);
     934               0 :       if (realFrame->GetType() == nsGkAtoms::letterFrame) {
     935               0 :         frame = realFrame;
     936                 :       }
     937                 :     }
     938                 : 
     939               0 :     PRUnichar ch = 0;
     940               0 :     if (frame->IsFrameOfType(nsIFrame::eBidiInlineContainer)) {
     941               0 :       const nsStyleVisibility* vis = frame->GetStyleVisibility();
     942               0 :       const nsStyleTextReset* text = frame->GetStyleTextReset();
     943               0 :       if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_OVERRIDE) {
     944               0 :         if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
     945               0 :           ch = kRLO;
     946                 :         }
     947               0 :         else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
     948               0 :           ch = kLRO;
     949                 :         }
     950               0 :       } else if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_EMBED) {
     951               0 :         if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
     952               0 :           ch = kRLE;
     953                 :         }
     954               0 :         else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
     955               0 :           ch = kLRE;
     956                 :         }
     957                 :       }
     958                 : 
     959                 :       // Add a dummy frame pointer representing a bidi control code before the
     960                 :       // first frame of an element specifying embedding or override
     961               0 :       if (ch != 0 && isFirstFrame) {
     962               0 :         aBpd->PushBidiControl(ch);
     963                 :       }
     964                 :     }
     965                 : 
     966               0 :     if (IsBidiLeaf(frame)) {
     967                 :       /* Bidi leaf frame: add the frame to the mLogicalFrames array,
     968                 :        * and add its index to the mContentToFrameIndex hashtable. This
     969                 :        * will be used in RemoveBidiContinuation() to identify the last
     970                 :        * frame in the array with a given content.
     971                 :        */
     972               0 :       nsIContent* content = frame->GetContent();
     973               0 :       aBpd->AppendFrame(frame, aLineIter, content);
     974                 : 
     975                 :       // Append the content of the frame to the paragraph buffer
     976               0 :       nsIAtom* frameType = frame->GetType();
     977               0 :       if (nsGkAtoms::textFrame == frameType) {
     978               0 :         if (content != aBpd->mPrevContent) {
     979               0 :           aBpd->mPrevContent = content;
     980               0 :           if (!frame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
     981               0 :             content->AppendTextTo(aBpd->mBuffer);
     982                 :           } else {
     983                 :             /*
     984                 :              * For preformatted text we have to do bidi resolution on each line
     985                 :              * separately. 
     986                 :              */
     987               0 :             nsAutoString text;
     988               0 :             content->AppendTextTo(text);
     989                 :             nsIFrame* next;
     990               0 :             do {
     991               0 :               next = nsnull;
     992                 : 
     993                 :               PRInt32 start, end;
     994               0 :               frame->GetOffsets(start, end);
     995               0 :               PRInt32 endLine = text.FindChar('\n', start);
     996               0 :               if (endLine == -1) {
     997                 :                 /*
     998                 :                  * If there is no newline in the text content, just save the
     999                 :                  * text from this frame and its continuations, and do bidi
    1000                 :                  * resolution later
    1001                 :                  */
    1002               0 :                 aBpd->AppendString(Substring(text, start));
    1003               0 :                 while (frame && nextSibling) {
    1004               0 :                   aBpd->AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
    1005                 :                 }
    1006               0 :                 break;
    1007                 :               }
    1008                 : 
    1009                 :               /*
    1010                 :                * If there is a newline in the frame, break the frame after the
    1011                 :                * newline, do bidi resolution and repeat until the last sibling
    1012                 :                */
    1013               0 :               ++endLine;
    1014                 : 
    1015                 :               /*
    1016                 :                * If the frame ends before the new line, save the text and move
    1017                 :                * into the next continuation
    1018                 :                */
    1019                 :               aBpd->AppendString(Substring(text, start,
    1020               0 :                                            NS_MIN(end, endLine) - start));
    1021               0 :               while (end < endLine && nextSibling) { 
    1022               0 :                 aBpd->AdvanceAndAppendFrame(&frame, aLineIter, &nextSibling);
    1023               0 :                 NS_ASSERTION(frame, "Premature end of continuation chain");
    1024               0 :                 frame->GetOffsets(start, end);
    1025                 :                 aBpd->AppendString(Substring(text, start,
    1026               0 :                                              NS_MIN(end, endLine) - start));
    1027                 :               }
    1028                 : 
    1029               0 :               if (end < endLine) {
    1030               0 :                 aBpd->mPrevContent = nsnull;
    1031               0 :                 break;
    1032                 :               }
    1033                 : 
    1034               0 :               bool createdContinuation = false;
    1035               0 :               if (PRUint32(endLine) < text.Length()) {
    1036                 :                 /*
    1037                 :                  * Timing is everything here: if the frame already has a bidi
    1038                 :                  * continuation, we need to make the continuation fluid *before*
    1039                 :                  * resetting the length of the current frame. Otherwise
    1040                 :                  * nsTextFrame::SetLength won't set the continuation frame's
    1041                 :                  * text offsets correctly.
    1042                 :                  *
    1043                 :                  * On the other hand, if the frame doesn't have a continuation,
    1044                 :                  * we need to create one *after* resetting the length, or
    1045                 :                  * CreateContinuingFrame will complain that there is no more
    1046                 :                  * content for the continuation.               
    1047                 :                  */
    1048               0 :                 next = frame->GetNextInFlow();
    1049               0 :                 if (!next) {
    1050                 :                   // If the frame already has a bidi continuation, make it fluid
    1051               0 :                   next = frame->GetNextContinuation();
    1052               0 :                   if (next) {
    1053               0 :                     MakeContinuationFluid(frame, next);
    1054               0 :                     JoinInlineAncestors(frame);
    1055                 :                   }
    1056                 :                 }
    1057                 : 
    1058               0 :                 nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
    1059               0 :                 textFrame->SetLength(endLine - start, nsnull);
    1060                 : 
    1061               0 :                 if (!next) {
    1062                 :                   // If the frame has no next in flow, create one.
    1063               0 :                   CreateContinuation(frame, &next, true);
    1064               0 :                   createdContinuation = true;
    1065                 :                 }
    1066                 :               }
    1067               0 :               ResolveParagraphWithinBlock(aBlockFrame, aBpd);
    1068                 : 
    1069               0 :               if (!nextSibling && !createdContinuation) {
    1070               0 :                 break;
    1071               0 :               } else if (next) {
    1072               0 :                 frame = next;
    1073               0 :                 aBpd->AppendFrame(frame, aLineIter);
    1074                 :               }
    1075                 : 
    1076                 :               /*
    1077                 :                * If we have already overshot the saved next-sibling while
    1078                 :                * scanning the frame's continuations, advance it.
    1079                 :                */
    1080               0 :               if (frame && frame == nextSibling) {
    1081               0 :                 nextSibling = frame->GetNextSibling();
    1082                 :               }
    1083                 : 
    1084                 :             } while (next);
    1085                 :           }
    1086                 :         }
    1087               0 :       } else if (nsGkAtoms::brFrame == frameType) {
    1088                 :         // break frame -- append line separator
    1089               0 :         aBpd->AppendUnichar(kLineSeparator);
    1090               0 :         ResolveParagraphWithinBlock(aBlockFrame, aBpd);
    1091                 :       } else { 
    1092                 :         // other frame type -- see the Unicode Bidi Algorithm:
    1093                 :         // "...inline objects (such as graphics) are treated as if they are ...
    1094                 :         // U+FFFC"
    1095                 :         // <wbr>, however, is treated as U+200B ZERO WIDTH SPACE. See
    1096                 :         // http://dev.w3.org/html5/spec/Overview.html#phrasing-content-1
    1097               0 :         aBpd->AppendUnichar(content->IsHTML(nsGkAtoms::wbr) ?
    1098               0 :                             kZWSP : kObjectSubstitute);
    1099               0 :         if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) {
    1100                 :           // if it is not inline, end the paragraph
    1101               0 :           ResolveParagraphWithinBlock(aBlockFrame, aBpd);
    1102                 :         }
    1103                 :       }
    1104                 :     }
    1105                 :     else {
    1106                 :       // For a non-leaf frame, recurse into TraverseFrames
    1107               0 :       nsIFrame* kid = frame->GetFirstPrincipalChild();
    1108               0 :       if (kid) {
    1109               0 :         const nsStyleTextReset* text = frame->GetStyleTextReset();
    1110               0 :         if (text->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_ISOLATE) {
    1111                 :           // css "unicode-bidi: isolate" and html5 bdi: 
    1112                 :           //  resolve the element as a separate paragraph
    1113               0 :           BidiParagraphData* subParagraph = aBpd->GetSubParagraph();
    1114                 : 
    1115                 :           /*
    1116                 :            * As at the beginning of the loop, it's important to check for
    1117                 :            * next-continuations before handling the frame. If we do
    1118                 :            * TraverseFrames and *then* do GetNextContinuation on the original
    1119                 :            * first frame, it could return a bidi continuation that had only
    1120                 :            * just been created, and we would skip doing bidi resolution on the
    1121                 :            * last part of the sub-paragraph.
    1122                 :            */
    1123               0 :           bool isLastContinuation = !frame->GetNextContinuation();
    1124               0 :           if (!frame->GetPrevContinuation() || !subParagraph->mReset) {
    1125               0 :             subParagraph->Reset(kid, aBpd);
    1126                 :           }
    1127               0 :           TraverseFrames(aBlockFrame, aLineIter, kid, subParagraph);
    1128               0 :           if (isLastContinuation) {
    1129               0 :             ResolveParagraph(aBlockFrame, subParagraph);
    1130                 :           }
    1131                 : 
    1132                 :           // Treat the element as a neutral character within its containing
    1133                 :           //  paragraph.
    1134               0 :           aBpd->AppendControlChar(kObjectSubstitute);
    1135                 :         } else {
    1136               0 :           TraverseFrames(aBlockFrame, aLineIter, kid, aBpd);
    1137                 :         }
    1138                 :       }
    1139                 :     }
    1140                 : 
    1141                 :     // If the element is attributed by dir, indicate direction pop (add PDF frame)
    1142               0 :     if (isLastFrame) {
    1143               0 :       if (ch) {
    1144                 :         // Add a dummy frame pointer representing a bidi control code after the
    1145                 :         // last frame of an element specifying embedding or override
    1146               0 :         aBpd->PopBidiControl();
    1147                 :       }
    1148                 :     }
    1149               0 :     childFrame = nextSibling;
    1150                 :   } while (childFrame);
    1151                 : }
    1152                 : 
    1153                 : void
    1154               0 : nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
    1155                 :                                              BidiParagraphData* aBpd)
    1156                 : {
    1157               0 :   aBpd->ClearBidiControls();
    1158               0 :   ResolveParagraph(aBlockFrame, aBpd);
    1159               0 :   aBpd->ResetData();
    1160               0 : }
    1161                 : 
    1162                 : void
    1163               0 : nsBidiPresUtils::ReorderFrames(nsIFrame*            aFirstFrameOnLine,
    1164                 :                                PRInt32              aNumFramesOnLine)
    1165                 : {
    1166                 :   // If this line consists of a line frame, reorder the line frame's children.
    1167               0 :   if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
    1168               0 :     aFirstFrameOnLine = aFirstFrameOnLine->GetFirstPrincipalChild();
    1169               0 :     if (!aFirstFrameOnLine)
    1170               0 :       return;
    1171                 :     // All children of the line frame are on the first line. Setting aNumFramesOnLine
    1172                 :     // to -1 makes InitLogicalArrayFromLine look at all of them.
    1173               0 :     aNumFramesOnLine = -1;
    1174                 :   }
    1175                 : 
    1176               0 :   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
    1177               0 :   RepositionInlineFrames(&bld, aFirstFrameOnLine);
    1178                 : }
    1179                 : 
    1180                 : nsBidiLevel
    1181               0 : nsBidiPresUtils::GetFrameEmbeddingLevel(nsIFrame* aFrame)
    1182                 : {
    1183               0 :   nsIFrame* firstLeaf = aFrame;
    1184               0 :   while (!IsBidiLeaf(firstLeaf)) {
    1185               0 :     nsIFrame* firstChild = firstLeaf->GetFirstPrincipalChild();
    1186               0 :     nsIFrame* realFrame = nsPlaceholderFrame::GetRealFrameFor(firstChild);
    1187               0 :     firstLeaf = (realFrame->GetType() == nsGkAtoms::letterFrame) ?
    1188               0 :                  realFrame : firstChild;
    1189                 :   }
    1190               0 :   return NS_GET_EMBEDDING_LEVEL(firstLeaf);
    1191                 : }
    1192                 : 
    1193                 : nsBidiLevel
    1194               0 : nsBidiPresUtils::GetFrameBaseLevel(nsIFrame* aFrame)
    1195                 : {
    1196               0 :   nsIFrame* firstLeaf = aFrame;
    1197               0 :   while (!IsBidiLeaf(firstLeaf)) {
    1198               0 :     firstLeaf = firstLeaf->GetFirstPrincipalChild();
    1199                 :   }
    1200               0 :   return NS_GET_BASE_LEVEL(firstLeaf);
    1201                 : }
    1202                 : 
    1203                 : void
    1204               0 : nsBidiPresUtils::IsLeftOrRightMost(nsIFrame*              aFrame,
    1205                 :                                    nsContinuationStates*  aContinuationStates,
    1206                 :                                    bool&                aIsLeftMost /* out */,
    1207                 :                                    bool&                aIsRightMost /* out */)
    1208                 : {
    1209               0 :   const nsStyleVisibility* vis = aFrame->GetStyleVisibility();
    1210               0 :   bool isLTR = (NS_STYLE_DIRECTION_LTR == vis->mDirection);
    1211                 : 
    1212                 :   /*
    1213                 :    * Since we lay out frames from left to right (in both LTR and RTL), visiting a
    1214                 :    * frame with 'mFirstVisualFrame == nsnull', means it's the first appearance of
    1215                 :    * one of its continuation chain frames on the line.
    1216                 :    * To determine if it's the last visual frame of its continuation chain on the line
    1217                 :    * or not, we count the number of frames of the chain on the line, and then reduce
    1218                 :    * it when we lay out a frame of the chain. If this value becomes 1 it means
    1219                 :    * that it's the last visual frame of its continuation chain on this line.
    1220                 :    */
    1221                 : 
    1222               0 :   nsFrameContinuationState* frameState = aContinuationStates->GetEntry(aFrame);
    1223                 :   nsFrameContinuationState* firstFrameState;
    1224                 : 
    1225               0 :   if (!frameState->mFirstVisualFrame) {
    1226                 :     // aFrame is the first visual frame of its continuation chain
    1227                 :     nsFrameContinuationState* contState;
    1228                 :     nsIFrame* frame;
    1229                 : 
    1230               0 :     frameState->mFrameCount = 1;
    1231               0 :     frameState->mFirstVisualFrame = aFrame;
    1232                 : 
    1233                 :     /**
    1234                 :      * Traverse continuation chain of aFrame in both backward and forward
    1235                 :      * directions while the frames are on this line. Count the frames and
    1236                 :      * set their mFirstVisualFrame to aFrame.
    1237                 :      */
    1238                 :     // Traverse continuation chain backward
    1239               0 :     for (frame = aFrame->GetPrevContinuation();
    1240                 :          frame && (contState = aContinuationStates->GetEntry(frame));
    1241               0 :          frame = frame->GetPrevContinuation()) {
    1242               0 :       frameState->mFrameCount++;
    1243               0 :       contState->mFirstVisualFrame = aFrame;
    1244                 :     }
    1245               0 :     frameState->mHasContOnPrevLines = (frame != nsnull);
    1246                 : 
    1247                 :     // Traverse continuation chain forward
    1248               0 :     for (frame = aFrame->GetNextContinuation();
    1249                 :          frame && (contState = aContinuationStates->GetEntry(frame));
    1250               0 :          frame = frame->GetNextContinuation()) {
    1251               0 :       frameState->mFrameCount++;
    1252               0 :       contState->mFirstVisualFrame = aFrame;
    1253                 :     }
    1254               0 :     frameState->mHasContOnNextLines = (frame != nsnull);
    1255                 : 
    1256               0 :     aIsLeftMost = isLTR ? !frameState->mHasContOnPrevLines
    1257               0 :                         : !frameState->mHasContOnNextLines;
    1258               0 :     firstFrameState = frameState;
    1259                 :   } else {
    1260                 :     // aFrame is not the first visual frame of its continuation chain
    1261               0 :     aIsLeftMost = false;
    1262               0 :     firstFrameState = aContinuationStates->GetEntry(frameState->mFirstVisualFrame);
    1263                 :   }
    1264                 : 
    1265                 :   aIsRightMost = (firstFrameState->mFrameCount == 1) &&
    1266               0 :                  (isLTR ? !firstFrameState->mHasContOnNextLines
    1267               0 :                         : !firstFrameState->mHasContOnPrevLines);
    1268                 : 
    1269               0 :   if ((aIsLeftMost || aIsRightMost) &&
    1270               0 :       (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL)) {
    1271                 :     // For ib splits, don't treat anything except the last part as
    1272                 :     // endmost or anything except the first part as startmost.
    1273                 :     // As an optimization, only get the first continuation once.
    1274               0 :     nsIFrame* firstContinuation = aFrame->GetFirstContinuation();
    1275               0 :     if (nsLayoutUtils::FrameIsNonLastInIBSplit(firstContinuation)) {
    1276                 :       // We are not endmost
    1277               0 :       if (isLTR) {
    1278               0 :         aIsRightMost = false;
    1279                 :       } else {
    1280               0 :         aIsLeftMost = false;
    1281                 :       }
    1282                 :     }
    1283               0 :     if (nsLayoutUtils::FrameIsNonFirstInIBSplit(firstContinuation)) {
    1284                 :       // We are not startmost
    1285               0 :       if (isLTR) {
    1286               0 :         aIsLeftMost = false;
    1287                 :       } else {
    1288               0 :         aIsRightMost = false;
    1289                 :       }
    1290                 :     }
    1291                 :   }
    1292                 : 
    1293                 :   // Reduce number of remaining frames of the continuation chain on the line.
    1294               0 :   firstFrameState->mFrameCount--;
    1295               0 : }
    1296                 : 
    1297                 : void
    1298               0 : nsBidiPresUtils::RepositionFrame(nsIFrame*              aFrame,
    1299                 :                                  bool                   aIsOddLevel,
    1300                 :                                  nscoord&               aLeft,
    1301                 :                                  nsContinuationStates*  aContinuationStates)
    1302                 : {
    1303               0 :   if (!aFrame)
    1304               0 :     return;
    1305                 : 
    1306                 :   bool isLeftMost, isRightMost;
    1307                 :   IsLeftOrRightMost(aFrame,
    1308                 :                     aContinuationStates,
    1309                 :                     isLeftMost /* out */,
    1310               0 :                     isRightMost /* out */);
    1311                 : 
    1312               0 :   nsInlineFrame* testFrame = do_QueryFrame(aFrame);
    1313               0 :   if (testFrame) {
    1314               0 :     aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET);
    1315                 : 
    1316               0 :     if (isLeftMost)
    1317               0 :       aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LEFT_MOST);
    1318                 :     else
    1319               0 :       aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_LEFT_MOST);
    1320                 : 
    1321               0 :     if (isRightMost)
    1322               0 :       aFrame->AddStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_RIGHT_MOST);
    1323                 :     else
    1324               0 :       aFrame->RemoveStateBits(NS_INLINE_FRAME_BIDI_VISUAL_IS_RIGHT_MOST);
    1325                 :   }
    1326                 :   // This method is called from nsBlockFrame::PlaceLine via the call to
    1327                 :   // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
    1328                 :   // have been reflowed, which is required for GetUsedMargin/Border/Padding
    1329               0 :   nsMargin margin = aFrame->GetUsedMargin();
    1330               0 :   if (isLeftMost)
    1331               0 :     aLeft += margin.left;
    1332                 : 
    1333               0 :   nscoord start = aLeft;
    1334                 : 
    1335               0 :   if (!IsBidiLeaf(aFrame))
    1336                 :   {
    1337               0 :     nscoord x = 0;
    1338               0 :     nsMargin borderPadding = aFrame->GetUsedBorderAndPadding();
    1339               0 :     if (isLeftMost) {
    1340               0 :       x += borderPadding.left;
    1341                 :     }
    1342                 : 
    1343                 :     // If aIsOddLevel is true, so we need to traverse the child list
    1344                 :     // in reverse order, to make it O(n) we store the list locally and
    1345                 :     // iterate the list reversely
    1346               0 :     nsTArray<nsIFrame*> childList;
    1347               0 :     nsIFrame *frame = aFrame->GetFirstPrincipalChild();
    1348               0 :     if (frame && aIsOddLevel) {
    1349               0 :       childList.AppendElement((nsIFrame*)nsnull);
    1350               0 :       while (frame) {
    1351               0 :         childList.AppendElement(frame);
    1352               0 :         frame = frame->GetNextSibling();
    1353                 :       }
    1354               0 :       frame = childList[childList.Length() - 1];
    1355                 :     }
    1356                 : 
    1357                 :     // Reposition the child frames
    1358               0 :     PRInt32 index = 0;
    1359               0 :     while (frame) {
    1360                 :       RepositionFrame(frame,
    1361                 :                       aIsOddLevel,
    1362                 :                       x,
    1363               0 :                       aContinuationStates);
    1364               0 :       index++;
    1365                 :       frame = aIsOddLevel ?
    1366               0 :                 childList[childList.Length() - index - 1] :
    1367               0 :                 frame->GetNextSibling();
    1368                 :     }
    1369                 : 
    1370               0 :     if (isRightMost) {
    1371               0 :       x += borderPadding.right;
    1372                 :     }
    1373               0 :     aLeft += x;
    1374                 :   } else {
    1375               0 :     aLeft += aFrame->GetSize().width;
    1376                 :   }
    1377               0 :   nsRect rect = aFrame->GetRect();
    1378               0 :   aFrame->SetRect(nsRect(start, rect.y, aLeft - start, rect.height));
    1379                 : 
    1380               0 :   if (isRightMost)
    1381               0 :     aLeft += margin.right;
    1382                 : }
    1383                 : 
    1384                 : void
    1385               0 : nsBidiPresUtils::InitContinuationStates(nsIFrame*              aFrame,
    1386                 :                                         nsContinuationStates*  aContinuationStates)
    1387                 : {
    1388               0 :   nsFrameContinuationState* state = aContinuationStates->PutEntry(aFrame);
    1389               0 :   state->mFirstVisualFrame = nsnull;
    1390               0 :   state->mFrameCount = 0;
    1391                 : 
    1392               0 :   if (!IsBidiLeaf(aFrame)) {
    1393                 :     // Continue for child frames
    1394                 :     nsIFrame* frame;
    1395               0 :     for (frame = aFrame->GetFirstPrincipalChild();
    1396                 :          frame;
    1397                 :          frame = frame->GetNextSibling()) {
    1398                 :       InitContinuationStates(frame,
    1399               0 :                              aContinuationStates);
    1400                 :     }
    1401                 :   }
    1402               0 : }
    1403                 : 
    1404                 : void
    1405               0 : nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
    1406                 :                                         nsIFrame* aFirstChild)
    1407                 : {
    1408               0 :   const nsStyleVisibility* vis = aFirstChild->GetStyleVisibility();
    1409               0 :   bool isLTR = (NS_STYLE_DIRECTION_LTR == vis->mDirection);
    1410               0 :   nscoord leftSpace = 0;
    1411                 : 
    1412                 :   // This method is called from nsBlockFrame::PlaceLine via the call to
    1413                 :   // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
    1414                 :   // have been reflowed, which is required for GetUsedMargin/Border/Padding
    1415               0 :   nsMargin margin = aFirstChild->GetUsedMargin();
    1416               0 :   if (!aFirstChild->GetPrevContinuation() &&
    1417               0 :       !nsLayoutUtils::FrameIsNonFirstInIBSplit(aFirstChild))
    1418               0 :     leftSpace = isLTR ? margin.left : margin.right;
    1419                 : 
    1420               0 :   nscoord left = aFirstChild->GetPosition().x - leftSpace;
    1421                 :   nsIFrame* frame;
    1422               0 :   PRInt32 count = aBld->mVisualFrames.Length();
    1423                 :   PRInt32 index;
    1424               0 :   nsContinuationStates continuationStates;
    1425                 : 
    1426               0 :   continuationStates.Init();
    1427                 : 
    1428                 :   // Initialize continuation states to (nsnull, 0) for
    1429                 :   // each frame on the line.
    1430               0 :   for (index = 0; index < count; index++) {
    1431               0 :     InitContinuationStates(aBld->VisualFrameAt(index), &continuationStates);
    1432                 :   }
    1433                 : 
    1434                 :   // Reposition frames in visual order
    1435               0 :   for (index = 0; index < count; index++) {
    1436               0 :     frame = aBld->VisualFrameAt(index);
    1437                 :     RepositionFrame(frame,
    1438               0 :                     (aBld->mLevels[aBld->mIndexMap[index]] & 1),
    1439                 :                     left,
    1440               0 :                     &continuationStates);
    1441                 :   } // for
    1442               0 : }
    1443                 : 
    1444                 : bool
    1445               0 : nsBidiPresUtils::CheckLineOrder(nsIFrame*  aFirstFrameOnLine,
    1446                 :                                 PRInt32    aNumFramesOnLine,
    1447                 :                                 nsIFrame** aFirstVisual,
    1448                 :                                 nsIFrame** aLastVisual)
    1449                 : {
    1450               0 :   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
    1451               0 :   PRInt32 count = bld.FrameCount();
    1452                 :   
    1453               0 :   if (aFirstVisual) {
    1454               0 :     *aFirstVisual = bld.VisualFrameAt(0);
    1455                 :   }
    1456               0 :   if (aLastVisual) {
    1457               0 :     *aLastVisual = bld.VisualFrameAt(count-1);
    1458                 :   }
    1459                 :   
    1460               0 :   return bld.mIsReordered;
    1461                 : }
    1462                 : 
    1463                 : nsIFrame*
    1464               0 : nsBidiPresUtils::GetFrameToRightOf(const nsIFrame*  aFrame,
    1465                 :                                    nsIFrame*        aFirstFrameOnLine,
    1466                 :                                    PRInt32          aNumFramesOnLine)
    1467                 : {
    1468               0 :   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
    1469                 : 
    1470               0 :   PRInt32 count = bld.mVisualFrames.Length();
    1471                 : 
    1472               0 :   if (aFrame == nsnull && count)
    1473               0 :     return bld.VisualFrameAt(0);
    1474                 :   
    1475               0 :   for (PRInt32 i = 0; i < count - 1; i++) {
    1476               0 :     if (bld.VisualFrameAt(i) == aFrame) {
    1477               0 :       return bld.VisualFrameAt(i+1);
    1478                 :     }
    1479                 :   }
    1480                 :   
    1481               0 :   return nsnull;
    1482                 : }
    1483                 : 
    1484                 : nsIFrame*
    1485               0 : nsBidiPresUtils::GetFrameToLeftOf(const nsIFrame*  aFrame,
    1486                 :                                   nsIFrame*        aFirstFrameOnLine,
    1487                 :                                   PRInt32          aNumFramesOnLine)
    1488                 : {
    1489               0 :   BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
    1490                 : 
    1491               0 :   PRInt32 count = bld.mVisualFrames.Length();
    1492                 :   
    1493               0 :   if (aFrame == nsnull && count)
    1494               0 :     return bld.VisualFrameAt(count-1);
    1495                 :   
    1496               0 :   for (PRInt32 i = 1; i < count; i++) {
    1497               0 :     if (bld.VisualFrameAt(i) == aFrame) {
    1498               0 :       return bld.VisualFrameAt(i-1);
    1499                 :     }
    1500                 :   }
    1501                 :   
    1502               0 :   return nsnull;
    1503                 : }
    1504                 : 
    1505                 : inline nsresult
    1506               0 : nsBidiPresUtils::EnsureBidiContinuation(nsIFrame*       aFrame,
    1507                 :                                         nsIFrame**      aNewFrame,
    1508                 :                                         PRInt32&        aFrameIndex,
    1509                 :                                         PRInt32         aStart,
    1510                 :                                         PRInt32         aEnd)
    1511                 : {
    1512               0 :   NS_PRECONDITION(aNewFrame, "null OUT ptr");
    1513               0 :   NS_PRECONDITION(aFrame, "aFrame is null");
    1514                 : 
    1515               0 :   aFrame->AdjustOffsetsForBidi(aStart, aEnd);
    1516               0 :   return CreateContinuation(aFrame, aNewFrame, false);
    1517                 : }
    1518                 : 
    1519                 : void
    1520               0 : nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
    1521                 :                                         nsIFrame*       aFrame,
    1522                 :                                         PRInt32         aFirstIndex,
    1523                 :                                         PRInt32         aLastIndex,
    1524                 :                                         PRInt32&        aOffset)
    1525                 : {
    1526               0 :   FrameProperties props = aFrame->Properties();
    1527                 :   nsBidiLevel embeddingLevel =
    1528               0 :     (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::EmbeddingLevelProperty()));
    1529                 :   nsBidiLevel baseLevel =
    1530               0 :     (nsBidiLevel)NS_PTR_TO_INT32(props.Get(nsIFrame::BaseLevelProperty()));
    1531                 : 
    1532               0 :   for (PRInt32 index = aFirstIndex + 1; index <= aLastIndex; index++) {
    1533               0 :     nsIFrame* frame = aBpd->FrameAt(index);
    1534               0 :     if (frame == NS_BIDI_CONTROL_FRAME) {
    1535               0 :       ++aOffset;
    1536                 :     }
    1537                 :     else {
    1538                 :       // Make the frame and its continuation ancestors fluid,
    1539                 :       // so they can be reused or deleted by normal reflow code
    1540               0 :       FrameProperties frameProps = frame->Properties();
    1541                 :       frameProps.Set(nsIFrame::EmbeddingLevelProperty(),
    1542               0 :                      NS_INT32_TO_PTR(embeddingLevel));
    1543                 :       frameProps.Set(nsIFrame::BaseLevelProperty(),
    1544               0 :                      NS_INT32_TO_PTR(baseLevel));
    1545               0 :       frame->AddStateBits(NS_FRAME_IS_BIDI);
    1546               0 :       while (frame) {
    1547               0 :         nsIFrame* prev = frame->GetPrevContinuation();
    1548               0 :         if (prev) {
    1549               0 :           MakeContinuationFluid(prev, frame);
    1550               0 :           frame = frame->GetParent();
    1551                 :         } else {
    1552               0 :           break;
    1553                 :         }
    1554                 :       }
    1555                 :     }
    1556                 :   }
    1557               0 : }
    1558                 : 
    1559                 : nsresult
    1560               0 : nsBidiPresUtils::FormatUnicodeText(nsPresContext*  aPresContext,
    1561                 :                                    PRUnichar*       aText,
    1562                 :                                    PRInt32&         aTextLength,
    1563                 :                                    nsCharType       aCharType,
    1564                 :                                    bool             aIsOddLevel)
    1565                 : {
    1566                 :   NS_ASSERTION(aIsOddLevel == 0 || aIsOddLevel == 1, "aIsOddLevel should be 0 or 1");
    1567               0 :   nsresult rv = NS_OK;
    1568                 :   // ahmed 
    1569                 :   //adjusted for correct numeral shaping  
    1570               0 :   PRUint32 bidiOptions = aPresContext->GetBidi();
    1571               0 :   switch (GET_BIDI_OPTION_NUMERAL(bidiOptions)) {
    1572                 : 
    1573                 :     case IBMBIDI_NUMERAL_HINDI:
    1574               0 :       HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_HINDI);
    1575               0 :       break;
    1576                 : 
    1577                 :     case IBMBIDI_NUMERAL_ARABIC:
    1578               0 :       HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC);
    1579               0 :       break;
    1580                 : 
    1581                 :     case IBMBIDI_NUMERAL_PERSIAN:
    1582               0 :       HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_PERSIAN);
    1583               0 :       break;
    1584                 : 
    1585                 :     case IBMBIDI_NUMERAL_REGULAR:
    1586                 : 
    1587               0 :       switch (aCharType) {
    1588                 : 
    1589                 :         case eCharType_EuropeanNumber:
    1590               0 :           HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC);
    1591               0 :           break;
    1592                 : 
    1593                 :         case eCharType_ArabicNumber:
    1594               0 :           HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_HINDI);
    1595               0 :           break;
    1596                 : 
    1597                 :         default:
    1598               0 :           break;
    1599                 :       }
    1600               0 :       break;
    1601                 : 
    1602                 :     case IBMBIDI_NUMERAL_HINDICONTEXT:
    1603               0 :       if ( ( (GET_BIDI_OPTION_DIRECTION(bidiOptions)==IBMBIDI_TEXTDIRECTION_RTL) && (IS_ARABIC_DIGIT (aText[0])) ) || (eCharType_ArabicNumber == aCharType) )
    1604               0 :         HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_HINDI);
    1605               0 :       else if (eCharType_EuropeanNumber == aCharType)
    1606               0 :         HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC);
    1607               0 :       break;
    1608                 : 
    1609                 :     case IBMBIDI_NUMERAL_PERSIANCONTEXT:
    1610               0 :       if ( ( (GET_BIDI_OPTION_DIRECTION(bidiOptions)==IBMBIDI_TEXTDIRECTION_RTL) && (IS_ARABIC_DIGIT (aText[0])) ) || (eCharType_ArabicNumber == aCharType) )
    1611               0 :         HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_PERSIAN);
    1612               0 :       else if (eCharType_EuropeanNumber == aCharType)
    1613               0 :         HandleNumbers(aText,aTextLength,IBMBIDI_NUMERAL_ARABIC);
    1614               0 :       break;
    1615                 : 
    1616                 :     case IBMBIDI_NUMERAL_NOMINAL:
    1617                 :     default:
    1618               0 :       break;
    1619                 :   }
    1620                 : 
    1621               0 :   StripBidiControlCharacters(aText, aTextLength);
    1622               0 :   return rv;
    1623                 : }
    1624                 : 
    1625                 : void
    1626               0 : nsBidiPresUtils::StripBidiControlCharacters(PRUnichar* aText,
    1627                 :                                             PRInt32&   aTextLength)
    1628                 : {
    1629               0 :   if ( (nsnull == aText) || (aTextLength < 1) ) {
    1630               0 :     return;
    1631                 :   }
    1632                 : 
    1633               0 :   PRInt32 stripLen = 0;
    1634                 : 
    1635               0 :   for (PRInt32 i = 0; i < aTextLength; i++) {
    1636                 :     // XXX: This silently ignores surrogate characters.
    1637                 :     //      As of Unicode 4.0, all Bidi control characters are within the BMP.
    1638               0 :     if (IsBidiControl((PRUint32)aText[i])) {
    1639               0 :       ++stripLen;
    1640                 :     }
    1641                 :     else {
    1642               0 :       aText[i - stripLen] = aText[i];
    1643                 :     }
    1644                 :   }
    1645               0 :   aTextLength -= stripLen;
    1646                 : }
    1647                 :  
    1648                 : #if 0 // XXX: for the future use ???
    1649                 : void
    1650                 : RemoveDiacritics(PRUnichar* aText,
    1651                 :                  PRInt32&   aTextLength)
    1652                 : {
    1653                 :   if (aText && (aTextLength > 0) ) {
    1654                 :     PRInt32 offset = 0;
    1655                 : 
    1656                 :     for (PRInt32 i = 0; i < aTextLength && aText[i]; i++) {
    1657                 :       if (IS_BIDI_DIACRITIC(aText[i]) ) {
    1658                 :         ++offset;
    1659                 :         continue;
    1660                 :       }
    1661                 :       aText[i - offset] = aText[i];
    1662                 :     }
    1663                 :     aTextLength = i - offset;
    1664                 :     aText[aTextLength] = 0;
    1665                 :   }
    1666                 : }
    1667                 : #endif
    1668                 : 
    1669                 : void
    1670               0 : nsBidiPresUtils::CalculateCharType(nsBidi* aBidiEngine,
    1671                 :                                    const PRUnichar* aText,
    1672                 :                                    PRInt32& aOffset,
    1673                 :                                    PRInt32  aCharTypeLimit,
    1674                 :                                    PRInt32& aRunLimit,
    1675                 :                                    PRInt32& aRunLength,
    1676                 :                                    PRInt32& aRunCount,
    1677                 :                                    PRUint8& aCharType,
    1678                 :                                    PRUint8& aPrevCharType)
    1679                 : 
    1680                 : {
    1681               0 :   bool       strongTypeFound = false;
    1682                 :   PRInt32    offset;
    1683                 :   nsCharType charType;
    1684                 : 
    1685               0 :   aCharType = eCharType_OtherNeutral;
    1686                 : 
    1687               0 :   for (offset = aOffset; offset < aCharTypeLimit; offset++) {
    1688                 :     // Make sure we give RTL chartype to all characters that would be classified
    1689                 :     // as Right-To-Left by a bidi platform.
    1690                 :     // (May differ from the UnicodeData, eg we set RTL chartype to some NSMs.)
    1691               0 :     if (IS_HEBREW_CHAR(aText[offset]) ) {
    1692               0 :       charType = eCharType_RightToLeft;
    1693                 :     }
    1694               0 :     else if (IS_ARABIC_ALPHABETIC(aText[offset]) ) {
    1695               0 :       charType = eCharType_RightToLeftArabic;
    1696                 :     }
    1697                 :     else {
    1698               0 :       aBidiEngine->GetCharTypeAt(offset, &charType);
    1699                 :     }
    1700                 : 
    1701               0 :     if (!CHARTYPE_IS_WEAK(charType) ) {
    1702                 : 
    1703               0 :       if (strongTypeFound
    1704                 :           && (charType != aPrevCharType)
    1705                 :           && (CHARTYPE_IS_RTL(charType) || CHARTYPE_IS_RTL(aPrevCharType) ) ) {
    1706                 :         // Stop at this point to ensure uni-directionality of the text
    1707                 :         // (from platform's point of view).
    1708                 :         // Also, don't mix Arabic and Hebrew content (since platform may
    1709                 :         // provide BIDI support to one of them only).
    1710               0 :         aRunLength = offset - aOffset;
    1711               0 :         aRunLimit = offset;
    1712               0 :         ++aRunCount;
    1713               0 :         break;
    1714                 :       }
    1715                 : 
    1716               0 :       if ( (eCharType_RightToLeftArabic == aPrevCharType
    1717                 :             || eCharType_ArabicNumber == aPrevCharType)
    1718                 :           && eCharType_EuropeanNumber == charType) {
    1719               0 :         charType = eCharType_ArabicNumber;
    1720                 :       }
    1721                 : 
    1722                 :       // Set PrevCharType to the last strong type in this frame
    1723                 :       // (for correct numeric shaping)
    1724               0 :       aPrevCharType = charType;
    1725                 : 
    1726               0 :       strongTypeFound = true;
    1727               0 :       aCharType = charType;
    1728                 :     }
    1729                 :   }
    1730               0 :   aOffset = offset;
    1731               0 : }
    1732                 : 
    1733               0 : nsresult nsBidiPresUtils::ProcessText(const PRUnichar*       aText,
    1734                 :                                       PRInt32                aLength,
    1735                 :                                       nsBidiDirection        aBaseDirection,
    1736                 :                                       nsPresContext*         aPresContext,
    1737                 :                                       BidiProcessor&         aprocessor,
    1738                 :                                       Mode                   aMode,
    1739                 :                                       nsBidiPositionResolve* aPosResolve,
    1740                 :                                       PRInt32                aPosResolveCount,
    1741                 :                                       nscoord*               aWidth,
    1742                 :                                       nsBidi*                aBidiEngine)
    1743                 : {
    1744               0 :   NS_ASSERTION((aPosResolve == nsnull) != (aPosResolveCount > 0), "Incorrect aPosResolve / aPosResolveCount arguments");
    1745                 : 
    1746                 :   PRInt32 runCount;
    1747                 : 
    1748               0 :   nsAutoString textBuffer(aText, aLength);
    1749                 : 
    1750               0 :   nsresult rv = aBidiEngine->SetPara(aText, aLength, aBaseDirection, nsnull);
    1751               0 :   if (NS_FAILED(rv))
    1752               0 :     return rv;
    1753                 : 
    1754               0 :   rv = aBidiEngine->CountRuns(&runCount);
    1755               0 :   if (NS_FAILED(rv))
    1756               0 :     return rv;
    1757                 : 
    1758               0 :   nscoord xOffset = 0;
    1759               0 :   nscoord width, xEndRun = 0;
    1760               0 :   nscoord totalWidth = 0;
    1761                 :   PRInt32 i, start, limit, length;
    1762               0 :   PRUint32 visualStart = 0;
    1763                 :   PRUint8 charType;
    1764               0 :   PRUint8 prevType = eCharType_LeftToRight;
    1765                 :   nsBidiLevel level;
    1766                 :       
    1767               0 :   for(int nPosResolve=0; nPosResolve < aPosResolveCount; ++nPosResolve)
    1768                 :   {
    1769               0 :     aPosResolve[nPosResolve].visualIndex = kNotFound;
    1770               0 :     aPosResolve[nPosResolve].visualLeftTwips = kNotFound;
    1771               0 :     aPosResolve[nPosResolve].visualWidth = kNotFound;
    1772                 :   }
    1773                 : 
    1774               0 :   for (i = 0; i < runCount; i++) {
    1775               0 :     rv = aBidiEngine->GetVisualRun(i, &start, &length, &aBaseDirection);
    1776               0 :     if (NS_FAILED(rv))
    1777               0 :       return rv;
    1778                 : 
    1779               0 :     rv = aBidiEngine->GetLogicalRun(start, &limit, &level);
    1780               0 :     if (NS_FAILED(rv))
    1781               0 :       return rv;
    1782                 : 
    1783               0 :     PRInt32 subRunLength = limit - start;
    1784               0 :     PRInt32 lineOffset = start;
    1785               0 :     PRInt32 typeLimit = NS_MIN(limit, aLength);
    1786               0 :     PRInt32 subRunCount = 1;
    1787               0 :     PRInt32 subRunLimit = typeLimit;
    1788                 : 
    1789                 :     /*
    1790                 :      * If |level| is even, i.e. the direction of the run is left-to-right, we
    1791                 :      * render the subruns from left to right and increment the x-coordinate
    1792                 :      * |xOffset| by the width of each subrun after rendering.
    1793                 :      *
    1794                 :      * If |level| is odd, i.e. the direction of the run is right-to-left, we
    1795                 :      * render the subruns from right to left. We begin by incrementing |xOffset| by
    1796                 :      * the width of the whole run, and then decrement it by the width of each
    1797                 :      * subrun before rendering. After rendering all the subruns, we restore the
    1798                 :      * x-coordinate of the end of the run for the start of the next run.
    1799                 :      */
    1800                 : 
    1801               0 :     if (level & 1) {
    1802               0 :       aprocessor.SetText(aText + start, subRunLength, nsBidiDirection(level & 1));
    1803               0 :       width = aprocessor.GetWidth();
    1804               0 :       xOffset += width;
    1805               0 :       xEndRun = xOffset;
    1806                 :     }
    1807                 : 
    1808               0 :     while (subRunCount > 0) {
    1809                 :       // CalculateCharType can increment subRunCount if the run
    1810                 :       // contains mixed character types
    1811               0 :       CalculateCharType(aBidiEngine, aText, lineOffset, typeLimit, subRunLimit, subRunLength, subRunCount, charType, prevType);
    1812                 :       
    1813               0 :       nsAutoString runVisualText;
    1814               0 :       runVisualText.Assign(aText + start, subRunLength);
    1815               0 :       if (PRInt32(runVisualText.Length()) < subRunLength)
    1816               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1817                 :       FormatUnicodeText(aPresContext, runVisualText.BeginWriting(), subRunLength,
    1818               0 :                         (nsCharType)charType, level & 1);
    1819                 : 
    1820               0 :       aprocessor.SetText(runVisualText.get(), subRunLength, nsBidiDirection(level & 1));
    1821               0 :       width = aprocessor.GetWidth();
    1822               0 :       totalWidth += width;
    1823               0 :       if (level & 1) {
    1824               0 :         xOffset -= width;
    1825                 :       }
    1826               0 :       if (aMode == MODE_DRAW) {
    1827               0 :         aprocessor.DrawText(xOffset, width);
    1828                 :       }
    1829                 : 
    1830                 :       /*
    1831                 :        * The caller may request to calculate the visual position of one
    1832                 :        * or more characters.
    1833                 :        */
    1834               0 :       for(int nPosResolve=0; nPosResolve<aPosResolveCount; ++nPosResolve)
    1835                 :       {
    1836               0 :         nsBidiPositionResolve* posResolve = &aPosResolve[nPosResolve];
    1837                 :         /*
    1838                 :          * Did we already resolve this position's visual metric? If so, skip.
    1839                 :          */
    1840               0 :         if (posResolve->visualLeftTwips != kNotFound)
    1841               0 :            continue;
    1842                 :            
    1843                 :         /*
    1844                 :          * First find out if the logical position is within this run.
    1845                 :          */
    1846               0 :         if (start <= posResolve->logicalIndex &&
    1847                 :             start + subRunLength > posResolve->logicalIndex) {
    1848                 :           /*
    1849                 :            * If this run is only one character long, we have an easy case:
    1850                 :            * the visual position is the x-coord of the start of the run
    1851                 :            * less the x-coord of the start of the whole text.
    1852                 :            */
    1853               0 :           if (subRunLength == 1) {
    1854               0 :             posResolve->visualIndex = visualStart;
    1855               0 :             posResolve->visualLeftTwips = xOffset;
    1856               0 :             posResolve->visualWidth = width;
    1857                 :           }
    1858                 :           /*
    1859                 :            * Otherwise, we need to measure the width of the run's part
    1860                 :            * which is to the visual left of the index.
    1861                 :            * In other words, the run is broken in two, around the logical index,
    1862                 :            * and we measure the part which is visually left.
    1863                 :            * If the run is right-to-left, this part will span from after the index
    1864                 :            * up to the end of the run; if it is left-to-right, this part will span
    1865                 :            * from the start of the run up to (and inclduing) the character before the index.
    1866                 :            */
    1867                 :           else {
    1868                 :             /*
    1869                 :              * Here is a description of how the width of the current character
    1870                 :              * (posResolve->visualWidth) is calculated:
    1871                 :              *
    1872                 :              * LTR (current char: "P"):
    1873                 :              *    S A M P L E          (logical index: 3, visual index: 3)
    1874                 :              *    ^ (visualLeftPart)
    1875                 :              *    ^ (visualRightSide)
    1876                 :              *    visualLeftLength == 3
    1877                 :              *    ^^^^^^ (subWidth)
    1878                 :              *    ^^^^^^^^ (aprocessor.GetWidth() -- with visualRightSide)
    1879                 :              *          ^^ (posResolve->visualWidth)
    1880                 :              *
    1881                 :              * RTL (current char: "M"):
    1882                 :              *    E L P M A S          (logical index: 2, visual index: 3)
    1883                 :              *        ^ (visualLeftPart)
    1884                 :              *          ^ (visualRightSide)
    1885                 :              *    visualLeftLength == 3
    1886                 :              *    ^^^^^^ (subWidth)
    1887                 :              *    ^^^^^^^^ (aprocessor.GetWidth() -- with visualRightSide)
    1888                 :              *          ^^ (posResolve->visualWidth)
    1889                 :              */
    1890                 :             nscoord subWidth;
    1891                 :             // The position in the text where this run's "left part" begins.
    1892                 :             const PRUnichar* visualLeftPart, *visualRightSide;
    1893               0 :             if (level & 1) {
    1894                 :               // One day, son, this could all be replaced with mBidiEngine.GetVisualIndex ...
    1895               0 :               posResolve->visualIndex = visualStart + (subRunLength - (posResolve->logicalIndex + 1 - start));
    1896                 :               // Skipping to the "left part".
    1897               0 :               visualLeftPart = aText + posResolve->logicalIndex + 1;
    1898                 :               // Skipping to the right side of the current character
    1899               0 :               visualRightSide = visualLeftPart - 1;
    1900                 :             }
    1901                 :             else {
    1902               0 :               posResolve->visualIndex = visualStart + (posResolve->logicalIndex - start);
    1903                 :               // Skipping to the "left part".
    1904               0 :               visualLeftPart = aText + start;
    1905                 :               // In LTR mode this is the same as visualLeftPart
    1906               0 :               visualRightSide = visualLeftPart;
    1907                 :             }
    1908                 :             // The delta between the start of the run and the left part's end.
    1909               0 :             PRInt32 visualLeftLength = posResolve->visualIndex - visualStart;
    1910               0 :             aprocessor.SetText(visualLeftPart, visualLeftLength, nsBidiDirection(level & 1));
    1911               0 :             subWidth = aprocessor.GetWidth();
    1912               0 :             aprocessor.SetText(visualRightSide, visualLeftLength + 1, nsBidiDirection(level & 1));
    1913               0 :             posResolve->visualLeftTwips = xOffset + subWidth;
    1914               0 :             posResolve->visualWidth = aprocessor.GetWidth() - subWidth;
    1915                 :           }
    1916                 :         }
    1917                 :       }
    1918                 : 
    1919               0 :       if (!(level & 1)) {
    1920               0 :         xOffset += width;
    1921                 :       }
    1922                 : 
    1923               0 :       --subRunCount;
    1924               0 :       start = lineOffset;
    1925               0 :       subRunLimit = typeLimit;
    1926               0 :       subRunLength = typeLimit - lineOffset;
    1927                 :     } // while
    1928               0 :     if (level & 1) {
    1929               0 :       xOffset = xEndRun;
    1930                 :     }
    1931                 :     
    1932               0 :     visualStart += length;
    1933                 :   } // for
    1934                 : 
    1935               0 :   if (aWidth) {
    1936               0 :     *aWidth = totalWidth;
    1937                 :   }
    1938               0 :   return NS_OK;
    1939                 : }
    1940                 : 
    1941                 : class NS_STACK_CLASS nsIRenderingContextBidiProcessor : public nsBidiPresUtils::BidiProcessor {
    1942                 : public:
    1943               0 :   nsIRenderingContextBidiProcessor(nsRenderingContext* aCtx,
    1944                 :                                    nsRenderingContext* aTextRunConstructionContext,
    1945                 :                                    const nsPoint&       aPt)
    1946               0 :     : mCtx(aCtx), mTextRunConstructionContext(aTextRunConstructionContext), mPt(aPt) { }
    1947                 : 
    1948               0 :   ~nsIRenderingContextBidiProcessor()
    1949               0 :   {
    1950               0 :     mCtx->SetTextRunRTL(false);
    1951               0 :   }
    1952                 : 
    1953               0 :   virtual void SetText(const PRUnichar* aText,
    1954                 :                        PRInt32          aLength,
    1955                 :                        nsBidiDirection  aDirection)
    1956                 :   {
    1957               0 :     mTextRunConstructionContext->SetTextRunRTL(aDirection==NSBIDI_RTL);
    1958               0 :     mText = aText;
    1959               0 :     mLength = aLength;
    1960               0 :   }
    1961                 : 
    1962               0 :   virtual nscoord GetWidth()
    1963                 :   {
    1964               0 :     return mTextRunConstructionContext->GetWidth(mText, mLength);
    1965                 :   }
    1966                 : 
    1967               0 :   virtual void DrawText(nscoord aXOffset,
    1968                 :                         nscoord)
    1969                 :   {
    1970                 :     mCtx->FontMetrics()->DrawString(mText, mLength, mPt.x + aXOffset, mPt.y,
    1971               0 :                                     mCtx, mTextRunConstructionContext);
    1972               0 :   }
    1973                 : 
    1974                 : private:
    1975                 :   nsRenderingContext* mCtx;
    1976                 :   nsRenderingContext* mTextRunConstructionContext;
    1977                 :   nsPoint mPt;
    1978                 :   const PRUnichar* mText;
    1979                 :   PRInt32 mLength;
    1980                 :   nsBidiDirection mDirection;
    1981                 : };
    1982                 : 
    1983               0 : nsresult nsBidiPresUtils::ProcessTextForRenderingContext(const PRUnichar*       aText,
    1984                 :                                                          PRInt32                aLength,
    1985                 :                                                          nsBidiDirection        aBaseDirection,
    1986                 :                                                          nsPresContext*         aPresContext,
    1987                 :                                                          nsRenderingContext&   aRenderingContext,
    1988                 :                                                          nsRenderingContext&   aTextRunConstructionContext,
    1989                 :                                                          Mode                   aMode,
    1990                 :                                                          nscoord                aX,
    1991                 :                                                          nscoord                aY,
    1992                 :                                                          nsBidiPositionResolve* aPosResolve,
    1993                 :                                                          PRInt32                aPosResolveCount,
    1994                 :                                                          nscoord*               aWidth)
    1995                 : {
    1996               0 :   nsIRenderingContextBidiProcessor processor(&aRenderingContext, &aTextRunConstructionContext, nsPoint(aX, aY));
    1997               0 :   nsBidi bidiEngine;
    1998                 :   return ProcessText(aText, aLength, aBaseDirection, aPresContext, processor,
    1999               0 :                      aMode, aPosResolve, aPosResolveCount, aWidth, &bidiEngine);
    2000                 : }
    2001                 : 
    2002                 : /* static */
    2003               0 : void nsBidiPresUtils::WriteReverse(const PRUnichar* aSrc,
    2004                 :                                    PRUint32 aSrcLength,
    2005                 :                                    PRUnichar* aDest)
    2006                 : {
    2007               0 :   PRUnichar* dest = aDest + aSrcLength;
    2008               0 :   mozilla::unicode::ClusterIterator iter(aSrc, aSrcLength);
    2009                 : 
    2010               0 :   while (!iter.AtEnd()) {
    2011               0 :     iter.Next();
    2012               0 :     for (const PRUnichar *cp = iter; cp > aSrc; ) {
    2013                 :       // Here we rely on the fact that there are no non-BMP mirrored pairs
    2014                 :       // currently in Unicode, so we don't need to look for surrogates
    2015               0 :       *--dest = mozilla::unicode::GetMirroredChar(*--cp);
    2016                 :     }
    2017               0 :     aSrc = iter;
    2018                 :   }
    2019                 : 
    2020               0 :   NS_ASSERTION(dest == aDest, "Whole string not copied");
    2021               0 : }
    2022                 : 
    2023                 : /* static */
    2024               0 : bool nsBidiPresUtils::WriteLogicalToVisual(const PRUnichar* aSrc,
    2025                 :                                            PRUint32 aSrcLength,
    2026                 :                                            PRUnichar* aDest,
    2027                 :                                            nsBidiLevel aBaseDirection,
    2028                 :                                            nsBidi* aBidiEngine)
    2029                 : {
    2030               0 :   const PRUnichar* src = aSrc;
    2031               0 :   nsresult rv = aBidiEngine->SetPara(src, aSrcLength, aBaseDirection, nsnull);
    2032               0 :   if (NS_FAILED(rv)) {
    2033               0 :     return false;
    2034                 :   }
    2035                 : 
    2036                 :   nsBidiDirection dir;
    2037               0 :   rv = aBidiEngine->GetDirection(&dir);
    2038                 :   // NSBIDI_LTR returned from GetDirection means the whole text is LTR
    2039               0 :   if (NS_FAILED(rv) || dir == NSBIDI_LTR) {
    2040               0 :     return false;
    2041                 :   }
    2042                 : 
    2043                 :   PRInt32 runCount;
    2044               0 :   rv = aBidiEngine->CountRuns(&runCount);
    2045               0 :   if (NS_FAILED(rv)) {
    2046               0 :     return false;
    2047                 :   }
    2048                 : 
    2049                 :   PRInt32 runIndex, start, length;
    2050               0 :   PRUnichar* dest = aDest;
    2051                 : 
    2052               0 :   for (runIndex = 0; runIndex < runCount; ++runIndex) {
    2053               0 :     rv = aBidiEngine->GetVisualRun(runIndex, &start, &length, &dir);
    2054               0 :     if (NS_FAILED(rv)) {
    2055               0 :       return false;
    2056                 :     }
    2057                 : 
    2058               0 :     src = aSrc + start;
    2059                 : 
    2060               0 :     if (dir == NSBIDI_RTL) {
    2061               0 :       WriteReverse(src, length, dest);
    2062               0 :       dest += length;
    2063                 :     } else {
    2064               0 :       do {
    2065               0 :         NS_ASSERTION(src >= aSrc && src < aSrc + aSrcLength,
    2066                 :                      "logical index out of range");
    2067               0 :         NS_ASSERTION(dest < aDest + aSrcLength, "visual index out of range");
    2068               0 :         *(dest++) = *(src++);
    2069                 :       } while (--length);
    2070                 :     }
    2071                 :   }
    2072                 : 
    2073               0 :   NS_ASSERTION(dest - aDest == aSrcLength, "whole string not copied");
    2074               0 :   return true;
    2075                 : }
    2076                 : 
    2077               0 : void nsBidiPresUtils::CopyLogicalToVisual(const nsAString& aSource,
    2078                 :                                           nsAString& aDest,
    2079                 :                                           nsBidiLevel aBaseDirection,
    2080                 :                                           bool aOverride)
    2081                 : {
    2082               0 :   aDest.SetLength(0);
    2083               0 :   PRUint32 srcLength = aSource.Length();
    2084               0 :   if (srcLength == 0)
    2085               0 :     return;
    2086               0 :   if (!EnsureStringLength(aDest, srcLength)) {
    2087               0 :     return;
    2088                 :   }
    2089               0 :   nsAString::const_iterator fromBegin, fromEnd;
    2090               0 :   nsAString::iterator toBegin;
    2091               0 :   aSource.BeginReading(fromBegin);
    2092               0 :   aSource.EndReading(fromEnd);
    2093               0 :   aDest.BeginWriting(toBegin);
    2094                 : 
    2095               0 :   if (aOverride) {
    2096               0 :     if (aBaseDirection == NSBIDI_RTL) {
    2097                 :       // no need to use the converter -- just copy the string in reverse order
    2098               0 :       WriteReverse(fromBegin.get(), srcLength, toBegin.get());
    2099                 :     } else {
    2100                 :       // if aOverride && aBaseDirection == NSBIDI_LTR, fall through to the
    2101                 :       // simple copy
    2102               0 :       aDest.SetLength(0);
    2103                 :     }
    2104                 :   } else {
    2105               0 :     nsBidi bidiEngine;
    2106               0 :     if (!WriteLogicalToVisual(fromBegin.get(), srcLength, toBegin.get(),
    2107               0 :                              aBaseDirection, &bidiEngine)) {
    2108               0 :       aDest.SetLength(0);
    2109                 :     }
    2110                 :   }
    2111                 : 
    2112               0 :   if (aDest.IsEmpty()) {
    2113                 :     // Either there was an error or the source is unidirectional
    2114                 :     //  left-to-right. In either case, just copy source to dest.
    2115               0 :     CopyUnicodeTo(aSource.BeginReading(fromBegin), aSource.EndReading(fromEnd),
    2116               0 :                   aDest);
    2117                 :   }
    2118                 : }
    2119                 : #endif // IBMBIDI

Generated by: LCOV version 1.7