mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-06-01 11:39:27 +00:00
Actually provide an implementation for GetRenderedtext()
This commit is contained in:
+122
-58
@@ -3936,9 +3936,8 @@ a11y::AccType
|
||||
nsTextFrame::AccessibleType()
|
||||
{
|
||||
if (IsEmpty()) {
|
||||
nsAutoString renderedWhitespace;
|
||||
GetRenderedText(&renderedWhitespace, nullptr, nullptr, 0, 1);
|
||||
if (renderedWhitespace.IsEmpty()) {
|
||||
RenderedText text = GetRenderedText();
|
||||
if (text.mString.IsEmpty()) {
|
||||
return a11y::eNoType;
|
||||
}
|
||||
}
|
||||
@@ -4051,13 +4050,6 @@ public:
|
||||
virtual void AddInlinePrefISize(nsRenderingContext *aRenderingContext,
|
||||
InlinePrefISizeData *aData) override;
|
||||
|
||||
virtual nsresult GetRenderedText(nsAString* aString = nullptr,
|
||||
gfxSkipChars* aSkipChars = nullptr,
|
||||
gfxSkipCharsIterator* aSkipIter = nullptr,
|
||||
uint32_t aSkippedStartOffset = 0,
|
||||
uint32_t aSkippedMaxLength = UINT32_MAX) override
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; } // Call on a primary text frame only
|
||||
|
||||
protected:
|
||||
explicit nsContinuingTextFrame(nsStyleContext* aContext) : nsTextFrame(aContext) {}
|
||||
nsIFrame* mPrevContinuation;
|
||||
@@ -8750,79 +8742,151 @@ static char16_t TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
||||
return aChar;
|
||||
}
|
||||
|
||||
nsresult nsTextFrame::GetRenderedText(nsAString* aAppendToString,
|
||||
gfxSkipChars* aSkipChars,
|
||||
gfxSkipCharsIterator* aSkipIter,
|
||||
uint32_t aSkippedStartOffset,
|
||||
uint32_t aSkippedMaxLength)
|
||||
static bool
|
||||
LineEndsInHardLineBreak(nsTextFrame* aFrame)
|
||||
{
|
||||
// The handling of aSkippedStartOffset and aSkippedMaxLength could be more efficient...
|
||||
gfxSkipChars skipChars;
|
||||
nsIFrame* lineContainer = FindLineContainer(aFrame);
|
||||
nsBlockFrame* block = do_QueryFrame(lineContainer);
|
||||
if (!block) {
|
||||
// Weird situation where we have a line layout without a block.
|
||||
// No soft breaks occur in this situation.
|
||||
return true;
|
||||
}
|
||||
bool foundValidLine;
|
||||
nsBlockInFlowLineIterator iter(block, aFrame, &foundValidLine);
|
||||
if (!foundValidLine) {
|
||||
NS_ERROR("Invalid line!");
|
||||
return true;
|
||||
}
|
||||
return !iter.GetLine()->IsLineWrapped();
|
||||
}
|
||||
|
||||
nsIFrame::RenderedText
|
||||
nsTextFrame::GetRenderedText(uint32_t aStartOffset,
|
||||
uint32_t aEndOffset,
|
||||
TextOffsetType aOffsetType)
|
||||
{
|
||||
NS_ASSERTION(!GetPrevContinuation(), "Must be called on first-in-flow");
|
||||
|
||||
// The handling of offsets could be more efficient...
|
||||
RenderedText result;
|
||||
nsTextFrame* textFrame;
|
||||
const nsTextFragment* textFrag = mContent->GetText();
|
||||
uint32_t keptCharsLength = 0;
|
||||
uint32_t validCharsLength = 0;
|
||||
uint32_t offsetInRenderedString = 0;
|
||||
bool haveOffsets = false;
|
||||
|
||||
// Build skipChars and copy text, for each text frame in this continuation block
|
||||
for (textFrame = this; textFrame;
|
||||
textFrame = static_cast<nsTextFrame*>(textFrame->GetNextContinuation())) {
|
||||
// For each text frame continuation in this block ...
|
||||
|
||||
if (textFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
|
||||
// We don't trust dirty frames, expecially when computing rendered text.
|
||||
// We don't trust dirty frames, especially when computing rendered text.
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure the text run and grab the gfxSkipCharsIterator for it
|
||||
gfxSkipCharsIterator iter =
|
||||
textFrame->EnsureTextRun(nsTextFrame::eInflated);
|
||||
if (!textFrame->mTextRun)
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!textFrame->mTextRun) {
|
||||
break;
|
||||
}
|
||||
gfxSkipCharsIterator tmpIter = iter;
|
||||
|
||||
// Skip to the start of the text run, past ignored chars at start of line
|
||||
// XXX In the future we may decide to trim extra spaces before a hard line
|
||||
// break, in which case we need to accurately detect those sitations and
|
||||
// call GetTrimmedOffsets() with true to trim whitespace at the line's end
|
||||
TrimmedOffsets trimmedContentOffsets = textFrame->GetTrimmedOffsets(textFrag, false);
|
||||
int32_t startOfLineSkipChars = trimmedContentOffsets.mStart - textFrame->mContentOffset;
|
||||
if (startOfLineSkipChars > 0) {
|
||||
skipChars.SkipChars(startOfLineSkipChars);
|
||||
iter.SetOriginalOffset(trimmedContentOffsets.mStart);
|
||||
TrimmedOffsets trimmedOffsets = textFrame->GetTrimmedOffsets(textFrag,
|
||||
textFrame->IsAtEndOfLine() && LineEndsInHardLineBreak(textFrame));
|
||||
bool trimmedSignificantNewline =
|
||||
trimmedOffsets.GetEnd() < GetContentEnd() &&
|
||||
HasSignificantTerminalNewline();
|
||||
uint32_t skippedToRenderedStringOffset = offsetInRenderedString -
|
||||
tmpIter.ConvertOriginalToSkipped(trimmedOffsets.mStart);
|
||||
uint32_t nextOffsetInRenderedString =
|
||||
tmpIter.ConvertOriginalToSkipped(trimmedOffsets.GetEnd()) +
|
||||
(trimmedSignificantNewline ? 1 : 0) + skippedToRenderedStringOffset;
|
||||
|
||||
if (aOffsetType == TextOffsetType::OFFSETS_IN_RENDERED_TEXT) {
|
||||
if (nextOffsetInRenderedString <= aStartOffset) {
|
||||
offsetInRenderedString = nextOffsetInRenderedString;
|
||||
continue;
|
||||
}
|
||||
if (!haveOffsets) {
|
||||
result.mOffsetWithinNodeText =
|
||||
tmpIter.ConvertSkippedToOriginal(aStartOffset - skippedToRenderedStringOffset);
|
||||
result.mOffsetWithinNodeRenderedText = aStartOffset;
|
||||
haveOffsets = true;
|
||||
}
|
||||
if (offsetInRenderedString >= aEndOffset) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (uint32_t(textFrame->GetContentEnd()) <= aStartOffset) {
|
||||
offsetInRenderedString = nextOffsetInRenderedString;
|
||||
continue;
|
||||
}
|
||||
if (!haveOffsets) {
|
||||
result.mOffsetWithinNodeText = aStartOffset;
|
||||
// Skip trimmed space when computed the rendered text offset.
|
||||
int32_t clamped = std::max<int32_t>(aStartOffset, trimmedOffsets.mStart);
|
||||
result.mOffsetWithinNodeRenderedText =
|
||||
tmpIter.ConvertOriginalToSkipped(clamped) + skippedToRenderedStringOffset;
|
||||
MOZ_ASSERT(result.mOffsetWithinNodeRenderedText >= offsetInRenderedString &&
|
||||
result.mOffsetWithinNodeRenderedText <= INT32_MAX,
|
||||
"Bad offset within rendered text");
|
||||
haveOffsets = true;
|
||||
}
|
||||
if (uint32_t(textFrame->mContentOffset) >= aEndOffset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t startOffset;
|
||||
int32_t endOffset;
|
||||
if (aOffsetType == TextOffsetType::OFFSETS_IN_RENDERED_TEXT) {
|
||||
startOffset =
|
||||
tmpIter.ConvertSkippedToOriginal(aStartOffset - skippedToRenderedStringOffset);
|
||||
endOffset =
|
||||
tmpIter.ConvertSkippedToOriginal(aEndOffset - skippedToRenderedStringOffset);
|
||||
} else {
|
||||
startOffset = aStartOffset;
|
||||
endOffset = std::min<uint32_t>(INT32_MAX, aEndOffset);
|
||||
}
|
||||
trimmedOffsets.mStart = std::max<uint32_t>(trimmedOffsets.mStart,
|
||||
startOffset);
|
||||
trimmedOffsets.mLength = std::min<uint32_t>(trimmedOffsets.GetEnd(),
|
||||
endOffset) - trimmedOffsets.mStart;
|
||||
if (trimmedOffsets.mLength <= 0) {
|
||||
offsetInRenderedString = nextOffsetInRenderedString;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Keep and copy the appropriate chars withing the caller's requested range
|
||||
const nsStyleText* textStyle = textFrame->StyleText();
|
||||
while (iter.GetOriginalOffset() < trimmedContentOffsets.GetEnd() &&
|
||||
keptCharsLength < aSkippedMaxLength) {
|
||||
// For each original char from content text
|
||||
if (iter.IsOriginalCharSkipped() || ++validCharsLength <= aSkippedStartOffset) {
|
||||
skipChars.SkipChar();
|
||||
} else {
|
||||
++keptCharsLength;
|
||||
skipChars.KeepChar();
|
||||
if (aAppendToString) {
|
||||
aAppendToString->Append(
|
||||
TransformChar(textStyle, textFrame->mTextRun, iter.GetSkippedOffset(),
|
||||
textFrag->CharAt(iter.GetOriginalOffset())));
|
||||
iter.SetOriginalOffset(trimmedOffsets.mStart);
|
||||
while (iter.GetOriginalOffset() < trimmedOffsets.GetEnd()) {
|
||||
char16_t ch = textFrag->CharAt(iter.GetOriginalOffset());
|
||||
if (iter.IsOriginalCharSkipped()) {
|
||||
if (ch == CH_SHY) {
|
||||
// We should preserve soft hyphens. They can't be transformed.
|
||||
result.mString.Append(ch);
|
||||
}
|
||||
} else {
|
||||
result.mString.Append(
|
||||
TransformChar(textStyle, textFrame->mTextRun,
|
||||
iter.GetSkippedOffset(), ch));
|
||||
}
|
||||
iter.AdvanceOriginal(1);
|
||||
}
|
||||
if (keptCharsLength >= aSkippedMaxLength) {
|
||||
break; // Already past the end, don't build string or gfxSkipCharsIter anymore
|
||||
}
|
||||
}
|
||||
|
||||
if (aSkipChars) {
|
||||
aSkipChars->TakeFrom(&skipChars); // Copy skipChars into aSkipChars
|
||||
if (aSkipIter) {
|
||||
// Caller must provide both pointers in order to retrieve a gfxSkipCharsIterator,
|
||||
// because the gfxSkipCharsIterator holds a weak pointer to the gfxSkipChars.
|
||||
*aSkipIter = gfxSkipCharsIterator(*aSkipChars, GetContentLength());
|
||||
|
||||
if (trimmedSignificantNewline && GetContentEnd() <= endOffset) {
|
||||
// A significant newline was trimmed off (we must be
|
||||
// white-space:pre-line). Put it back.
|
||||
result.mString.Append('\n');
|
||||
}
|
||||
offsetInRenderedString = nextOffsetInRenderedString;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
if (!haveOffsets) {
|
||||
result.mOffsetWithinNodeText = textFrag->GetLength();
|
||||
result.mOffsetWithinNodeRenderedText = offsetInRenderedString;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsIAtom*
|
||||
|
||||
Reference in New Issue
Block a user