Bug 1553378 - Devirtualize calls to GetText() / TextLength() when we know we have a Text node. r=smaug,jfkthame

Differential Revision: https://phabricator.services.mozilla.com/D32100

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Cameron McCormack 2019-05-24 08:10:55 +00:00
parent 697c499897
commit 5bed2b0138
24 changed files with 141 additions and 163 deletions

View File

@ -251,7 +251,8 @@ nsresult CharacterData::SetTextInternal(
Directionality oldDir = eDir_NotSet;
bool dirAffectsAncestor =
(NodeType() == TEXT_NODE &&
TextNodeWillChangeDirection(this, &oldDir, aOffset));
TextNodeWillChangeDirection(static_cast<nsTextNode*>(this), &oldDir,
aOffset));
if (aOffset == 0 && endOffset == textLength) {
// Replacing whole text or old text was empty. Don't bother to check for

View File

@ -117,10 +117,10 @@ class CharacterData : public nsIContent {
}
const nsTextFragment* GetText() override { return &mText; }
uint32_t TextLength() const final { return TextDataLength(); }
const nsTextFragment& TextFragment() const { return mText; }
uint32_t TextLength() const final { return TextDataLength(); }
uint32_t TextDataLength() const { return mText.GetLength(); }
/**
* Set the text to the given value. If aNotify is true then
@ -197,8 +197,6 @@ class CharacterData : public nsIContent {
void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData,
ErrorResult& rv);
uint32_t TextDataLength() const { return mText.GetLength(); }
//----------------------------------------
#ifdef DEBUG

View File

@ -378,14 +378,14 @@ static Directionality GetDirectionFromText(const char* aText,
return eDir_NotSet;
}
static Directionality GetDirectionFromText(const nsTextFragment* aFrag,
static Directionality GetDirectionFromText(const Text* aTextNode,
uint32_t* aFirstStrong = nullptr) {
if (aFrag->Is2b()) {
return GetDirectionFromText(aFrag->Get2b(), aFrag->GetLength(),
aFirstStrong);
const nsTextFragment* frag = &aTextNode->TextFragment();
if (frag->Is2b()) {
return GetDirectionFromText(frag->Get2b(), frag->GetLength(), aFirstStrong);
}
return GetDirectionFromText(aFrag->Get1b(), aFrag->GetLength(), aFirstStrong);
return GetDirectionFromText(frag->Get1b(), frag->GetLength(), aFirstStrong);
}
static nsTextNode* WalkDescendantsAndGetDirectionFromText(
@ -405,12 +405,12 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
for (uint32_t i = 0; i < assignedNodes.Length(); ++i) {
nsIContent* assignedNode = assignedNodes[i]->AsContent();
if (assignedNode->NodeType() == nsINode::TEXT_NODE) {
auto text = static_cast<nsTextNode*>(assignedNode);
if (assignedNode != aSkip) {
Directionality textNodeDir =
GetDirectionFromText(assignedNode->GetText());
Directionality textNodeDir = GetDirectionFromText(text);
if (textNodeDir != eDir_NotSet) {
*aDirectionality = textNodeDir;
return static_cast<nsTextNode*>(assignedNode);
return text;
}
}
} else if (assignedNode->IsElement() &&
@ -426,10 +426,11 @@ static nsTextNode* WalkDescendantsAndGetDirectionFromText(
}
if (child->NodeType() == nsINode::TEXT_NODE && child != aSkip) {
Directionality textNodeDir = GetDirectionFromText(child->GetText());
auto text = static_cast<nsTextNode*>(child);
Directionality textNodeDir = GetDirectionFromText(text);
if (textNodeDir != eDir_NotSet) {
*aDirectionality = textNodeDir;
return static_cast<nsTextNode*>(child);
return text;
}
}
child = child->GetNextNode(aRoot);
@ -1052,7 +1053,7 @@ void SetAncestorDirectionIfAuto(nsTextNode* aTextNode, Directionality aDir,
}
}
bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
uint32_t aOffset) {
if (!NodeAffectsDirAutoAncestor(aTextNode)) {
nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
@ -1060,13 +1061,13 @@ bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
}
uint32_t firstStrong;
*aOldDir = GetDirectionFromText(aTextNode->GetText(), &firstStrong);
*aOldDir = GetDirectionFromText(aTextNode, &firstStrong);
return (aOffset <= firstStrong);
}
void TextNodeChangedDirection(nsTextNode* aTextNode, Directionality aOldDir,
bool aNotify) {
Directionality newDir = GetDirectionFromText(aTextNode->GetText());
Directionality newDir = GetDirectionFromText(aTextNode);
if (newDir == eDir_NotSet) {
if (aOldDir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
// This node used to have a strong directional character but no
@ -1102,7 +1103,7 @@ void SetDirectionFromNewTextNode(nsTextNode* aTextNode) {
aTextNode->SetAncestorHasDirAuto();
}
Directionality dir = GetDirectionFromText(aTextNode->GetText());
Directionality dir = GetDirectionFromText(aTextNode);
if (dir != eDir_NotSet) {
SetAncestorDirectionIfAuto(aTextNode, dir);
}
@ -1114,7 +1115,7 @@ void ResetDirectionSetByTextNode(nsTextNode* aTextNode) {
return;
}
Directionality dir = GetDirectionFromText(aTextNode->GetText());
Directionality dir = GetDirectionFromText(aTextNode);
if (dir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
}

View File

@ -96,7 +96,7 @@ void WalkDescendantsClearAncestorDirAuto(nsIContent* aContent);
*
* @return whether the text node affects the directionality of any element
*/
bool TextNodeWillChangeDirection(nsIContent* aTextNode, Directionality* aOldDir,
bool TextNodeWillChangeDirection(nsTextNode* aTextNode, Directionality* aOldDir,
uint32_t aOffset);
/**

View File

@ -1474,8 +1474,8 @@ void Selection::SelectFramesForContent(nsIContent* aContent, bool aSelected) {
// as a text frame.
if (frame->IsTextFrame()) {
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
textFrame->SetSelectedRange(0, aContent->GetText()->GetLength(), aSelected,
mSelectionType);
textFrame->SetSelectedRange(0, textFrame->TextFragment()->GetLength(),
aSelected, mSelectionType);
} else {
frame->InvalidateFrameSubtree(); // frame continuations?
}

View File

@ -9056,8 +9056,7 @@ bool nsContentUtils::SerializeNodeToMarkup(nsINode* aRoot,
case nsINode::TEXT_NODE:
case nsINode::CDATA_SECTION_NODE: {
const nsTextFragment* text =
static_cast<nsIContent*>(current)->GetText();
const nsTextFragment* text = &current->AsText()->TextFragment();
nsIContent* parent = current->GetParent();
if (ShouldEscape(parent)) {
AppendEncodedCharacters(text, builder);

View File

@ -2875,7 +2875,7 @@ void nsRange::CollectClientRectsAndText(
if (node == startContainer) {
int32_t offset = startContainer == endContainer
? static_cast<int32_t>(aEndOffset)
: content->GetText()->GetLength();
: content->AsText()->TextDataLength();
GetPartialTextRect(aCollector, aTextList, content,
static_cast<int32_t>(aStartOffset), offset,
aClampToEdge, aFlushLayout);
@ -2989,7 +2989,7 @@ nsresult nsRange::GetUsedFontFaces(nsLayoutUtils::UsedFontFaceList& aResult,
if (node == startContainer) {
int32_t offset = startContainer == endContainer
? mEnd.Offset()
: content->GetText()->GetLength();
: content->AsText()->TextDataLength();
nsLayoutUtils::GetFontFacesForText(frame, mStart.Offset(), offset, true,
aResult, fontFaces, aMaxRanges,
aSkipCollapsedWhitespace);

View File

@ -506,33 +506,19 @@ static void ConvertToNativeNewlines(nsString& aString) {
#endif
}
static void AppendString(nsAString& aString, nsIContent* aContent) {
NS_ASSERTION(aContent->IsText(), "aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text) {
return;
}
text->AppendTo(aString);
static void AppendString(nsAString& aString, Text* aText) {
aText->TextFragment().AppendTo(aString);
}
static void AppendSubString(nsAString& aString, nsIContent* aContent,
uint32_t aXPOffset, uint32_t aXPLength) {
NS_ASSERTION(aContent->IsText(), "aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text) {
return;
}
text->AppendTo(aString, int32_t(aXPOffset), int32_t(aXPLength));
static void AppendSubString(nsAString& aString, Text* aText, uint32_t aXPOffset,
uint32_t aXPLength) {
aText->TextFragment().AppendTo(aString, int32_t(aXPOffset),
int32_t(aXPLength));
}
#if defined(XP_WIN)
static uint32_t CountNewlinesInXPLength(nsIContent* aContent,
uint32_t aXPLength) {
NS_ASSERTION(aContent->IsText(), "aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text) {
return 0;
}
static uint32_t CountNewlinesInXPLength(Text* aText, uint32_t aXPLength) {
const nsTextFragment* text = aText->TextFragment();
// For automated tests, we should abort on debug build.
MOZ_ASSERT(aXPLength == UINT32_MAX || aXPLength <= text->GetLength(),
"aXPLength is out-of-bounds");
@ -546,13 +532,9 @@ static uint32_t CountNewlinesInXPLength(nsIContent* aContent,
return newlines;
}
static uint32_t CountNewlinesInNativeLength(nsIContent* aContent,
static uint32_t CountNewlinesInNativeLength(Text* aText,
uint32_t aNativeLength) {
NS_ASSERTION(aContent->IsText(), "aContent is not a text node!");
const nsTextFragment* text = aContent->GetText();
if (!text) {
return 0;
}
const nsTextFragment* text = &aText->TextFragment();
// For automated tests, we should abort on debug build.
MOZ_ASSERT(
(aNativeLength == UINT32_MAX || aNativeLength <= text->GetLength() * 2),
@ -584,8 +566,9 @@ uint32_t ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
if (aStartOffset == aEndOffset) {
return 0;
}
return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aEndOffset) -
GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aStartOffset);
return GetTextLength(aContent->AsText(), LINE_BREAK_TYPE_NATIVE, aEndOffset) -
GetTextLength(aContent->AsText(), LINE_BREAK_TYPE_NATIVE,
aStartOffset);
}
/* static */
@ -594,7 +577,7 @@ uint32_t ContentEventHandler::GetNativeTextLength(nsIContent* aContent,
if (NS_WARN_IF(!aContent->IsText())) {
return 0;
}
return GetTextLength(aContent, LINE_BREAK_TYPE_NATIVE, aMaxLength);
return GetTextLength(aContent->AsText(), LINE_BREAK_TYPE_NATIVE, aMaxLength);
}
/* static */
@ -630,7 +613,7 @@ uint32_t ContentEventHandler::GetTextLength(nsIContent* aContent,
// of the XP newline ("\n"), so XP length is equal to the length of the
// native offset plus the number of newlines encountered in the string.
(aLineBreakType == LINE_BREAK_TYPE_NATIVE)
? CountNewlinesInXPLength(aContent, aMaxLength)
? CountNewlinesInXPLength(aContent->AsText(), aMaxLength)
: 0;
#else
// On other platforms, the native and XP newlines are the same.
@ -651,7 +634,8 @@ static uint32_t ConvertToXPOffset(nsIContent* aContent,
// On Windows, the length of a native newline ("\r\n") is twice the length of
// the XP newline ("\n"), so XP offset is equal to the length of the native
// offset minus the number of newlines encountered in the string.
return aNativeOffset - CountNewlinesInNativeLength(aContent, aNativeOffset);
return aNativeOffset - CountNewlinesInNativeLength(aContent->AsText(),
aNativeOffset);
#else
// On other platforms, the native and XP newlines are the same.
return aNativeOffset;
@ -731,8 +715,7 @@ nsresult ContentEventHandler::GenerateFlatTextContent(
}
if (startNode == endNode && startNode->IsText()) {
nsIContent* content = startNode->AsContent();
AppendSubString(aString, content, aRawRange.StartOffset(),
AppendSubString(aString, startNode->AsText(), aRawRange.StartOffset(),
aRawRange.EndOffset() - aRawRange.StartOffset());
ConvertToNativeNewlines(aString);
return NS_OK;
@ -752,18 +735,17 @@ nsresult ContentEventHandler::GenerateFlatTextContent(
if (!node->IsContent()) {
continue;
}
nsIContent* content = node->AsContent();
if (content->IsText()) {
if (content == startNode) {
AppendSubString(aString, content, aRawRange.StartOffset(),
content->TextLength() - aRawRange.StartOffset());
} else if (content == endNode) {
AppendSubString(aString, content, 0, aRawRange.EndOffset());
if (node->IsText()) {
if (node == startNode) {
AppendSubString(aString, node->AsText(), aRawRange.StartOffset(),
node->AsText()->TextLength() - aRawRange.StartOffset());
} else if (node == endNode) {
AppendSubString(aString, node->AsText(), 0, aRawRange.EndOffset());
} else {
AppendString(aString, content);
AppendString(aString, node->AsText());
}
} else if (ShouldBreakLineBefore(content, mRootContent)) {
} else if (ShouldBreakLineBefore(node->AsContent(), mRootContent)) {
aString.Append(char16_t('\n'));
}
}
@ -1001,7 +983,7 @@ nsresult ContentEventHandler::ExpandToClusterBoundary(nsIContent* aContent,
}
// If the frame isn't available, we only can check surrogate pair...
const nsTextFragment* text = aContent->GetText();
const nsTextFragment* text = &aContent->AsText()->TextFragment();
NS_ENSURE_TRUE(text, NS_ERROR_FAILURE);
if (NS_IS_LOW_SURROGATE(text->CharAt(*aXPOffset)) &&
NS_IS_HIGH_SURROGATE(text->CharAt(*aXPOffset - 1))) {
@ -1864,7 +1846,7 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
}
// Assign the characters whose rects are computed by the call of
// nsTextFrame::GetCharacterRectsInRange().
AppendSubString(chars, firstContent, firstFrame.mOffsetInNode,
AppendSubString(chars, firstContent->AsText(), firstFrame.mOffsetInNode,
charRects.Length());
if (NS_WARN_IF(chars.Length() != charRects.Length())) {
return NS_ERROR_UNEXPECTED;

View File

@ -83,7 +83,7 @@ Maybe<int32_t> SVGTextContentElement::GetNonLayoutDependentNumberOfChars() {
return Nothing();
}
const nsTextFragment* text = static_cast<nsTextNode*>(n)->GetText();
const nsTextFragment* text = &n->AsText()->TextFragment();
uint32_t length = text->GetLength();
if (text->Is2b()) {

View File

@ -2429,7 +2429,7 @@ nsresult HTMLEditRules::WillDeleteSelection(
eo--;
// Bug 1068979: delete both codepoints if surrogate pair
if (so > 0) {
const nsTextFragment* text = nodeAsText->GetText();
const nsTextFragment* text = &nodeAsText->TextFragment();
if (NS_IS_LOW_SURROGATE(text->CharAt(so)) &&
NS_IS_HIGH_SURROGATE(text->CharAt(so - 1))) {
so--;

View File

@ -587,7 +587,7 @@ nsresult TextEditor::ExtendSelectionForDelete(nsIEditor::EDirection* aAction) {
if (insertionPoint.IsInTextNode()) {
const nsTextFragment* data =
insertionPoint.GetContainerAsText()->GetText();
&insertionPoint.GetContainerAsText()->TextFragment();
uint32_t offset = insertionPoint.Offset();
if ((offset > 1 && NS_IS_LOW_SURROGATE(data->CharAt(offset - 1)) &&
NS_IS_HIGH_SURROGATE(data->CharAt(offset - 2))) ||

View File

@ -657,7 +657,7 @@ nsresult WSRunObject::GetWSNodes() {
// first look backwards to find preceding ws nodes
if (Text* textNode = mScanStartPoint.GetContainerAsText()) {
const nsTextFragment* textFrag = textNode->GetText();
const nsTextFragment* textFrag = &textNode->TextFragment();
mNodeArray.InsertElementAt(0, textNode);
if (!mScanStartPoint.IsStartOfContainer()) {
for (uint32_t i = mScanStartPoint.Offset(); i; i--) {
@ -701,10 +701,10 @@ nsresult WSRunObject::GetWSNodes() {
} else if (priorNode->IsText() && priorNode->IsEditable()) {
RefPtr<Text> textNode = priorNode->GetAsText();
mNodeArray.InsertElementAt(0, textNode);
const nsTextFragment* textFrag;
if (!textNode || !(textFrag = textNode->GetText())) {
if (!textNode) {
return NS_ERROR_NULL_POINTER;
}
const nsTextFragment* textFrag = &textNode->TextFragment();
uint32_t len = textNode->TextLength();
if (len < 1) {
@ -763,7 +763,7 @@ nsresult WSRunObject::GetWSNodes() {
// then look ahead to find following ws nodes
if (Text* textNode = mScanEndPoint.GetContainerAsText()) {
// don't need to put it on list. it already is from code above
const nsTextFragment* textFrag = textNode->GetText();
const nsTextFragment* textFrag = &textNode->TextFragment();
if (!mScanEndPoint.IsEndOfContainer()) {
for (uint32_t i = mScanEndPoint.Offset(); i < textNode->TextLength();
i++) {
@ -808,10 +808,10 @@ nsresult WSRunObject::GetWSNodes() {
} else if (nextNode->IsText() && nextNode->IsEditable()) {
RefPtr<Text> textNode = nextNode->GetAsText();
mNodeArray.AppendElement(textNode);
const nsTextFragment* textFrag;
if (!textNode || !(textFrag = textNode->GetText())) {
if (!textNode) {
return NS_ERROR_NULL_POINTER;
}
const nsTextFragment* textFrag = &textNode->TextFragment();
uint32_t len = textNode->TextLength();
if (len < 1) {
@ -1510,7 +1510,7 @@ nsresult WSRunObject::InsertNBSPAndRemoveFollowingASCIIWhitespaces(
// Now, the text node may have been modified by mutation observer.
// So, the NBSP may have gone.
if (aPoint.mTextNode->TextDataLength() <= aPoint.mOffset ||
aPoint.mTextNode->GetText()->CharAt(aPoint.mOffset) != kNBSP) {
aPoint.mTextNode->TextFragment().CharAt(aPoint.mOffset) != kNBSP) {
// This is just preparation of an edit action. Let's return NS_OK.
// XXX Perhaps, we should return another success code which indicates
// mutation observer touched the DOM tree. However, that should
@ -1640,11 +1640,11 @@ char16_t WSRunObject::GetCharAt(Text* aTextNode, int32_t aOffset) const {
// return 0 if we can't get a char, for whatever reason
NS_ENSURE_TRUE(aTextNode, 0);
int32_t len = int32_t(aTextNode->TextLength());
int32_t len = int32_t(aTextNode->TextDataLength());
if (aOffset < 0 || aOffset >= len) {
return 0;
}
return aTextNode->GetText()->CharAt(aOffset);
return aTextNode->TextFragment().CharAt(aOffset);
}
template <typename PT, typename CT>

View File

@ -286,7 +286,7 @@ void RestyleManager::CharacterDataChanged(
return;
}
const nsTextFragment* text = aContent->GetText();
const nsTextFragment* text = &aContent->AsText()->TextFragment();
const size_t oldLength = aInfo.mChangeStart;
const size_t newLength = text->GetLength();

View File

@ -1277,10 +1277,10 @@ bool nsBidiPresUtils::ChildListMayRequireBidi(nsIFrame* aFirstChild,
// Check whether the text frame has any RTL characters; if so, bidi
// resolution will be needed.
nsIContent* content = frame->GetContent();
dom::Text* content = frame->GetContent()->AsText();
if (content != *aCurrContent) {
*aCurrContent = content;
const nsTextFragment* txt = content->GetText();
const nsTextFragment* txt = &content->TextFragment();
if (txt->Is2b() &&
HasRTLChars(MakeSpan(txt->Get2b(), txt->GetLength()))) {
return true;

View File

@ -9989,35 +9989,24 @@ static int32_t FirstLetterCount(const nsTextFragment* aFragment) {
return count;
}
static bool NeedFirstLetterContinuation(nsIContent* aContent) {
MOZ_ASSERT(aContent, "null ptr");
bool result = false;
if (aContent) {
const nsTextFragment* frag = aContent->GetText();
if (frag) {
int32_t flc = FirstLetterCount(frag);
int32_t tl = frag->GetLength();
if (flc < tl) {
result = true;
}
}
}
return result;
static bool NeedFirstLetterContinuation(Text* aText) {
MOZ_ASSERT(aText, "null ptr");
int32_t flc = FirstLetterCount(&aText->TextFragment());
int32_t tl = aText->TextDataLength();
return flc < tl;
}
static bool IsFirstLetterContent(nsIContent* aContent) {
return aContent->TextLength() && !aContent->TextIsOnlyWhitespace();
static bool IsFirstLetterContent(Text* aText) {
return aText->TextDataLength() && !aText->TextIsOnlyWhitespace();
}
/**
* Create a letter frame, only make it a floating frame.
*/
nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
nsFrameConstructorState& aState, nsIContent* aTextContent,
nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
ComputedStyle* aParentComputedStyle, ComputedStyle* aComputedStyle,
nsFrameList& aResult) {
nsFrameConstructorState& aState, Text* aTextContent, nsIFrame* aTextFrame,
nsContainerFrame* aParentFrame, ComputedStyle* aParentComputedStyle,
ComputedStyle* aComputedStyle, nsFrameList& aResult) {
MOZ_ASSERT(aParentComputedStyle);
nsFirstLetterFrame* letterFrame =
@ -10081,9 +10070,7 @@ nsFirstLetterFrame* nsCSSFrameConstructor::CreateFloatingLetterFrame(
*/
void nsCSSFrameConstructor::CreateLetterFrame(
nsContainerFrame* aBlockFrame, nsContainerFrame* aBlockContinuation,
nsIContent* aTextContent, nsContainerFrame* aParentFrame,
nsFrameList& aResult) {
MOZ_ASSERT(aTextContent->IsText(), "aTextContent isn't text");
Text* aTextContent, nsContainerFrame* aParentFrame, nsFrameList& aResult) {
NS_ASSERTION(aBlockFrame->IsBlockFrameOrSubclass(), "Not a block frame?");
// Get a ComputedStyle for the first-letter-frame.
@ -10217,7 +10204,7 @@ void nsCSSFrameConstructor::WrapFramesInFirstLetterFrame(
LayoutFrameType frameType = frame->Type();
if (LayoutFrameType::Text == frameType) {
// Wrap up first-letter content in a letter frame
nsIContent* textContent = frame->GetContent();
Text* textContent = frame->GetContent()->AsText();
if (IsFirstLetterContent(textContent)) {
// Create letter frame to wrap up the text
CreateLetterFrame(aBlockFrame, aBlockContinuation, textContent,

View File

@ -1920,14 +1920,14 @@ class nsCSSFrameConstructor final : public nsFrameManager {
// Methods support :first-letter style
nsFirstLetterFrame* CreateFloatingLetterFrame(
nsFrameConstructorState& aState, nsIContent* aTextContent,
nsFrameConstructorState& aState, mozilla::dom::Text* aTextContent,
nsIFrame* aTextFrame, nsContainerFrame* aParentFrame,
ComputedStyle* aParentComputedStyle, ComputedStyle* aComputedStyle,
nsFrameList& aResult);
void CreateLetterFrame(nsContainerFrame* aBlockFrame,
nsContainerFrame* aBlockContinuation,
nsIContent* aTextContent,
mozilla::dom::Text* aTextContent,
nsContainerFrame* aParentFrame, nsFrameList& aResult);
void WrapFramesInFirstLetterFrame(nsContainerFrame* aBlockFrame,

View File

@ -9363,7 +9363,7 @@ void nsLayoutUtils::AppendFrameTextContent(nsIFrame* aFrame,
auto textFrame = static_cast<nsTextFrame*>(aFrame);
auto offset = textFrame->GetContentOffset();
auto length = textFrame->GetContentLength();
textFrame->GetContent()->GetText()->AppendTo(aResult, offset, length);
textFrame->TextFragment()->AppendTo(aResult, offset, length);
} else {
for (nsIFrame* child : aFrame->PrincipalChildList()) {
AppendFrameTextContent(child, aResult);

View File

@ -890,8 +890,7 @@ nsresult nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect) {
child = child->GetPreviousSibling();
if (child && child->IsText()) {
rootNode = child;
const nsTextFragment* fragment = child->GetText();
numChildren = fragment ? fragment->GetLength() : 0;
numChildren = child->AsText()->TextDataLength();
}
}
}

View File

@ -258,7 +258,7 @@ void nsFontInflationData::UpdateISize(const ReflowInput& aReflowInput) {
if (content && kid == content->GetPrimaryFrame()) {
uint32_t len = nsTextFrameUtils::
ComputeApproximateLengthWithWhitespaceCompression(
content, kid->StyleText());
content->AsText(), kid->StyleText());
if (len != 0) {
return kid;
}
@ -295,7 +295,8 @@ static uint32_t DoCharCountOfLargestOption(nsIFrame* aContainer) {
if (optionChild->IsTextFrame()) {
optionResult += nsTextFrameUtils::
ComputeApproximateLengthWithWhitespaceCompression(
optionChild->GetContent(), optionChild->StyleText());
optionChild->GetContent()->AsText(),
optionChild->StyleText());
}
}
}
@ -334,7 +335,7 @@ void nsFontInflationData::ScanTextIn(nsIFrame* aFrame) {
if (content && kid == content->GetPrimaryFrame()) {
uint32_t len = nsTextFrameUtils::
ComputeApproximateLengthWithWhitespaceCompression(
content, kid->StyleText());
content->AsText(), kid->StyleText());
if (len != 0) {
nscoord fontSize = kid->StyleFont()->mFont.size;
if (fontSize > 0) {

View File

@ -676,7 +676,7 @@ void GlyphObserver::NotifyGlyphsChanged() {
int32_t nsTextFrame::GetContentEnd() const {
nsTextFrame* next = GetNextContinuation();
return next ? next->GetContentOffset() : mContent->GetText()->GetLength();
return next ? next->GetContentOffset() : TextFragment()->GetLength();
}
struct FlowLengthProperty {
@ -716,7 +716,7 @@ int32_t nsTextFrame::GetInFlowContentLength() {
nsTextFrame* nextBidi = LastInFlow()->GetNextContinuation();
int32_t endFlow =
nextBidi ? nextBidi->GetContentOffset() : mContent->TextLength();
nextBidi ? nextBidi->GetContentOffset() : GetContent()->TextLength();
if (!flowLength) {
flowLength = new FlowLengthProperty;
@ -1047,7 +1047,7 @@ class BuildTextRunsScanner {
int32_t GetContentEnd() {
return mEndFrame ? mEndFrame->GetContentOffset()
: mStartFrame->GetContent()->GetText()->GetLength();
: mStartFrame->TextFragment()->GetLength();
}
};
@ -1306,7 +1306,7 @@ BuildTextRunsScanner::FindBoundaryResult BuildTextRunsScanner::FindBoundaries(
if (aState->mSeenSpaceForLineBreakingOnThisLine) {
return FB_CONTINUE;
}
const nsTextFragment* frag = textFrame->GetContent()->GetText();
const nsTextFragment* frag = textFrame->TextFragment();
uint32_t start = textFrame->GetContentOffset();
uint32_t length = textFrame->GetContentLength();
const void* text;
@ -1684,7 +1684,7 @@ void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame) {
mMaxTextLength += aFrame->GetContentLength();
}
}
mDoubleByteText |= aFrame->GetContent()->GetText()->Is2b();
mDoubleByteText |= aFrame->TextFragment()->Is2b();
mLastFrame = aFrame;
mCommonAncestorWithLastFrame = aFrame->GetParent();
@ -1705,7 +1705,7 @@ void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame) {
static bool HasTerminalNewline(const nsTextFrame* aFrame) {
if (aFrame->GetContentLength() == 0) return false;
const nsTextFragment* frag = aFrame->GetContent()->GetText();
const nsTextFragment* frag = aFrame->TextFragment();
return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n';
}
@ -2244,7 +2244,7 @@ already_AddRefed<gfxTextRun> BuildTextRunsScanner::BuildTextRunForFrames(
// Figure out what content is included in this flow.
nsIContent* content = f->GetContent();
const nsTextFragment* frag = content->GetText();
const nsTextFragment* frag = f->TextFragment();
int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
int32_t contentEnd = mappedFlow->GetContentEnd();
int32_t contentLength = contentEnd - contentStart;
@ -2523,8 +2523,7 @@ bool BuildTextRunsScanner::SetupLineBreakerContext(gfxTextRun* aTextRun) {
GetCSSWhitespaceToCompressionMode(f, textStyle);
// Figure out what content is included in this flow.
nsIContent* content = f->GetContent();
const nsTextFragment* frag = content->GetText();
const nsTextFragment* frag = f->TextFragment();
int32_t contentStart = mappedFlow->mStartFrame->GetContentOffset();
int32_t contentEnd = mappedFlow->GetContentEnd();
int32_t contentLength = contentEnd - contentStart;
@ -2579,7 +2578,7 @@ static bool HasCompressedLeadingWhitespace(
gfxSkipCharsIterator iter = aIterator;
int32_t frameContentOffset = aFrame->GetContentOffset();
const nsTextFragment* frag = aFrame->GetContent()->GetText();
const nsTextFragment* frag = aFrame->TextFragment();
while (frameContentOffset < aContentEndOffset &&
iter.IsOriginalCharSkipped()) {
if (IsTrimmableSpace(frag, frameContentOffset, aStyleText)) return true;
@ -3188,7 +3187,7 @@ class MOZ_STACK_CLASS PropertyProvider final
mFontGroup(nullptr),
mFontMetrics(aFontMetrics),
mTextStyle(aFrame->StyleText()),
mFrag(aFrame->GetContent()->GetText()),
mFrag(aFrame->TextFragment()),
mLineContainer(nullptr),
mFrame(aFrame),
mStart(aStart),
@ -4768,7 +4767,7 @@ void nsTextFrame::NotifyNativeAnonymousTextnodeChange(uint32_t aOldLength) {
info.mAppend = false;
info.mChangeStart = 0;
info.mChangeEnd = aOldLength;
info.mReplaceLength = mContent->TextLength();
info.mReplaceLength = GetContent()->TextLength();
CharacterDataChanged(info);
}
@ -7066,7 +7065,7 @@ nsIFrame::ContentOffsets nsTextFrame::GetCharacterOffsetAtFramePointInternal(
// ...but don't let selection/insertion-point split two Regional Indicator
// chars that are ligated in the textrun to form a single flag symbol.
uint32_t offs = extraCluster.GetOriginalOffset();
const nsTextFragment* frag = GetContent()->GetText();
const nsTextFragment* frag = TextFragment();
if (offs + 1 < frag->GetLength() &&
NS_IS_HIGH_SURROGATE(frag->CharAt(offs)) &&
NS_IS_LOW_SURROGATE(frag->CharAt(offs + 1)) &&
@ -7483,7 +7482,7 @@ nsIFrame::FrameSearchResult nsTextFrame::PeekOffsetNoAmount(bool aForward,
gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated);
if (!mTextRun) return CONTINUE_EMPTY;
TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText());
TrimmedOffsets trimmed = GetTrimmedOffsets(TextFragment());
// Check whether there are nonskipped characters in the trimmmed range
return (iter.ConvertOriginalToSkipped(trimmed.GetEnd()) >
iter.ConvertOriginalToSkipped(trimmed.mStart))
@ -7544,7 +7543,7 @@ class MOZ_STACK_CLASS ClusterIterator {
static bool IsAcceptableCaretPosition(const gfxSkipCharsIterator& aIter,
bool aRespectClusters,
const gfxTextRun* aTextRun,
nsIFrame* aFrame) {
nsTextFrame* aFrame) {
if (aIter.IsOriginalCharSkipped()) return false;
uint32_t index = aIter.GetSkippedOffset();
if (aRespectClusters && !aTextRun->IsClusterStart(index)) return false;
@ -7556,7 +7555,7 @@ static bool IsAcceptableCaretPosition(const gfxSkipCharsIterator& aIter,
// this far because the low surrogate is also marked as non-clusterStart
// so we'll return FALSE above.)
uint32_t offs = aIter.GetOriginalOffset();
const nsTextFragment* frag = aFrame->GetContent()->GetText();
const nsTextFragment* frag = aFrame->TextFragment();
uint32_t ch = frag->CharAt(offs);
if (gfxFontUtils::IsVarSelector(ch) ||
@ -7608,7 +7607,7 @@ nsIFrame::FrameSearchResult nsTextFrame::PeekOffsetCharacter(
if (!mTextRun) return CONTINUE_EMPTY;
TrimmedOffsets trimmed =
GetTrimmedOffsets(mContent->GetText(), TrimmedOffsetFlags::NoTrimAfter);
GetTrimmedOffsets(TextFragment(), TrimmedOffsetFlags::NoTrimAfter);
// A negative offset means "end of frame".
int32_t startOffset =
@ -7741,7 +7740,7 @@ ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition,
}
mIterator.SetOriginalOffset(aPosition);
mFrag = aTextFrame->GetContent()->GetText();
mFrag = aTextFrame->TextFragment();
mTrimmed = aTextFrame->GetTrimmedOffsets(
mFrag, aTrimSpaces ? nsTextFrame::TrimmedOffsetFlags::Default
: nsTextFrame::TrimmedOffsetFlags::NoTrimAfter |
@ -8049,7 +8048,7 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
// Pass null for the line container. This will disable tab spacing, but that's
// OK since we can't really handle tabs for intrinsic sizing anyway.
const nsStyleText* textStyle = StyleText();
const nsTextFragment* frag = mContent->GetText();
const nsTextFragment* frag = TextFragment();
// If we're hyphenating, the PropertyProvider needs the actual length;
// otherwise we can just pass INT32_MAX to mean "all the text"
@ -8246,7 +8245,7 @@ void nsTextFrame::AddInlinePrefISizeForFlow(
// OK since we can't really handle tabs for intrinsic sizing anyway.
const nsStyleText* textStyle = StyleText();
const nsTextFragment* frag = mContent->GetText();
const nsTextFragment* frag = TextFragment();
PropertyProvider provider(textRun, textStyle, frag, this, iter, INT32_MAX,
nullptr, 0, aTextRunType);
@ -8775,7 +8774,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
uint32_t flowEndInTextRun;
nsIFrame* lineContainer = aLineLayout.LineContainerFrame();
const nsTextFragment* frag = mContent->GetText();
const nsTextFragment* frag = TextFragment();
// DOM offsets of the text range we need to measure, after trimming
// whitespace, restricting to first-letter, and restricting preformatted text
@ -8799,7 +8798,7 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
contentNewLineOffset = cachedNewlineOffset->mNewlineOffset;
} else {
contentNewLineOffset =
FindChar(frag, offset, mContent->TextLength() - offset, '\n');
FindChar(frag, offset, GetContent()->TextLength() - offset, '\n');
}
if (contentNewLineOffset < offset + length) {
/*
@ -9349,7 +9348,7 @@ nsTextFrame::TrimOutput nsTextFrame::TrimTrailingWhiteSpace(
uint32_t trimmedStart = start.GetSkippedOffset();
const nsTextFragment* frag = mContent->GetText();
const nsTextFragment* frag = TextFragment();
TrimmedOffsets trimmed = GetTrimmedOffsets(frag);
gfxSkipCharsIterator trimmedEndIter = start;
const nsStyleText* textStyle = StyleText();
@ -9517,7 +9516,7 @@ nsIFrame::RenderedText nsTextFrame::GetRenderedText(
RenderedText result;
nsBlockFrame* lineContainer = nullptr;
nsTextFrame* textFrame;
const nsTextFragment* textFrag = mContent->GetText();
const nsTextFragment* textFrag = TextFragment();
uint32_t offsetInRenderedString = 0;
bool haveOffsets = false;
@ -9693,9 +9692,9 @@ bool nsTextFrame::IsEmpty() {
return true;
}
bool isEmpty = IsAllWhitespace(
mContent->GetText(),
textStyle->mWhiteSpace != mozilla::StyleWhiteSpace::PreLine);
bool isEmpty =
IsAllWhitespace(TextFragment(), textStyle->mWhiteSpace !=
mozilla::StyleWhiteSpace::PreLine);
AddStateBits(isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE);
return isEmpty;
}
@ -9705,7 +9704,7 @@ bool nsTextFrame::IsEmpty() {
void nsTextFrame::ToCString(nsCString& aBuf,
int32_t* aTotalContentLength) const {
// Get the frames text content
const nsTextFragment* frag = mContent->GetText();
const nsTextFragment* frag = TextFragment();
if (!frag) {
return;
}
@ -9886,7 +9885,7 @@ mozilla::JustificationAssignment nsTextFrame::GetJustificationAssignment()
}
uint32_t nsTextFrame::CountGraphemeClusters() const {
const nsTextFragment* frag = GetContent()->GetText();
const nsTextFragment* frag = TextFragment();
MOZ_ASSERT(frag, "Text frame must have text fragment");
nsAutoString content;
frag->AppendTo(content, GetContentOffset(), GetContentLength());
@ -9906,6 +9905,6 @@ bool nsTextFrame::HasNonSuppressedText() {
}
TrimmedOffsets offsets =
GetTrimmedOffsets(mContent->GetText(), TrimmedOffsetFlags::NoTrimAfter);
GetTrimmedOffsets(TextFragment(), TrimmedOffsetFlags::NoTrimAfter);
return offsets.mLength != 0;
}

View File

@ -11,7 +11,7 @@
#include "mozilla/EventForwards.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/CharacterData.h"
#include "mozilla/dom/Text.h"
#include "nsFrame.h"
#include "nsFrameSelection.h"
#include "nsSplittableFrame.h"
@ -157,6 +157,13 @@ class nsTextFrame : public nsFrame {
void ToCString(nsCString& aBuf, int32_t* aTotalContentLength) const;
#endif
// Returns this text frame's content's text fragment.
//
// Assertions in Init() ensure we only ever get a Text node as content.
const nsTextFragment* TextFragment() const {
return &mContent->AsText()->TextFragment();
}
ContentOffsets CalcContentOffsetsFromFramePoint(const nsPoint& aPoint) final;
ContentOffsets GetCharacterOffsetAtFramePoint(const nsPoint& aPoint);

View File

@ -340,8 +340,8 @@ template bool nsTextFrameUtils::IsSkippableCharacterForTransformText(
char16_t aChar);
uint32_t nsTextFrameUtils::ComputeApproximateLengthWithWhitespaceCompression(
nsIContent* aContent, const nsStyleText* aStyleText) {
const nsTextFragment* frag = aContent->GetText();
Text* aText, const nsStyleText* aStyleText) {
const nsTextFragment* frag = &aText->TextFragment();
// This is an approximation so we don't really need anything
// too fancy here.
uint32_t len;

View File

@ -13,6 +13,12 @@
class nsIContent;
struct nsStyleText;
namespace mozilla {
namespace dom {
class Text;
}
} // namespace mozilla
#define BIG_TEXT_NODE_SIZE 4096
#define CH_NBSP 160
@ -133,7 +139,7 @@ class nsTextFrameUtils {
}
static uint32_t ComputeApproximateLengthWithWhitespaceCompression(
nsIContent* aContent, const nsStyleText* aStyleText);
mozilla::dom::Text* aText, const nsStyleText* aStyleText);
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrameUtils::Flags)

View File

@ -980,7 +980,7 @@ void TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge,
// white space, as the nsTextFrame when painting does not include them when
// interpreting clip edges.
nsTextFrame::TrimmedOffsets trimmedOffsets =
mFrame->GetTrimmedOffsets(mFrame->GetContent()->GetText());
mFrame->GetTrimmedOffsets(mFrame->TextFragment());
TrimOffsets(frameOffset, frameLength, trimmedOffsets);
// Convert the trimmed whole-nsTextFrame offset/length into skipped
@ -1885,7 +1885,7 @@ TextRenderedRun TextRenderedRunIterator::Next() {
uint32_t untrimmedOffset = offset;
uint32_t untrimmedLength = length;
nsTextFrame::TrimmedOffsets trimmedOffsets =
frame->GetTrimmedOffsets(frame->GetContent()->GetText());
frame->GetTrimmedOffsets(frame->TextFragment());
TrimOffsets(offset, length, trimmedOffsets);
charIndex += offset - untrimmedOffset;
@ -2364,9 +2364,8 @@ bool CharIterator::IsOriginalCharTrimmed() const {
mFrameForTrimCheck = TextFrame();
uint32_t offset = mFrameForTrimCheck->GetContentOffset();
uint32_t length = mFrameForTrimCheck->GetContentLength();
nsIContent* content = mFrameForTrimCheck->GetContent();
nsTextFrame::TrimmedOffsets trim = mFrameForTrimCheck->GetTrimmedOffsets(
content->GetText(),
mFrameForTrimCheck->TextFragment(),
(mPostReflow ? nsTextFrame::TrimmedOffsetFlags::Default
: nsTextFrame::TrimmedOffsetFlags::NotPostReflow));
TrimOffsets(offset, length, trim);
@ -2382,7 +2381,7 @@ bool CharIterator::IsOriginalCharTrimmed() const {
(index >= mTrimmedOffset + mTrimmedLength &&
mFrameForTrimCheck->StyleText()->NewlineIsSignificant(
mFrameForTrimCheck) &&
mFrameForTrimCheck->GetContent()->GetText()->CharAt(index) == '\n'));
mFrameForTrimCheck->TextFragment()->CharAt(index) == '\n'));
}
void CharIterator::GetOriginalGlyphOffsets(uint32_t& aOriginalOffset,
@ -3804,8 +3803,7 @@ nsresult SVGTextFrame::GetSubStringLength(nsIContent* aContent,
uint32_t trimmedOffset = untrimmedOffset;
uint32_t trimmedLength = untrimmedLength;
nsTextFrame::TrimmedOffsets trimmedOffsets = frame->GetTrimmedOffsets(
frame->GetContent()->GetText(),
nsTextFrame::TrimmedOffsetFlags::NotPostReflow);
frame->TextFragment(), nsTextFrame::TrimmedOffsetFlags::NotPostReflow);
TrimOffsets(trimmedOffset, trimmedLength, trimmedOffsets);
textElementCharIndex += trimmedOffset - untrimmedOffset;
@ -4414,7 +4412,7 @@ void SVGTextFrame::DetermineCharPositions(nsTArray<nsPoint>& aPositions) {
// Any white space characters trimmed at the start of the line of text.
nsTextFrame::TrimmedOffsets trimmedOffsets =
frame->GetTrimmedOffsets(frame->GetContent()->GetText());
frame->GetTrimmedOffsets(frame->TextFragment());
while (it.GetOriginalOffset() < trimmedOffsets.mStart) {
aPositions.AppendElement(position);
it.AdvanceOriginal(1);