Attachment #537515: Patch part 2.5: cache the lines for each frame while building mLogicalArray for bug #263359

View | Details | Raw Unified | Return to bug 263359
Collapse All | Expand All

(-)a/layout/base/nsBidiPresUtils.cpp (-24 / +18 lines)
Line     Link Here 
 Lines 310-342   AdvanceLineIteratorToFrame(nsIFrame* aFr Link Here 
310
 *  We may also need to call RemoveBidiContinuation() to convert frames created
310
 *  We may also need to call RemoveBidiContinuation() to convert frames created
311
 *  by EnsureBidiContinuation() in previous reflows into fluid continuations.
311
 *  by EnsureBidiContinuation() in previous reflows into fluid continuations.
312
 */
312
 */
313
nsresult
313
nsresult
314
nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
314
nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
315
{
315
{
316
  mLogicalFrames.Clear();
316
  mLogicalFrames.Clear();
317
  mContentToFrameIndex.Clear();
317
  mContentToFrameIndex.Clear();
318
  mLinePerFrame.Clear();
318
  mBuffer.SetLength(0);
319
  mBuffer.SetLength(0);
319
  
320
  
320
  nsPresContext *presContext = aBlockFrame->PresContext();
321
  nsPresContext *presContext = aBlockFrame->PresContext();
321
322
322
  const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
323
  const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
323
324
324
  mParaLevel = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
325
  mParaLevel = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
325
                NSBIDI_RTL : NSBIDI_LTR;
326
                NSBIDI_RTL : NSBIDI_LTR;
326
327
327
  mLineIter = new nsBlockInFlowLineIterator(aBlockFrame,
328
                                            aBlockFrame->begin_lines(),
329
                                            PR_FALSE);
330
  if (mLineIter->GetLine() == aBlockFrame->end_lines()) {
331
    // Advance to first valid line (might be in a next-continuation)
332
    mLineIter->Next();
333
  }
334
335
  mIsVisual = presContext->IsVisualMode();
328
  mIsVisual = presContext->IsVisualMode();
336
  if (mIsVisual) {
329
  if (mIsVisual) {
337
    /**
330
    /**
338
     * Drill up in content to detect whether this is an element that needs to be
331
     * Drill up in content to detect whether this is an element that needs to be
339
     * rendered with logical order even on visual pages.
332
     * rendered with logical order even on visual pages.
340
     *
333
     *
341
     * We always use logical order on form controls, firstly so that text entry
334
     * We always use logical order on form controls, firstly so that text entry
342
     * will be in logical order, but also because visual pages were written with
335
     * will be in logical order, but also because visual pages were written with
 Lines 352-394   nsBidiPresUtils::Resolve(nsBlockFrame* a Link Here 
352
         content = content->GetParent()) {
345
         content = content->GetParent()) {
353
      if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
346
      if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
354
          content->IsXUL()) {
347
          content->IsXUL()) {
355
        mIsVisual = PR_FALSE;
348
        mIsVisual = PR_FALSE;
356
        break;
349
        break;
357
      }
350
      }
358
    }
351
    }
359
  }
352
  }
360
  mPrevFrame = nsnull;
361
353
362
  // handle bidi-override being set on the block itself before calling
354
  // handle bidi-override being set on the block itself before calling
363
  // InitLogicalArray.
355
  // InitLogicalArray.
364
  const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
356
  const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
365
  PRUnichar ch = 0;
357
  PRUnichar ch = 0;
366
  if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
358
  if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
367
    if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
359
    if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
368
      ch = kRLO;
360
      ch = kRLO;
369
    }
361
    }
370
    else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
362
    else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
371
      ch = kLRO;
363
      ch = kLRO;
372
    }
364
    }
373
    if (ch != 0) {
365
    if (ch != 0) {
374
      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
366
      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
367
      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
375
      mBuffer.Append(ch);
368
      mBuffer.Append(ch);
376
    }
369
    }
377
  }
370
  }
378
  mPrevContent = nsnull;
371
  mPrevContent = nsnull;
379
  for (nsBlockFrame* block = aBlockFrame; block;
372
  for (nsBlockFrame* block = aBlockFrame; block;
380
       block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
373
       block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
381
    block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
374
    block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
382
    InitLogicalArray(block->GetFirstChild(nsnull));
375
    nsBlockInFlowLineIterator lineIter(block, block->begin_lines(), PR_FALSE);
376
    mPrevFrame = nsnull;
377
    InitLogicalArray(&lineIter, block->GetFirstChild(nsnull));
383
  }
378
  }
384
379
385
  if (ch != 0) {
380
  if (ch != 0) {
386
    mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
381
    mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
382
    mLinePerFrame.AppendElement((nsLineBox*)nsnull);
387
    mBuffer.Append(kPDF);
383
    mBuffer.Append(kPDF);
388
  }
384
  }
389
385
390
  // XXX: TODO: Handle preformatted text ('\n')
386
  // XXX: TODO: Handle preformatted text ('\n')
391
  mBuffer.ReplaceChar("\t\r\n", kSpace);
387
  mBuffer.ReplaceChar("\t\r\n", kSpace);
392
  ResolveParagraph(aBlockFrame);
388
  ResolveParagraph(aBlockFrame);
393
  return mSuccess;
389
  return mSuccess;
394
}
390
}
 Lines 424-440   nsBidiPresUtils::ResolveParagraph(nsBloc Link Here 
424
  PRInt32     frameCount     = mLogicalFrames.Length();
420
  PRInt32     frameCount     = mLogicalFrames.Length();
425
  PRInt32     contentOffset  = 0;   // offset of current frame in its content node
421
  PRInt32     contentOffset  = 0;   // offset of current frame in its content node
426
  PRBool      isTextFrame    = PR_FALSE;
422
  PRBool      isTextFrame    = PR_FALSE;
427
  nsIFrame*   frame = nsnull;
423
  nsIFrame*   frame = nsnull;
428
  nsIContent* content = nsnull;
424
  nsIContent* content = nsnull;
429
  PRInt32     contentTextLength;
425
  PRInt32     contentTextLength;
430
426
431
  FramePropertyTable *propTable = presContext->PropertyTable();
427
  FramePropertyTable *propTable = presContext->PropertyTable();
432
  PRBool lineNeedsUpdate = PR_FALSE;
428
  nsLineBox* currentLine = nsnull;
433
  
429
  
434
#ifdef DEBUG
430
#ifdef DEBUG
435
#ifdef NOISY_BIDI
431
#ifdef NOISY_BIDI
436
  printf("Before Resolve(), aBlockFrame=0x%p, mBuffer='%s', frameCount=%d\n",
432
  printf("Before Resolve(), aBlockFrame=0x%p, mBuffer='%s', frameCount=%d\n",
437
         (void*)aBlockFrame, NS_ConvertUTF16toUTF8(mBuffer).get(), frameCount);
433
         (void*)aBlockFrame, NS_ConvertUTF16toUTF8(mBuffer).get(), frameCount);
438
#ifdef REALLY_NOISY_BIDI
434
#ifdef REALLY_NOISY_BIDI
439
  printf(" block frame tree=:\n");
435
  printf(" block frame tree=:\n");
440
  aBlockFrame->List(stdout, 0);
436
  aBlockFrame->List(stdout, 0);
 Lines 444-470   nsBidiPresUtils::ResolveParagraph(nsBloc Link Here 
444
440
445
  for (; ;) {
441
  for (; ;) {
446
    if (fragmentLength <= 0) {
442
    if (fragmentLength <= 0) {
447
      // Get the next frame from mLogicalFrames
443
      // Get the next frame from mLogicalFrames
448
      if (++frameIndex >= frameCount) {
444
      if (++frameIndex >= frameCount) {
449
        break;
445
        break;
450
      }
446
      }
451
      frame = mLogicalFrames[frameIndex];
447
      frame = mLogicalFrames[frameIndex];
452
      lineNeedsUpdate = PR_TRUE;
453
      if (frame == NS_BIDI_CONTROL_FRAME ||
448
      if (frame == NS_BIDI_CONTROL_FRAME ||
454
          nsGkAtoms::textFrame != frame->GetType()) {
449
          nsGkAtoms::textFrame != frame->GetType()) {
455
        /*
450
        /*
456
         * Any non-text frame corresponds to a single character in the text buffer
451
         * Any non-text frame corresponds to a single character in the text buffer
457
         * (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
452
         * (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
458
         */
453
         */
459
        isTextFrame = PR_FALSE;
454
        isTextFrame = PR_FALSE;
460
        fragmentLength = 1;
455
        fragmentLength = 1;
461
      }
456
      }
462
      else {
457
      else {
458
        currentLine = mLinePerFrame[frameIndex];
463
        content = frame->GetContent();
459
        content = frame->GetContent();
464
        if (!content) {
460
        if (!content) {
465
          mSuccess = NS_OK;
461
          mSuccess = NS_OK;
466
          break;
462
          break;
467
        }
463
        }
468
        contentTextLength = content->TextLength();
464
        contentTextLength = content->TextLength();
469
        if (contentTextLength == 0) {
465
        if (contentTextLength == 0) {
470
          frame->AdjustOffsetsForBidi(0, 0);
466
          frame->AdjustOffsetsForBidi(0, 0);
 Lines 512-532   nsBidiPresUtils::ResolveParagraph(nsBloc Link Here 
512
      propTable->Set(frame, nsIFrame::BaseLevelProperty(),
508
      propTable->Set(frame, nsIFrame::BaseLevelProperty(),
513
                     NS_INT32_TO_PTR(mParaLevel));
509
                     NS_INT32_TO_PTR(mParaLevel));
514
      if (isTextFrame) {
510
      if (isTextFrame) {
515
        if ( (runLength > 0) && (runLength < fragmentLength) ) {
511
        if ( (runLength > 0) && (runLength < fragmentLength) ) {
516
          /*
512
          /*
517
           * The text in this frame continues beyond the end of this directional run.
513
           * The text in this frame continues beyond the end of this directional run.
518
           * Create a non-fluid continuation frame for the next directional run.
514
           * Create a non-fluid continuation frame for the next directional run.
519
           */
515
           */
520
          if (lineNeedsUpdate) {
516
          currentLine->MarkDirty();
521
            AdvanceLineIteratorToFrame(frame, mLineIter, mPrevFrame);
522
            lineNeedsUpdate = PR_FALSE;
523
          }
524
          mLineIter->GetLine()->MarkDirty();
525
          nsIFrame* nextBidi;
517
          nsIFrame* nextBidi;
526
          PRInt32 runEnd = contentOffset + runLength;
518
          PRInt32 runEnd = contentOffset + runLength;
527
          EnsureBidiContinuation(frame, &nextBidi, frameIndex,
519
          EnsureBidiContinuation(frame, &nextBidi, frameIndex,
528
                                 contentOffset,
520
                                 contentOffset,
529
                                 runEnd);
521
                                 runEnd);
530
          if (NS_FAILED(mSuccess)) {
522
          if (NS_FAILED(mSuccess)) {
531
            break;
523
            break;
532
          }
524
          }
 Lines 566-586   nsBidiPresUtils::ResolveParagraph(nsBloc Link Here 
566
             */
558
             */
567
            nsIFrame* next = frame->GetNextInFlow();
559
            nsIFrame* next = frame->GetNextInFlow();
568
            if (next) {
560
            if (next) {
569
              frame->SetNextContinuation(next);
561
              frame->SetNextContinuation(next);
570
              next->SetPrevContinuation(frame);
562
              next->SetPrevContinuation(frame);
571
            }
563
            }
572
          }
564
          }
573
          frame->AdjustOffsetsForBidi(contentOffset, contentOffset + fragmentLength);
565
          frame->AdjustOffsetsForBidi(contentOffset, contentOffset + fragmentLength);
574
          if (lineNeedsUpdate) {
566
          currentLine->MarkDirty();
575
            AdvanceLineIteratorToFrame(frame, mLineIter, mPrevFrame);
576
            lineNeedsUpdate = PR_FALSE;
577
          }
578
          mLineIter->GetLine()->MarkDirty();
579
        }
567
        }
580
      } // isTextFrame
568
      } // isTextFrame
581
      else {
569
      else {
582
        ++lineOffset;
570
        ++lineOffset;
583
      }
571
      }
584
    } // not bidi control frame
572
    } // not bidi control frame
585
    PRInt32 temp = runLength;
573
    PRInt32 temp = runLength;
586
    runLength -= fragmentLength;
574
    runLength -= fragmentLength;
 Lines 637-653   nsBidiPresUtils::ResolveParagraph(nsBloc Link Here 
637
// Should this frame be treated as a leaf (e.g. when building mLogicalFrames)?
625
// Should this frame be treated as a leaf (e.g. when building mLogicalFrames)?
638
PRBool IsBidiLeaf(nsIFrame* aFrame) {
626
PRBool IsBidiLeaf(nsIFrame* aFrame) {
639
  nsIFrame* kid = aFrame->GetFirstChild(nsnull);
627
  nsIFrame* kid = aFrame->GetFirstChild(nsnull);
640
  return !kid
628
  return !kid
641
    || !aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer);
629
    || !aFrame->IsFrameOfType(nsIFrame::eBidiInlineContainer);
642
}
630
}
643
631
644
void
632
void
645
nsBidiPresUtils::InitLogicalArray(nsIFrame*    aCurrentFrame)
633
nsBidiPresUtils::InitLogicalArray(nsBlockInFlowLineIterator* aLineIter,
634
                                  nsIFrame*    aCurrentFrame)
646
{
635
{
647
  if (!aCurrentFrame)
636
  if (!aCurrentFrame)
648
    return;
637
    return;
649
638
650
  for (nsIFrame* childFrame = aCurrentFrame; childFrame;
639
  for (nsIFrame* childFrame = aCurrentFrame; childFrame;
651
       childFrame = childFrame->GetNextSibling()) {
640
       childFrame = childFrame->GetNextSibling()) {
652
641
653
    // If the real frame for a placeholder is a first letter frame, we need to
642
    // If the real frame for a placeholder is a first letter frame, we need to
 Lines 686-717   nsBidiPresUtils::InitLogicalArray(nsIFra Link Here 
686
          }
675
          }
687
          break;
676
          break;
688
      }
677
      }
689
678
690
      // Add a dummy frame pointer representing a bidi control code before the
679
      // Add a dummy frame pointer representing a bidi control code before the
691
      // first frame of an element specifying embedding or override
680
      // first frame of an element specifying embedding or override
692
      if (ch != 0 && !frame->GetPrevContinuation()) {
681
      if (ch != 0 && !frame->GetPrevContinuation()) {
693
        mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
682
        mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
683
        mLinePerFrame.AppendElement((nsLineBox*)nsnull);
694
        mBuffer.Append(ch);
684
        mBuffer.Append(ch);
695
      }
685
      }
696
    }
686
    }
697
687
698
    if (IsBidiLeaf(frame)) {
688
    if (IsBidiLeaf(frame)) {
699
      /* Bidi leaf frame: add the frame to the mLogicalFrames array,
689
      /* Bidi leaf frame: add the frame to the mLogicalFrames array,
700
       * and add its index to the mContentToFrameIndex hashtable. This
690
       * and add its index to the mContentToFrameIndex hashtable. This
701
       * will be used in RemoveBidiContinuation() to identify the last
691
       * will be used in RemoveBidiContinuation() to identify the last
702
       * frame in the array with a given content.
692
       * frame in the array with a given content.
703
       */
693
       */
704
      nsIContent* content = frame->GetContent();
694
      nsIContent* content = frame->GetContent();
705
      if (content) {
695
      if (content) {
706
        mContentToFrameIndex.Put(content, mLogicalFrames.Length());
696
        mContentToFrameIndex.Put(content, mLogicalFrames.Length());
707
      }
697
      }
708
      mLogicalFrames.AppendElement(frame);
698
      mLogicalFrames.AppendElement(frame);
709
699
700
      AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
701
      mLinePerFrame.AppendElement(aLineIter->GetLine().get());
702
710
      // Append the content of the frame to the paragraph buffer
703
      // Append the content of the frame to the paragraph buffer
711
      nsIAtom* frameType = frame->GetType();
704
      nsIAtom* frameType = frame->GetType();
712
      if (nsGkAtoms::textFrame == frameType) {
705
      if (nsGkAtoms::textFrame == frameType) {
713
        if (content != mPrevContent) {
706
        if (content != mPrevContent) {
714
          mPrevContent = content;
707
          mPrevContent = content;
715
          content->AppendTextTo(mBuffer);
708
          content->AppendTextTo(mBuffer);
716
        }
709
        }
717
      } else if (nsGkAtoms::brFrame == frameType) {
710
      } else if (nsGkAtoms::brFrame == frameType) {
 Lines 721-744   nsBidiPresUtils::InitLogicalArray(nsIFra Link Here 
721
        // other frame type -- see the Unicode Bidi Algorithm:
714
        // other frame type -- see the Unicode Bidi Algorithm:
722
        // "...inline objects (such as graphics) are treated as if they are ...
715
        // "...inline objects (such as graphics) are treated as if they are ...
723
        // U+FFFC"
716
        // U+FFFC"
724
        mBuffer.Append(kObjectSubstitute);
717
        mBuffer.Append(kObjectSubstitute);
725
      }
718
      }
726
    }
719
    }
727
    else {
720
    else {
728
      nsIFrame* kid = frame->GetFirstChild(nsnull);
721
      nsIFrame* kid = frame->GetFirstChild(nsnull);
729
      InitLogicalArray(kid);
722
      InitLogicalArray(aLineIter, kid);
730
    }
723
    }
731
724
732
    // If the element is attributed by dir, indicate direction pop (add PDF frame)
725
    // If the element is attributed by dir, indicate direction pop (add PDF frame)
733
    if (ch != 0 && !frame->GetNextContinuation()) {
726
    if (ch != 0 && !frame->GetNextContinuation()) {
734
      // Add a dummy frame pointer representing a bidi control code after the
727
      // Add a dummy frame pointer representing a bidi control code after the
735
      // last frame of an element specifying embedding or override
728
      // last frame of an element specifying embedding or override
736
      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
729
      mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
730
      mLinePerFrame.AppendElement((nsLineBox*)nsnull);
737
      mBuffer.Append(kPDF);
731
      mBuffer.Append(kPDF);
738
    }
732
    }
739
  } // for
733
  } // for
740
}
734
}
741
735
742
void
736
void
743
nsBidiPresUtils::ReorderFrames(nsIFrame*            aFirstFrameOnLine,
737
nsBidiPresUtils::ReorderFrames(nsIFrame*            aFirstFrameOnLine,
744
                               PRInt32              aNumFramesOnLine)
738
                               PRInt32              aNumFramesOnLine)
(-)a/layout/base/nsBidiPresUtils.h (-2 / +3 lines)
Line     Link Here 
 Lines 362-378   private: Link Here 
362
                                          PRInt32                aPosResolveCount,
362
                                          PRInt32                aPosResolveCount,
363
                                          nscoord*               aWidth /* may be null */);
