--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -293,17 +293,19 @@ struct TextRunMappedFlow {
/**
* This is the type in the gfxTextRun's userdata field in the common case that
* the text run maps to multiple flows, but no fonts have been found with
* animatable glyphs.
*
* This way, we avoid allocating and constructing the extra nsTArray.
*/
struct TextRunUserData {
+#ifdef DEBUG
TextRunMappedFlow* mMappedFlows;
+#endif
uint32_t mMappedFlowCount;
uint32_t mLastFlowIndex;
};
/**
* This is our user data for the textrun, when textRun->GetFlags() does not
* have TEXT_IS_SIMPLE_FLOW set and has the TEXT_MIGHT HAVE_GLYPH_CHANGES flag.
*/
@@ -455,17 +457,19 @@ protected:
};
static TextRunUserData*
CreateUserData(uint32_t aMappedFlowCount)
{
TextRunUserData* data = static_cast<TextRunUserData*>
(moz_xmalloc(sizeof(TextRunUserData) +
aMappedFlowCount * sizeof(TextRunMappedFlow)));
+#ifdef DEBUG
data->mMappedFlows = reinterpret_cast<TextRunMappedFlow*>(data + 1);
+#endif
data->mMappedFlowCount = aMappedFlowCount;
data->mLastFlowIndex = 0;
return data;
}
static void
DestroyUserData(TextRunUserData* aUserData)
{
@@ -476,17 +480,19 @@ DestroyUserData(TextRunUserData* aUserDa
static ComplexTextRunUserData*
CreateComplexUserData(uint32_t aMappedFlowCount)
{
ComplexTextRunUserData* data = static_cast<ComplexTextRunUserData*>
(moz_xmalloc(sizeof(ComplexTextRunUserData) +
aMappedFlowCount * sizeof(TextRunMappedFlow)));
new (data) ComplexTextRunUserData();
+#ifdef DEBUG
data->mMappedFlows = reinterpret_cast<TextRunMappedFlow*>(data + 1);
+#endif
data->mMappedFlowCount = aMappedFlowCount;
data->mLastFlowIndex = 0;
return data;
}
static void
DestroyComplexUserData(ComplexTextRunUserData* aUserData)
{
@@ -512,16 +518,36 @@ DestroyTextRunUserData(gfxTextRun* aText
DestroyUserData(
static_cast<TextRunUserData*>(aTextRun->GetUserData()));
}
}
aTextRun->ClearFlagBits(nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES);
aTextRun->SetUserData(nullptr);
}
+static TextRunMappedFlow*
+GetMappedFlows(const gfxTextRun* aTextRun)
+{
+ MOZ_ASSERT(aTextRun->GetUserData(), "UserData must exist.");
+ MOZ_ASSERT(!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW),
+ "The method should not be called for simple flows.");
+ TextRunMappedFlow* flows;
+ if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES) {
+ flows = reinterpret_cast<TextRunMappedFlow*>(
+ static_cast<ComplexTextRunUserData*>(aTextRun->GetUserData()) + 1);
+ } else {
+ flows = reinterpret_cast<TextRunMappedFlow*>(
+ static_cast<TextRunUserData*>(aTextRun->GetUserData()) + 1);
+ }
+ MOZ_ASSERT(static_cast<TextRunUserData*>(aTextRun->GetUserData())->
+ mMappedFlows == flows,
+ "GetMappedFlows should return the same pointer as mMappedFlows.");
+ return flows;
+}
+
/**
* These are utility functions just for helping with the complexity related with
* the text runs user data.
*/
static nsTextFrame*
GetFrameForSimpleFlow(const gfxTextRun* aTextRun)
{
MOZ_ASSERT(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW,
@@ -601,19 +627,20 @@ UnhookTextRunFromFrames(gfxTextRun* aTex
aStartContinuation, whichTextRunState);
NS_ASSERTION(!aStartContinuation || found,
"aStartContinuation wasn't found in simple flow text run");
if (!(userDataFrame->GetStateBits() & whichTextRunState)) {
DestroyTextRunUserData(aTextRun);
}
} else {
auto userData = static_cast<TextRunUserData*>(aTextRun->GetUserData());
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(aTextRun);
int32_t destroyFromIndex = aStartContinuation ? -1 : 0;
for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) {
- nsTextFrame* userDataFrame = userData->mMappedFlows[i].mStartFrame;
+ nsTextFrame* userDataFrame = userMappedFlows[i].mStartFrame;
nsFrameState whichTextRunState =
userDataFrame->GetTextRun(nsTextFrame::eInflated) == aTextRun
? TEXT_IN_TEXTRUN_USER_DATA
: TEXT_IN_UNINFLATED_TEXTRUN_USER_DATA;
bool found =
ClearAllTextRunReferences(userDataFrame, aTextRun,
aStartContinuation, whichTextRunState);
if (found) {
@@ -672,18 +699,19 @@ void
GlyphObserver::NotifyGlyphsChanged()
{
if (mTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
InvalidateFrameDueToGlyphsChanged(GetFrameForSimpleFlow(mTextRun));
return;
}
auto data = static_cast<TextRunUserData*>(mTextRun->GetUserData());
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(mTextRun);
for (uint32_t i = 0; i < data->mMappedFlowCount; ++i) {
- InvalidateFrameDueToGlyphsChanged(data->mMappedFlows[i].mStartFrame);
+ InvalidateFrameDueToGlyphsChanged(userMappedFlows[i].mStartFrame);
}
}
int32_t nsTextFrame::GetContentEnd() const {
nsTextFrame* next = static_cast<nsTextFrame*>(GetNextContinuation());
return next ? next->GetContentOffset() : mContent->GetText()->GetLength();
}
@@ -917,20 +945,24 @@ CreateObserversForAnimatedGlyphs(gfxText
}
auto data =
static_cast<SimpleTextRunUserData*>(aTextRun->GetUserData());
observers = &data->mGlyphObservers;
} else {
if (!(aTextRun->GetFlags() & nsTextFrameUtils::TEXT_MIGHT_HAVE_GLYPH_CHANGES)) {
auto oldData = static_cast<TextRunUserData*>(aTextRun->GetUserData());
- auto data = CreateComplexUserData(oldData->mMappedFlowCount);
+ TextRunMappedFlow* oldMappedFlows = GetMappedFlows(aTextRun);
+ ComplexTextRunUserData* data =
+ CreateComplexUserData(oldData->mMappedFlowCount);
+ TextRunMappedFlow* dataMappedFlows =
+ reinterpret_cast<TextRunMappedFlow*>(data + 1);
data->mLastFlowIndex = oldData->mLastFlowIndex;
for (uint32_t i = 0; i < oldData->mMappedFlowCount; ++i) {
- data->mMappedFlows[i] = oldData->mMappedFlows[i];
+ dataMappedFlows[i] = oldMappedFlows[i];
}
DestroyUserData(oldData);
aTextRun->SetUserData(data);
}
auto data = static_cast<ComplexTextRunUserData*>(aTextRun->GetUserData());
observers = &data->mGlyphObservers;
}
@@ -1540,21 +1572,22 @@ BuildTextRunsScanner::IsTextRunValidForM
{
if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
return mMappedFlows.Length() == 1 &&
mMappedFlows[0].mStartFrame == GetFrameForSimpleFlow(aTextRun) &&
mMappedFlows[0].mEndFrame == nullptr;
}
auto userData = static_cast<TextRunUserData*>(aTextRun->GetUserData());
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(aTextRun);
if (userData->mMappedFlowCount != mMappedFlows.Length())
return false;
for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
- if (userData->mMappedFlows[i].mStartFrame != mMappedFlows[i].mStartFrame ||
- int32_t(userData->mMappedFlows[i].mContentLength) !=
+ if (userMappedFlows[i].mStartFrame != mMappedFlows[i].mStartFrame ||
+ int32_t(userMappedFlows[i].mContentLength) !=
mMappedFlows[i].GetContentEnd() - mMappedFlows[i].mStartFrame->GetContentOffset())
return false;
}
return true;
}
/**
* This gets called when we need to make a text run for the current list of
@@ -1996,30 +2029,31 @@ BuildTextRunsScanner::BuildTextRunForFra
}
if (mCurrentRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) {
textFlags |= gfxTextRunFactory::TEXT_INCOMING_ARABICCHAR;
}
AutoTArray<int32_t,50> textBreakPoints;
TextRunUserData dummyData;
TextRunMappedFlow dummyMappedFlow;
-
+ TextRunMappedFlow* userMappedFlows;
TextRunUserData* userData;
TextRunUserData* userDataToDestroy;
// If the situation is particularly simple (and common) we don't need to
// allocate userData.
if (mMappedFlows.Length() == 1 && !mMappedFlows[0].mEndFrame &&
mMappedFlows[0].mStartFrame->GetContentOffset() == 0) {
userData = &dummyData;
+ userMappedFlows = &dummyMappedFlow;
userDataToDestroy = nullptr;
- dummyData.mMappedFlows = &dummyMappedFlow;
dummyData.mMappedFlowCount = mMappedFlows.Length();
dummyData.mLastFlowIndex = 0;
} else {
userData = CreateUserData(mMappedFlows.Length());
+ userMappedFlows = reinterpret_cast<TextRunMappedFlow*>(userData + 1);
userDataToDestroy = userData;
}
uint32_t currentTransformedTextOffset = 0;
uint32_t nextBreakIndex = 0;
nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
bool isSVG = mLineContainer->IsSVGText();
@@ -2139,17 +2173,17 @@ BuildTextRunsScanner::BuildTextRunForFra
// Figure out what content is included in this flow.
nsIContent* content = f->GetContent();
const nsTextFragment* frag = content->GetText();
int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
int32_t contentEnd = mappedFlow->GetContentEnd();
int32_t contentLength = contentEnd - contentStart;
- TextRunMappedFlow* newFlow = &userData->mMappedFlows[i];
+ TextRunMappedFlow* newFlow = &userMappedFlows[i];
newFlow->mStartFrame = mappedFlow->mStartFrame;
newFlow->mDOMOffsetToBeforeTransformOffset = skipChars.GetOriginalCharCount() -
mappedFlow->mStartFrame->GetContentOffset();
newFlow->mContentLength = contentLength;
while (nextBreakBeforeFrame && nextBreakBeforeFrame->GetContent() == content) {
textBreakPoints.AppendElement(
nextBreakBeforeFrame->GetContentOffset() + newFlow->mDOMOffsetToBeforeTransformOffset);
@@ -2396,30 +2430,31 @@ BuildTextRunsScanner::SetupLineBreakerCo
return false;
}
gfxSkipChars skipChars;
AutoTArray<int32_t,50> textBreakPoints;
TextRunUserData dummyData;
TextRunMappedFlow dummyMappedFlow;
-
+ TextRunMappedFlow* userMappedFlows;
TextRunUserData* userData;
TextRunUserData* userDataToDestroy;
// If the situation is particularly simple (and common) we don't need to
// allocate userData.
if (mMappedFlows.Length() == 1 && !mMappedFlows[0].mEndFrame &&
mMappedFlows[0].mStartFrame->GetContentOffset() == 0) {
userData = &dummyData;
+ userMappedFlows = &dummyMappedFlow;
userDataToDestroy = nullptr;
- dummyData.mMappedFlows = &dummyMappedFlow;
dummyData.mMappedFlowCount = mMappedFlows.Length();
dummyData.mLastFlowIndex = 0;
} else {
userData = CreateUserData(mMappedFlows.Length());
+ userMappedFlows = reinterpret_cast<TextRunMappedFlow*>(userData + 1);
userDataToDestroy = userData;
}
uint32_t nextBreakIndex = 0;
nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
const nsStyleText* textStyle = nullptr;
for (uint32_t i = 0; i < mMappedFlows.Length(); ++i) {
@@ -2432,17 +2467,17 @@ BuildTextRunsScanner::SetupLineBreakerCo
// Figure out what content is included in this flow.
nsIContent* content = f->GetContent();
const nsTextFragment* frag = content->GetText();
int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
int32_t contentEnd = mappedFlow->GetContentEnd();
int32_t contentLength = contentEnd - contentStart;
- TextRunMappedFlow* newFlow = &userData->mMappedFlows[i];
+ TextRunMappedFlow* newFlow = &userMappedFlows[i];
newFlow->mStartFrame = mappedFlow->mStartFrame;
newFlow->mDOMOffsetToBeforeTransformOffset = skipChars.GetOriginalCharCount() -
mappedFlow->mStartFrame->GetContentOffset();
newFlow->mContentLength = contentLength;
while (nextBreakBeforeFrame && nextBreakBeforeFrame->GetContent() == content) {
textBreakPoints.AppendElement(
nextBreakBeforeFrame->GetContentOffset() + newFlow->mDOMOffsetToBeforeTransformOffset);
@@ -2644,49 +2679,50 @@ BuildTextRunsScanner::SetupTextEmphasisF
}
}
}
}
}
// Find the flow corresponding to aContent in aUserData
static inline TextRunMappedFlow*
-FindFlowForContent(TextRunUserData* aUserData, nsIContent* aContent)
+FindFlowForContent(TextRunUserData* aUserData, nsIContent* aContent,
+ TextRunMappedFlow* userMappedFlows)
{
// Find the flow that contains us
int32_t i = aUserData->mLastFlowIndex;
int32_t delta = 1;
int32_t sign = 1;
// Search starting at the current position and examine close-by
// positions first, moving further and further away as we go.
while (i >= 0 && uint32_t(i) < aUserData->mMappedFlowCount) {
- TextRunMappedFlow* flow = &aUserData->mMappedFlows[i];
+ TextRunMappedFlow* flow = &userMappedFlows[i];
if (flow->mStartFrame->GetContent() == aContent) {
return flow;
}
i += delta;
sign = -sign;
delta = -delta + sign;
}
// We ran into an array edge. Add |delta| to |i| once more to get
// back to the side where we still need to search, then step in
// the |sign| direction.
i += delta;
if (sign > 0) {
for (; i < int32_t(aUserData->mMappedFlowCount); ++i) {
- TextRunMappedFlow* flow = &aUserData->mMappedFlows[i];
+ TextRunMappedFlow* flow = &userMappedFlows[i];
if (flow->mStartFrame->GetContent() == aContent) {
return flow;
}
}
} else {
for (; i >= 0; --i) {
- TextRunMappedFlow* flow = &aUserData->mMappedFlows[i];
+ TextRunMappedFlow* flow = &userMappedFlows[i];
if (flow->mStartFrame->GetContent() == aContent) {
return flow;
}
}
}
return nullptr;
}
@@ -2705,37 +2741,39 @@ BuildTextRunsScanner::AssignTextRun(gfxT
if (f->GetTextRun(mWhichTextRun)) {
gfxTextRun* textRun = f->GetTextRun(mWhichTextRun);
if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
if (mMappedFlows[0].mStartFrame != GetFrameForSimpleFlow(textRun)) {
NS_WARNING("REASSIGNING SIMPLE FLOW TEXT RUN!");
}
} else {
auto userData = static_cast<TextRunUserData*>(aTextRun->GetUserData());
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(aTextRun);
if (userData->mMappedFlowCount >= mMappedFlows.Length() ||
- userData->mMappedFlows[userData->mMappedFlowCount - 1].mStartFrame !=
+ userMappedFlows[userData->mMappedFlowCount - 1].mStartFrame !=
mMappedFlows[userdata->mMappedFlowCount - 1].mStartFrame) {
NS_WARNING("REASSIGNING MULTIFLOW TEXT RUN (not append)!");
}
}
}
#endif
gfxTextRun* oldTextRun = f->GetTextRun(mWhichTextRun);
if (oldTextRun) {
nsTextFrame* firstFrame = nullptr;
uint32_t startOffset = 0;
if (oldTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
firstFrame = GetFrameForSimpleFlow(oldTextRun);
} else {
auto userData = static_cast<TextRunUserData*>(oldTextRun->GetUserData());
- firstFrame = userData->mMappedFlows[0].mStartFrame;
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(oldTextRun);
+ firstFrame = userMappedFlows[0].mStartFrame;
if (MOZ_UNLIKELY(f != firstFrame)) {
- TextRunMappedFlow* flow = FindFlowForContent(userData,
- f->GetContent());
+ TextRunMappedFlow* flow =
+ FindFlowForContent(userData, f->GetContent(), userMappedFlows);
if (flow) {
startOffset = flow->mDOMOffsetToBeforeTransformOffset;
} else {
NS_ERROR("Can't find flow containing frame 'f'");
}
}
}
@@ -2809,21 +2847,23 @@ nsTextFrame::EnsureTextRun(TextRunType a
if (textRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
if (aFlowEndInTextRun) {
*aFlowEndInTextRun = textRun->GetLength();
}
return gfxSkipCharsIterator(textRun->GetSkipChars(), 0, mContentOffset);
}
auto userData = static_cast<TextRunUserData*>(textRun->GetUserData());
- TextRunMappedFlow* flow = FindFlowForContent(userData, mContent);
+ TextRunMappedFlow* userMappedFlows = GetMappedFlows(textRun);
+ TextRunMappedFlow* flow =
+ FindFlowForContent(userData, mContent, userMappedFlows);
if (flow) {
// Since textruns can only contain one flow for a given content element,
// this must be our flow.
- uint32_t flowIndex = flow - userData->mMappedFlows;
+ uint32_t flowIndex = flow - userMappedFlows;
userData->mLastFlowIndex = flowIndex;
gfxSkipCharsIterator iter(textRun->GetSkipChars(),
flow->mDOMOffsetToBeforeTransformOffset, mContentOffset);
if (aFlowEndInTextRun) {
if (flowIndex + 1 < userData->mMappedFlowCount) {
gfxSkipCharsIterator end(textRun->GetSkipChars());
*aFlowEndInTextRun = end.ConvertOriginalToSkipped(
flow[1].mStartFrame->GetContentOffset() + flow[1].mDOMOffsetToBeforeTransformOffset);