Bug 1281099 part 2 - Merge three bidi frame properties into one. r?jfkthame
MozReview-Commit-ID: CEJhM3c21KO
--- a/layout/base/nsBidi.h
+++ b/layout/base/nsBidi.h
@@ -404,16 +404,25 @@ struct LevState {
PImpTab pImpTab; /* level table pointer */
PImpAct pImpAct; /* action map array */
int32_t startON; /* start of ON sequence */
int32_t state; /* current state */
int32_t runStart; /* start position of the run */
nsBidiLevel runLevel; /* run level before implicit solving */
};
+namespace mozilla {
+struct FrameBidiData
+{
+ nsBidiLevel baseLevel;
+ nsBidiLevel embeddingLevel;
+ uint8_t paragraphDepth;
+};
+} // namespace mozilla
+
/**
* This class holds information about a paragraph of text
* with Bidi-algorithm-related details, or about one line of
* such a paragraph.<p>
* Reordering can be done on a line, or on a paragraph which is
* then interpreted as one single line.<p>
*
* On construction, the class is initially empty. It is assigned
@@ -653,33 +662,36 @@ public:
*
* @param aOptions A bit set of options for the reordering that control
* how the reordered text is written.
*
* @param aDestSize will receive the number of characters that were written to <code>aDest</code>.
*/
nsresult WriteReverse(const char16_t *aSrc, int32_t aSrcLength, char16_t *aDest, uint16_t aOptions, int32_t *aDestSize);
- NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BaseLevelProperty, nsBidiLevel)
- NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(EmbeddingLevelProperty, nsBidiLevel)
- NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ParagraphDepthProperty, uint8_t)
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
+
+ static mozilla::FrameBidiData GetBidiData(nsIFrame* aFrame)
+ {
+ return aFrame->Properties().Get(BidiDataProperty());
+ }
static nsBidiLevel GetBaseLevel(nsIFrame* aFrame)
{
- return aFrame->Properties().Get(BaseLevelProperty());
+ return GetBidiData(aFrame).baseLevel;
}
static nsBidiLevel GetEmbeddingLevel(nsIFrame* aFrame)
{
- return aFrame->Properties().Get(EmbeddingLevelProperty());
+ return GetBidiData(aFrame).embeddingLevel;
}
static uint8_t GetParagraphDepth(nsIFrame* aFrame)
{
- return aFrame->Properties().Get(ParagraphDepthProperty());
+ return GetBidiData(aFrame).paragraphDepth;
}
protected:
friend class nsBidiPresUtils;
class BracketData {
public:
explicit BracketData(const nsBidi* aBidi);
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -739,26 +739,27 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
aBpd->mParagraphDepth == 0 && aBpd->GetDirection() == NSBIDI_LTR &&
aBpd->GetParaLevel() == 0) {
// We have a single left-to-right frame in a left-to-right paragraph,
// without bidi isolation from the surrounding text.
// Make sure that the embedding level and base level frame properties aren't
// set (because if they are this frame used to have some other direction,
// so we can't do this optimization), and we're done.
nsIFrame* frame = aBpd->FrameAt(0);
- if (frame != NS_BIDI_CONTROL_FRAME &&
- !frame->Properties().Get(nsBidi::EmbeddingLevelProperty()) &&
- !frame->Properties().Get(nsBidi::BaseLevelProperty())) {
+ if (frame != NS_BIDI_CONTROL_FRAME) {
+ FrameBidiData bidiData = nsBidi::GetBidiData(frame);
+ if (!bidiData.embeddingLevel && !bidiData.baseLevel) {
#ifdef DEBUG
#ifdef NOISY_BIDI
- printf("early return for single direction frame %p\n", (void*)frame);
+ printf("early return for single direction frame %p\n", (void*)frame);
#endif
#endif
- frame->AddStateBits(NS_FRAME_IS_BIDI);
- return NS_OK;
+ frame->AddStateBits(NS_FRAME_IS_BIDI);
+ return NS_OK;
+ }
}
}
nsIFrame* firstFrame = nullptr;
nsIFrame* lastFrame = nullptr;
for (; ;) {
if (fragmentLength <= 0) {
@@ -787,22 +788,21 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
rv = NS_OK;
break;
}
contentTextLength = content->TextLength();
if (contentTextLength == 0) {
frame->AdjustOffsetsForBidi(0, 0);
// Set the base level and embedding level of the current run even
// on an empty frame. Otherwise frame reordering will not be correct.
- propTable->Set(frame, nsBidi::EmbeddingLevelProperty(),
- embeddingLevel);
- propTable->Set(frame, nsBidi::BaseLevelProperty(),
- aBpd->GetParaLevel());
- propTable->Set(frame, nsBidi::ParagraphDepthProperty(),
- aBpd->mParagraphDepth);
+ FrameBidiData bidiData;
+ bidiData.embeddingLevel = embeddingLevel;
+ bidiData.baseLevel = aBpd->GetParaLevel();
+ bidiData.paragraphDepth = aBpd->mParagraphDepth;
+ propTable->Set(frame, nsBidi::BidiDataProperty(), bidiData);
continue;
}
int32_t start, end;
frame->GetOffsets(start, end);
NS_ASSERTION(!(contentTextLength < end - start),
"Frame offsets don't fit in content");
fragmentLength = std::min(contentTextLength, end - start);
contentOffset = start;
@@ -823,22 +823,21 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
runLength = logicalLimit - lineOffset;
} // if (runLength <= 0)
if (frame == NS_BIDI_CONTROL_FRAME) {
frame = nullptr;
++lineOffset;
}
else {
- propTable->Set(frame, nsBidi::EmbeddingLevelProperty(),
- embeddingLevel);
- propTable->Set(frame, nsBidi::BaseLevelProperty(),
- aBpd->GetParaLevel());
- propTable->Set(frame, nsBidi::ParagraphDepthProperty(),
- aBpd->mParagraphDepth);
+ FrameBidiData bidiData;
+ bidiData.embeddingLevel = embeddingLevel;
+ bidiData.baseLevel = aBpd->GetParaLevel();
+ bidiData.paragraphDepth = aBpd->mParagraphDepth;
+ propTable->Set(frame, nsBidi::BidiDataProperty(), bidiData);
if (isTextFrame) {
if ( (runLength > 0) && (runLength < fragmentLength) ) {
/*
* The text in this frame continues beyond the end of this directional run.
* Create a non-fluid continuation frame for the next directional run.
*/
currentLine->MarkDirty();
nsIFrame* nextBidi;
@@ -1773,33 +1772,26 @@ nsBidiPresUtils::EnsureBidiContinuation(
void
nsBidiPresUtils::RemoveBidiContinuation(BidiParagraphData *aBpd,
nsIFrame* aFrame,
int32_t aFirstIndex,
int32_t aLastIndex,
int32_t& aOffset)
{
- FrameProperties props = aFrame->Properties();
- nsBidiLevel embeddingLevel = props.Get(nsBidi::EmbeddingLevelProperty());
- nsBidiLevel baseLevel = props.Get(nsBidi::BaseLevelProperty());
- uint8_t paragraphDepth = props.Get(nsBidi::ParagraphDepthProperty());
-
+ FrameBidiData bidiData = nsBidi::GetBidiData(aFrame);
for (int32_t index = aFirstIndex + 1; index <= aLastIndex; index++) {
nsIFrame* frame = aBpd->FrameAt(index);
if (frame == NS_BIDI_CONTROL_FRAME) {
++aOffset;
}
else {
// Make the frame and its continuation ancestors fluid,
// so they can be reused or deleted by normal reflow code
- FrameProperties frameProps = frame->Properties();
- frameProps.Set(nsBidi::EmbeddingLevelProperty(), embeddingLevel);
- frameProps.Set(nsBidi::BaseLevelProperty(), baseLevel);
- frameProps.Set(nsBidi::ParagraphDepthProperty(), paragraphDepth);
+ frame->Properties().Set(nsBidi::BidiDataProperty(), bidiData);
frame->AddStateBits(NS_FRAME_IS_BIDI);
while (frame) {
nsIFrame* prev = frame->GetPrevContinuation();
if (prev) {
MakeContinuationFluid(prev, frame);
frame = frame->GetParent();
} else {
break;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -149,18 +149,18 @@ struct nsContentAndOffset
#define CALC_DEBUG 0
// This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
// because it uses the frame pointer passed in without drilling down to
// the leaf frame.
static bool
IsReversedDirectionFrame(nsIFrame* aFrame)
{
- return !IS_SAME_DIRECTION(nsBidi::GetEmbeddingLevel(aFrame),
- nsBidi::GetBaseLevel(aFrame));
+ FrameBidiData bidiData = nsBidi::GetBidiData(aFrame);
+ return !IS_SAME_DIRECTION(bidiData.embeddingLevel, bidiData.baseLevel);
}
#include "nsILineIterator.h"
//non Hack prototypes
#if 0
static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
#endif
@@ -6585,21 +6585,21 @@ nsFrame::GetPointFromOffset(int32_t inOf
if (newContent){
int32_t newOffset = newContent->IndexOf(mContent);
// Find the direction of the frame from the EmbeddingLevelProperty,
// which is the resolved bidi level set in
// nsBidiPresUtils::ResolveParagraph (odd levels = right-to-left).
// If the embedding level isn't set, just use the CSS direction
// property.
- bool hasEmbeddingLevel;
- nsBidiLevel embeddingLevel = Properties().Get(
- nsBidi::EmbeddingLevelProperty(), &hasEmbeddingLevel);
- bool isRTL = hasEmbeddingLevel
- ? IS_LEVEL_RTL(embeddingLevel)
+ bool hasBidiData;
+ FrameBidiData bidiData =
+ Properties().Get(nsBidi::BidiDataProperty(), &hasBidiData);
+ bool isRTL = hasBidiData
+ ? IS_LEVEL_RTL(bidiData.embeddingLevel)
: StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
if ((!isRTL && inOffset > newOffset) ||
(isRTL && inOffset <= newOffset)) {
pt = contentRect.TopRight();
}
}
}
*outPoint = pt;
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -1112,26 +1112,27 @@ nsFrameSelection::MoveCaret(nsDirection
theFrame->GetOffsets(frameStart, frameEnd);
}
if (context->BidiEnabled())
{
switch (aAmount) {
case eSelectBeginLine:
- case eSelectEndLine:
+ case eSelectEndLine: {
// In Bidi contexts, PeekOffset calculates pos.mContentOffset
// differently depending on whether the movement is visual or logical.
// For visual movement, pos.mContentOffset depends on the direction-
// ality of the first/last frame on the line (theFrame), and the caret
// directionality must correspond.
- SetCaretBidiLevel(visualMovement ? nsBidi::GetEmbeddingLevel(theFrame)
- : nsBidi::GetBaseLevel(theFrame));
+ FrameBidiData bidiData = nsBidi::GetBidiData(theFrame);
+ SetCaretBidiLevel(visualMovement ? bidiData.embeddingLevel
+ : bidiData.baseLevel);
break;
-
+ }
default:
// If the current position is not a frame boundary, it's enough just
// to take the Bidi level of the current frame
if ((pos.mContentOffset != frameStart &&
pos.mContentOffset != frameEnd) ||
eSelectLine == aAmount) {
SetCaretBidiLevel(nsBidi::GetEmbeddingLevel(theFrame));
}
@@ -1373,31 +1374,31 @@ nsFrameSelection::GetPrevNextBidiLevels(
bool jumpedLine, movedOverNonSelectableText;
nsresult rv = currentFrame->GetFrameFromDirection(direction, false,
aJumpLines, true,
&newFrame, &offset, &jumpedLine,
&movedOverNonSelectableText);
if (NS_FAILED(rv))
newFrame = nullptr;
- nsBidiLevel baseLevel = nsBidi::GetBaseLevel(currentFrame);
- nsBidiLevel currentLevel = nsBidi::GetEmbeddingLevel(currentFrame);
+ FrameBidiData currentBidi = nsBidi::GetBidiData(currentFrame);
+ nsBidiLevel currentLevel = currentBidi.embeddingLevel;
nsBidiLevel newLevel = newFrame ? nsBidi::GetEmbeddingLevel(newFrame)
- : baseLevel;
+ : currentBidi.baseLevel;
// If not jumping lines, disregard br frames, since they might be positioned incorrectly.
// XXX This could be removed once bug 339786 is fixed.
if (!aJumpLines) {
if (currentFrame->GetType() == nsGkAtoms::brFrame) {
currentFrame = nullptr;
- currentLevel = baseLevel;
+ currentLevel = currentBidi.baseLevel;
}
if (newFrame && newFrame->GetType() == nsGkAtoms::brFrame) {
newFrame = nullptr;
- newLevel = baseLevel;
+ newLevel = currentBidi.baseLevel;
}
}
if (direction == eDirNext)
levels.SetData(currentFrame, newFrame, currentLevel, newLevel);
else
levels.SetData(newFrame, currentFrame, newLevel, currentLevel);
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1601,22 +1601,24 @@ bool
BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFrame* aFrame2)
{
// We don't need to check font size inflation, since
// |FindLineContainer| above (via |nsIFrame::CanContinueTextRun|)
// ensures that text runs never cross block boundaries. This means
// that the font size inflation on all text frames in the text run is
// already guaranteed to be the same as each other (and for the line
// container).
- if (mBidiEnabled &&
- (nsBidi::GetEmbeddingLevel(aFrame1) !=
- nsBidi::GetEmbeddingLevel(aFrame2) ||
- nsBidi::GetParagraphDepth(aFrame1) !=
- nsBidi::GetParagraphDepth(aFrame2)))
- return false;
+ if (mBidiEnabled) {
+ FrameBidiData data1 = nsBidi::GetBidiData(aFrame1);
+ FrameBidiData data2 = nsBidi::GetBidiData(aFrame2);
+ if (data1.embeddingLevel != data2.embeddingLevel ||
+ data1.paragraphDepth != data2.paragraphDepth) {
+ return false;
+ }
+ }
nsStyleContext* sc1 = aFrame1->StyleContext();
const nsStyleText* textStyle1 = sc1->StyleText();
// If the first frame ends in a preformatted newline, then we end the textrun
// here. This avoids creating giant textruns for an entire plain text file.
// Note that we create a single text frame for a preformatted text node,
// even if it has newlines in it, so typically we won't see trailing newlines
// until after reflow has broken up the frame into one (or more) frames per
@@ -4144,43 +4146,32 @@ nsContinuingTextFrame::Init(nsIContent*
gfxTextRun *uninflatedTextRun =
prev->GetTextRun(nsTextFrame::eNotInflated);
if (uninflatedTextRun) {
SetTextRun(uninflatedTextRun, nsTextFrame::eNotInflated, 1.0f);
}
}
}
if (aPrevInFlow->GetStateBits() & NS_FRAME_IS_BIDI) {
- FramePropertyTable *propTable = PresContext()->PropertyTable();
- // Get all the properties from the prev-in-flow first to take
- // advantage of the propTable's cache and simplify the assertion below
- auto embeddingLevel =
- propTable->Get(aPrevInFlow, nsBidi::EmbeddingLevelProperty());
- auto baseLevel =
- propTable->Get(aPrevInFlow, nsBidi::BaseLevelProperty());
- auto paragraphDepth =
- propTable->Get(aPrevInFlow, nsBidi::ParagraphDepthProperty());
- propTable->Set(this, nsBidi::EmbeddingLevelProperty(), embeddingLevel);
- propTable->Set(this, nsBidi::BaseLevelProperty(), baseLevel);
- propTable->Set(this, nsBidi::ParagraphDepthProperty(), paragraphDepth);
+ FrameBidiData bidiData = nsBidi::GetBidiData(aPrevInFlow);
+ Properties().Set(nsBidi::BidiDataProperty(), bidiData);
if (nextContinuation) {
SetNextContinuation(nextContinuation);
nextContinuation->SetPrevContinuation(this);
// Adjust next-continuations' content offset as needed.
while (nextContinuation &&
nextContinuation->GetContentOffset() < mContentOffset) {
- NS_ASSERTION(
- embeddingLevel == propTable->Get(
- nextContinuation, nsBidi::EmbeddingLevelProperty()) &&
- baseLevel == propTable->Get(
- nextContinuation, nsBidi::BaseLevelProperty()) &&
- paragraphDepth == propTable->Get(
- nextContinuation, nsBidi::ParagraphDepthProperty()),
- "stealing text from different type of BIDI continuation");
+#ifdef DEBUG
+ FrameBidiData nextBidiData = nsBidi::GetBidiData(nextContinuation);
+ NS_ASSERTION(bidiData.embeddingLevel == nextBidiData.embeddingLevel &&
+ bidiData.baseLevel == nextBidiData.baseLevel &&
+ bidiData.paragraphDepth == nextBidiData.paragraphDepth,
+ "stealing text from different type of BIDI continuation");
+#endif
nextContinuation->mContentOffset = mContentOffset;
nextContinuation = static_cast<nsTextFrame*>(nextContinuation->GetNextContinuation());
}
}
mState |= NS_FRAME_IS_BIDI;
} // prev frame is bidi
}