363
                                          nscoord*               aWidth /* may be null */);
364
364
365
  /**
365
  /**
366
   * Set up an array of the frames after splitting frames so that each frame has
366
   * Set up an array of the frames after splitting frames so that each frame has
367
   * consistent directionality. At this point the frames are still in logical
367
   * consistent directionality. At this point the frames are still in logical
368
   * order
368
   * order
369
   */
369
   */
370
  void InitLogicalArray(nsIFrame* aCurrentFrame);
370
  void InitLogicalArray(nsBlockInFlowLineIterator* aLineIter,
371
                        nsIFrame* aCurrentFrame);
371
372
372
  /**
373
  /**
373
   * Initialize the logically-ordered array of frames
374
   * Initialize the logically-ordered array of frames
374
   * using the top-level frames of a single line
375
   * using the top-level frames of a single line
375
   */
376
   */
376
  void InitLogicalArrayFromLine(nsIFrame* aFirstFrameOnLine,
377
  void InitLogicalArrayFromLine(nsIFrame* aFirstFrameOnLine,
377
                                PRInt32   aNumFramesOnLine);
378
                                PRInt32   aNumFramesOnLine);
378
379
 Lines 504-529   private: Link Here 
504
                                     nsBidi* aBidiEngine);
505
                                     nsBidi* aBidiEngine);
