|
|
|
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) |