505
506
506
 static void WriteReverse(const PRUnichar* aSrc,
507
 static void WriteReverse(const PRUnichar* aSrc,
507
                          PRUint32 aSrcLength,
508
                          PRUint32 aSrcLength,
508
                          PRUnichar* aDest);
509
                          PRUnichar* aDest);
509
510
510
  nsAutoString    mBuffer;
511
  nsAutoString    mBuffer;
511
  nsTArray<nsIFrame*> mLogicalFrames;
512
  nsTArray<nsIFrame*> mLogicalFrames;
513
  nsTArray<nsLineBox*> mLinePerFrame;
512
  nsTArray<nsIFrame*> mVisualFrames;
514
  nsTArray<nsIFrame*> mVisualFrames;
513
  nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
515
  nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
514
  PRInt32         mArraySize;
516
  PRInt32         mArraySize;
515
  PRInt32*        mIndexMap;
517
  PRInt32*        mIndexMap;
516
  PRUint8*        mLevels;
518
  PRUint8*        mLevels;
517
  nsresult        mSuccess;
519
  nsresult        mSuccess;
518
  PRPackedBool    mIsVisual;
520
  PRPackedBool    mIsVisual;
519
  nsBidiLevel     mParaLevel;
521
  nsBidiLevel     mParaLevel;
520
  nsIFrame*       mPrevFrame;
522
  nsIFrame*       mPrevFrame;
521
  nsIContent*     mPrevContent;
523
  nsIContent*     mPrevContent;
522
524
523
  nsAutoPtr<nsBlockInFlowLineIterator> mLineIter;
524
  nsBidi*         mBidiEngine;
525
  nsBidi*         mBidiEngine;
525
};
526
};
526
527
527
#endif /* nsBidiPresUtils_h___ */
528
#endif /* nsBidiPresUtils_h___ */
528
529
529
#endif // IBMBIDI
530
#endif // IBMBIDI

Return to bug 263359