From 0c0641a63e670967f3641aff3af4388c1c39ba88 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 22 Feb 2019 16:44:49 +0100 Subject: [PATCH] Fix reading word-by-word from Orca --- .../patches-60/text-at-offset-word | 764 ++++++++++++++++++ firefox-patches/series-60 | 1 + firefox-patches/version | 2 +- 3 files changed, 766 insertions(+), 1 deletion(-) create mode 100644 firefox-patches/patches-60/text-at-offset-word diff --git a/firefox-patches/patches-60/text-at-offset-word b/firefox-patches/patches-60/text-at-offset-word new file mode 100644 index 0000000..c75611d --- /dev/null +++ b/firefox-patches/patches-60/text-at-offset-word @@ -0,0 +1,764 @@ +Fix reading word-by-word from Orca + +# HG changeset patch +# User Samuel Thibault +# Date 1550588324 -3600 +# Tue Feb 19 15:58:44 2019 +0100 +# Branch trim-offset +# Node ID fbdb5d7ff36319d91c9063ea66b778ff72e51ff1 +# Parent dd4aa59c6a1271cbf6ca10813d73f62e7cb072d5 +nsTextFrame::GetTrimmedOffsets: Rework flag parameters r=jfkthame + +diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp +--- a/layout/generic/nsTextFrame.cpp ++++ b/layout/generic/nsTextFrame.cpp +@@ -2941,19 +2941,19 @@ static uint32_t GetEndOfTrimmedText(cons + aIterator->AdvanceSkipped(-1); + if (!IsTrimmableSpace(aFrag, aIterator->GetOriginalOffset(), aStyleText)) + return aIterator->GetSkippedOffset() + 1; + } + return aStart; + } + + nsTextFrame::TrimmedOffsets nsTextFrame::GetTrimmedOffsets( +- const nsTextFragment* aFrag, bool aTrimAfter, bool aPostReflow) const { ++ const nsTextFragment* aFrag, TrimmedOffsetFlags aFlags) const { + NS_ASSERTION(mTextRun, "Need textrun here"); +- if (aPostReflow) { ++ if (!(aFlags & TrimmedOffsetFlags::kNoPostReflow)) { + // This should not be used during reflow. We need our TEXT_REFLOW_FLAGS + // to be set correctly. If our parent wasn't reflowed due to the frame + // tree being too deep then the return value doesn't matter. + NS_ASSERTION( + !(GetStateBits() & NS_FRAME_FIRST_REFLOW) || + (GetParent()->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE), + "Can only call this on frames that have been reflowed"); + NS_ASSERTION(!(GetStateBits() & NS_FRAME_IN_REFLOW), +@@ -2961,24 +2961,27 @@ nsTextFrame::TrimmedOffsets nsTextFrame: + } + + TrimmedOffsets offsets = {GetContentOffset(), GetContentLength()}; + const nsStyleText* textStyle = StyleText(); + // Note that pre-line newlines should still allow us to trim spaces + // for display + if (textStyle->WhiteSpaceIsSignificant()) return offsets; + +- if (!aPostReflow || (GetStateBits() & TEXT_START_OF_LINE)) { ++ if ((aFlags & TrimmedOffsetFlags::kNoPostReflow) || ++ (GetStateBits() & TEXT_START_OF_LINE)) { + int32_t whitespaceCount = + GetTrimmableWhitespaceCount(aFrag, offsets.mStart, offsets.mLength, 1); + offsets.mStart += whitespaceCount; + offsets.mLength -= whitespaceCount; + } + +- if (aTrimAfter && (!aPostReflow || (GetStateBits() & TEXT_END_OF_LINE))) { ++ if (!(aFlags & TrimmedOffsetFlags::kNoTrimAfter) && ++ ((aFlags & TrimmedOffsetFlags::kNoPostReflow) || ++ (GetStateBits() & TEXT_END_OF_LINE))) { + // This treats a trailing 'pre-line' newline as trimmable. That's fine, + // it's actually what we want since we want whitespace before it to + // be trimmed. + int32_t whitespaceCount = GetTrimmableWhitespaceCount( + aFrag, offsets.GetEnd() - 1, offsets.mLength, -1); + offsets.mLength -= whitespaceCount; + } + return offsets; +@@ -3706,25 +3709,28 @@ void PropertyProvider::GetHyphenationBre + aBreakBefore[i] = HyphenType::AutoWithoutManualInSameWord; + } + } + } + } + + void PropertyProvider::InitializeForDisplay(bool aTrimAfter) { + nsTextFrame::TrimmedOffsets trimmed = +- mFrame->GetTrimmedOffsets(mFrag, aTrimAfter); ++ mFrame->GetTrimmedOffsets(mFrag, ++ (aTrimAfter ? nsTextFrame::TrimmedOffsetFlags::kDefaultTrimFlags : ++ nsTextFrame::TrimmedOffsetFlags::kNoTrimAfter)); + mStart.SetOriginalOffset(trimmed.mStart); + mLength = trimmed.mLength; + SetupJustificationSpacing(true); + } + + void PropertyProvider::InitializeForMeasure() { + nsTextFrame::TrimmedOffsets trimmed = +- mFrame->GetTrimmedOffsets(mFrag, true, false); ++ mFrame->GetTrimmedOffsets(mFrag, ++ nsTextFrame::TrimmedOffsetFlags::kNoPostReflow); + mStart.SetOriginalOffset(trimmed.mStart); + mLength = trimmed.mLength; + SetupJustificationSpacing(false); + } + + void PropertyProvider::SetupJustificationSpacing(bool aPostReflow) { + MOZ_ASSERT(mLength != INT32_MAX, "Can't call this with undefined length"); + +@@ -3732,17 +3738,19 @@ void PropertyProvider::SetupJustificatio + return; + } + + gfxSkipCharsIterator start(mStart), end(mStart); + // We can't just use our mLength here; when InitializeForDisplay is + // called with false for aTrimAfter, we still shouldn't be assigning + // justification space to any trailing whitespace. + nsTextFrame::TrimmedOffsets trimmed = +- mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow); ++ mFrame->GetTrimmedOffsets(mFrag, ++ (aPostReflow ? nsTextFrame::TrimmedOffsetFlags::kDefaultTrimFlags : ++ nsTextFrame::TrimmedOffsetFlags::kNoPostReflow)); + end.AdvanceOriginal(trimmed.mLength); + gfxSkipCharsIterator realEnd(end); + + Range range(uint32_t(start.GetOriginalOffset()), + uint32_t(end.GetOriginalOffset())); + nsTArray assignments; + JustificationInfo info = ComputeJustification(range, &assignments); + +@@ -7698,17 +7706,17 @@ nsresult nsTextFrame::GetChildFrameConta + nsIFrame::FrameSearchResult nsTextFrame::PeekOffsetNoAmount(bool aForward, + int32_t* aOffset) { + NS_ASSERTION(aOffset && *aOffset <= GetContentLength(), + "aOffset out of range"); + + gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated); + if (!mTextRun) return CONTINUE_EMPTY; + +- TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), true); ++ TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText()); + // Check whether there are nonskipped characters in the trimmmed range + return (iter.ConvertOriginalToSkipped(trimmed.GetEnd()) > + iter.ConvertOriginalToSkipped(trimmed.mStart)) + ? FOUND + : CONTINUE; + } + + /** +@@ -7821,17 +7829,18 @@ nsIFrame::FrameSearchResult nsTextFrame: + if (selectStyle == StyleUserSelect::All) { + return CONTINUE_UNSELECTABLE; + } + } + + gfxSkipCharsIterator iter = EnsureTextRun(nsTextFrame::eInflated); + if (!mTextRun) return CONTINUE_EMPTY; + +- TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), false); ++ TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), ++ TrimmedOffsetFlags::kNoTrimAfter); + + // A negative offset means "end of frame". + int32_t startOffset = + GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); + + if (!aForward) { + // If at the beginning of the line, look at the previous continuation + for (int32_t i = std::min(trimmed.GetEnd(), startOffset) - 1; +@@ -7954,17 +7963,17 @@ ClusterIterator::ClusterIterator(nsTextF + mIterator = aTextFrame->EnsureTextRun(nsTextFrame::eInflated); + if (!aTextFrame->GetTextRun(nsTextFrame::eInflated)) { + mDirection = 0; // signal failure + return; + } + mIterator.SetOriginalOffset(aPosition); + + mFrag = aTextFrame->GetContent()->GetText(); +- mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag, true); ++ mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag); + + int32_t textOffset = aTextFrame->GetContentOffset(); + int32_t textLen = aTextFrame->GetContentLength(); + if (!mWordBreaks.AppendElements(textLen + 1)) { + mDirection = 0; // signal failure + return; + } + memset(mWordBreaks.Elements(), false, (textLen + 1) * sizeof(bool)); +@@ -9556,17 +9565,17 @@ nsTextFrame::TrimOutput nsTextFrame::Tri + + gfxSkipCharsIterator start = + EnsureTextRun(nsTextFrame::eInflated, aDrawTarget); + NS_ENSURE_TRUE(mTextRun, result); + + uint32_t trimmedStart = start.GetSkippedOffset(); + + const nsTextFragment* frag = mContent->GetText(); +- TrimmedOffsets trimmed = GetTrimmedOffsets(frag, true); ++ TrimmedOffsets trimmed = GetTrimmedOffsets(frag); + gfxSkipCharsIterator trimmedEndIter = start; + const nsStyleText* textStyle = StyleText(); + gfxFloat delta = 0; + uint32_t trimmedEnd = + trimmedEndIter.ConvertOriginalToSkipped(trimmed.GetEnd()); + + if (!(GetStateBits() & TEXT_TRIMMED_TRAILING_WHITESPACE) && + trimmed.GetEnd() < GetContentEnd()) { +@@ -9762,17 +9771,19 @@ nsIFrame::RenderedText nsTextFrame::GetR + } else { + // Weird situation where we have a line layout without a block. + // No soft breaks occur in this situation. + trimAfter = true; + } + + // Skip to the start of the text run, past ignored chars at start of line + TrimmedOffsets trimmedOffsets = +- textFrame->GetTrimmedOffsets(textFrag, trimAfter); ++ textFrame->GetTrimmedOffsets(textFrag, ++ (trimAfter ? TrimmedOffsetFlags::kDefaultTrimFlags : ++ TrimmedOffsetFlags::kNoTrimAfter)); + bool trimmedSignificantNewline = + trimmedOffsets.GetEnd() < GetContentEnd() && + HasSignificantTerminalNewline(); + uint32_t skippedToRenderedStringOffset = + offsetInRenderedString - + tmpIter.ConvertOriginalToSkipped(trimmedOffsets.mStart); + uint32_t nextOffsetInRenderedString = + tmpIter.ConvertOriginalToSkipped(trimmedOffsets.GetEnd()) + +@@ -10101,11 +10112,12 @@ bool nsTextFrame::HasNonSuppressedText() + NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW)) { + return true; + } + + if (!GetTextRun(nsTextFrame::eInflated)) { + return false; + } + +- TrimmedOffsets offsets = GetTrimmedOffsets(mContent->GetText(), false); ++ TrimmedOffsets offsets = GetTrimmedOffsets(mContent->GetText(), ++ TrimmedOffsetFlags::kNoTrimAfter); + return offsets.mLength != 0; + } +diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h +--- a/layout/generic/nsTextFrame.h ++++ b/layout/generic/nsTextFrame.h +@@ -568,18 +568,23 @@ class nsTextFrame : public nsFrame { + // Get the DOM content range mapped by this frame after excluding + // whitespace subject to start-of-line and end-of-line trimming. + // The textrun must have been created before calling this. + struct TrimmedOffsets { + int32_t mStart; + int32_t mLength; + int32_t GetEnd() const { return mStart + mLength; } + }; +- TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, bool aTrimAfter, +- bool aPostReflow = true) const; ++ enum class TrimmedOffsetFlags : uint8_t { ++ kDefaultTrimFlags = 0, ++ kNoPostReflow = 1 << 0, ++ kNoTrimAfter = 1 << 1 ++ }; ++ TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, ++ TrimmedOffsetFlags aFlags = TrimmedOffsetFlags::kDefaultTrimFlags) const; + + // Similar to Reflow(), but for use from nsLineLayout + void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, + DrawTarget* aDrawTarget, ReflowOutput& aMetrics, + nsReflowStatus& aStatus); + + bool IsFloatingFirstLetterChild() const; + +@@ -801,9 +806,11 @@ class nsTextFrame : public nsFrame { + void UpdateIteratorFromOffset(const PropertyProvider& aProperties, + int32_t& aInOffset, + gfxSkipCharsIterator& aIter); + + nsPoint GetPointFromIterator(const gfxSkipCharsIterator& aIter, + PropertyProvider& aProperties); + }; + ++MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsTextFrame::TrimmedOffsetFlags) ++ + #endif +diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp +--- a/layout/svg/SVGTextFrame.cpp ++++ b/layout/svg/SVGTextFrame.cpp +@@ -979,17 +979,17 @@ void TextRenderedRun::GetClipEdges(nscoo + // Get the offset/length of the whole nsTextFrame. + uint32_t frameOffset = mFrame->GetContentOffset(); + uint32_t frameLength = mFrame->GetContentLength(); + + // Trim the whole-nsTextFrame offset/length to remove any leading/trailing + // white space, as the nsTextFrame when painting does not include them when + // interpreting clip edges. + nsTextFrame::TrimmedOffsets trimmedOffsets = +- mFrame->GetTrimmedOffsets(mFrame->GetContent()->GetText(), true); ++ mFrame->GetTrimmedOffsets(mFrame->GetContent()->GetText()); + TrimOffsets(frameOffset, frameLength, trimmedOffsets); + + // Convert the trimmed whole-nsTextFrame offset/length into skipped + // characters. + Range frameRange = ConvertOriginalToSkipped(it, frameOffset, frameLength); + + // Measure the advance width in the text run between the start of + // frame's content and the start of the rendered run's content, +@@ -1884,17 +1884,17 @@ TextRenderedRun TextRenderedRunIterator: + baseline = GetBaselinePosition( + frame, frame->GetTextRun(nsTextFrame::eInflated), + mFrameIterator.DominantBaseline(), mFontSizeScaleFactor); + + // Trim the offset/length to remove any leading/trailing white space. + uint32_t untrimmedOffset = offset; + uint32_t untrimmedLength = length; + nsTextFrame::TrimmedOffsets trimmedOffsets = +- frame->GetTrimmedOffsets(frame->GetContent()->GetText(), true); ++ frame->GetTrimmedOffsets(frame->GetContent()->GetText()); + TrimOffsets(offset, length, trimmedOffsets); + charIndex += offset - untrimmedOffset; + + // Get the position and rotation of the character that begins this + // rendered run. + pt = Root()->mPositions[charIndex].mPosition; + rotate = Root()->mPositions[charIndex].mAngle; + +@@ -2366,17 +2366,18 @@ bool CharIterator::IsOriginalCharTrimmed + // Since we do a lot of trim checking, we cache the trimmed offsets and + // lengths while we are in the same frame. + mFrameForTrimCheck = TextFrame(); + uint32_t offset = mFrameForTrimCheck->GetContentOffset(); + uint32_t length = mFrameForTrimCheck->GetContentLength(); + nsIContent* content = mFrameForTrimCheck->GetContent(); + nsTextFrame::TrimmedOffsets trim = mFrameForTrimCheck->GetTrimmedOffsets( + content->GetText(), +- /* aTrimAfter */ true, mPostReflow); ++ (mPostReflow ? nsTextFrame::TrimmedOffsetFlags::kDefaultTrimFlags : ++ nsTextFrame::TrimmedOffsetFlags::kNoPostReflow)); + TrimOffsets(offset, length, trim); + mTrimmedOffset = offset; + mTrimmedLength = length; + } + + // A character is trimmed if it is outside the mTrimmedOffset/mTrimmedLength + // range and it is not a significant newline character. + uint32_t index = mSkipCharsIterator.GetOriginalOffset(); +@@ -3818,18 +3819,17 @@ nsresult SVGTextFrame::GetSubStringLengt + const uint32_t untrimmedOffset = frame->GetContentOffset(); + const uint32_t untrimmedLength = frame->GetContentEnd() - untrimmedOffset; + + // Trim the offset/length to remove any leading/trailing white space. + uint32_t trimmedOffset = untrimmedOffset; + uint32_t trimmedLength = untrimmedLength; + nsTextFrame::TrimmedOffsets trimmedOffsets = + frame->GetTrimmedOffsets(frame->GetContent()->GetText(), +- /* aTrimAfter */ true, +- /* aPostReflow */ false); ++ nsTextFrame::TrimmedOffsetFlags::kNoPostReflow); + TrimOffsets(trimmedOffset, trimmedLength, trimmedOffsets); + + textElementCharIndex += trimmedOffset - untrimmedOffset; + + if (textElementCharIndex >= charnum + nchars) { + break; // we're past the end of the substring + } + +@@ -4427,17 +4427,17 @@ void SVGTextFrame::DetermineCharPosition + + // Any characters not in a frame, e.g. when display:none. + for (uint32_t i = 0; i < frit.UndisplayedCharacters(); i++) { + aPositions.AppendElement(position); + } + + // Any white space characters trimmed at the start of the line of text. + nsTextFrame::TrimmedOffsets trimmedOffsets = +- frame->GetTrimmedOffsets(frame->GetContent()->GetText(), true); ++ frame->GetTrimmedOffsets(frame->GetContent()->GetText()); + while (it.GetOriginalOffset() < trimmedOffsets.mStart) { + aPositions.AppendElement(position); + it.AdvanceOriginal(1); + } + + // If a ligature was started in the previous frame, we should record + // the ligature's start position, not any partial position. + while (it.GetOriginalOffset() < frame->GetContentEnd() && + +# HG changeset patch +# User Samuel Thibault +# Date 1550767631 -3600 +# Thu Feb 21 17:47:11 2019 +0100 +# Branch trim-offset2 +# Node ID bf487fadc54796a6559570e9fdafd746a863f76e +# Parent fbdb5d7ff36319d91c9063ea66b778ff72e51ff1 +Bug 919508 layout: Do not trim spaces when inspected from accessibility layer r=jfkthame + +diff --git a/accessible/generic/HyperTextAccessible.cpp b/accessible/generic/HyperTextAccessible.cpp +--- a/accessible/generic/HyperTextAccessible.cpp ++++ b/accessible/generic/HyperTextAccessible.cpp +@@ -514,17 +514,17 @@ uint32_t HyperTextAccessible::FindOffset + + const bool kIsJumpLinesOk = true; // okay to jump lines + const bool kIsScrollViewAStop = false; // do not stop at scroll views + const bool kIsKeyboardSelect = true; // is keyboard selection + const bool kIsVisualBidi = false; // use visual order for bidi text + nsPeekOffsetStruct pos( + aAmount, aDirection, innerContentOffset, nsPoint(0, 0), kIsJumpLinesOk, + kIsScrollViewAStop, kIsKeyboardSelect, kIsVisualBidi, false, +- nsPeekOffsetStruct::ForceEditableRegion::No, aWordMovementType); ++ nsPeekOffsetStruct::ForceEditableRegion::No, aWordMovementType, false); + nsresult rv = frameAtOffset->PeekOffset(&pos); + + // PeekOffset fails on last/first lines of the text in certain cases. + if (NS_FAILED(rv) && aAmount == eSelectLine) { + pos.mAmount = (aDirection == eDirNext) ? eSelectEndLine : eSelectBeginLine; + frameAtOffset->PeekOffset(&pos); + } + if (!pos.mResultContent) { +diff --git a/layout/generic/BRFrame.cpp b/layout/generic/BRFrame.cpp +--- a/layout/generic/BRFrame.cpp ++++ b/layout/generic/BRFrame.cpp +@@ -40,17 +40,18 @@ class BRFrame final : public nsFrame { + virtual FrameSearchResult PeekOffsetCharacter( + bool aForward, int32_t* aOffset, + PeekOffsetCharacterOptions aOptions = + PeekOffsetCharacterOptions()) override; + virtual FrameSearchResult PeekOffsetWord(bool aForward, + bool aWordSelectEatSpace, + bool aIsKeyboardSelect, + int32_t* aOffset, +- PeekWordState* aState) override; ++ PeekWordState* aState, ++ bool aTrimSpaces) override; + + virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + virtual void AddInlineMinISize(gfxContext* aRenderingContext, + InlineMinISizeData* aData) override; + virtual void AddInlinePrefISize(gfxContext* aRenderingContext, + InlinePrefISizeData* aData) override; +@@ -233,17 +234,18 @@ nsIFrame::FrameSearchResult BRFrame::Pee + // Keep going. The actual line jumping will stop us. + return CONTINUE; + } + + nsIFrame::FrameSearchResult BRFrame::PeekOffsetWord(bool aForward, + bool aWordSelectEatSpace, + bool aIsKeyboardSelect, + int32_t* aOffset, +- PeekWordState* aState) { ++ PeekWordState* aState, ++ bool aTrimSpaces) { + NS_ASSERTION(aOffset && *aOffset <= 1, "aOffset out of range"); + // Keep going. The actual line jumping will stop us. + return CONTINUE; + } + + #ifdef ACCESSIBILITY + a11y::AccType BRFrame::AccessibleType() { + nsIContent* parent = mContent->GetParent(); +diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp +--- a/layout/generic/nsFrame.cpp ++++ b/layout/generic/nsFrame.cpp +@@ -8135,17 +8135,18 @@ nsresult nsIFrame::PeekOffset(nsPeekOffs + int32_t offsetAdjustment = 0; + bool done = false; + while (!done) { + bool movingInFrameDirection = + IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual); + + done = current->PeekOffsetWord( + movingInFrameDirection, wordSelectEatSpace, +- aPos->mIsKeyboardSelect, &offset, &state) == FOUND; ++ aPos->mIsKeyboardSelect, &offset, &state, ++ aPos->mTrimSpaces) == FOUND; + + if (!done) { + nsIFrame* nextFrame; + int32_t nextFrameOffset; + bool jumpedLine, movedOverNonSelectableText; + result = current->GetFrameFromDirection( + aPos->mDirection, aPos->mVisual, aPos->mJumpLines, + aPos->mScrollViewStop, aPos->mForceEditableRegion, &nextFrame, +@@ -8386,17 +8387,18 @@ nsIFrame::FrameSearchResult nsFrame::Pee + } + return CONTINUE; + } + + nsIFrame::FrameSearchResult nsFrame::PeekOffsetWord(bool aForward, + bool aWordSelectEatSpace, + bool aIsKeyboardSelect, + int32_t* aOffset, +- PeekWordState* aState) { ++ PeekWordState* aState, ++ bool aTrimSpaces) { + NS_ASSERTION(aOffset && *aOffset <= 1, "aOffset out of range"); + int32_t startOffset = *aOffset; + // This isn't text, so truncate the context + aState->mContext.Truncate(); + if (startOffset < 0) startOffset = 1; + if (aForward == (startOffset == 0)) { + // We're before the frame and moving forward, or after it and moving + // backwards. If we're looking for non-whitespace, we found it (without +diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h +--- a/layout/generic/nsFrame.h ++++ b/layout/generic/nsFrame.h +@@ -211,17 +211,18 @@ class nsFrame : public nsBox { + FrameSearchResult PeekOffsetNoAmount(bool aForward, + int32_t* aOffset) override; + FrameSearchResult PeekOffsetCharacter( + bool aForward, int32_t* aOffset, + PeekOffsetCharacterOptions aOptions = + PeekOffsetCharacterOptions()) override; + FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, + bool aIsKeyboardSelect, int32_t* aOffset, +- PeekWordState* aState) override; ++ PeekWordState* aState, bool aTrimSpaces) ++ override; + /** + * Check whether we should break at a boundary between punctuation and + * non-punctuation. Only call it at a punctuation boundary + * (i.e. exactly one of the previous and next characters are punctuation). + * @param aForward true if we're moving forward in content order + * @param aPunctAfter true if the next character is punctuation + * @param aWhitespaceAfter true if the next character is whitespace + */ +diff --git a/layout/generic/nsFrameSelection.cpp b/layout/generic/nsFrameSelection.cpp +--- a/layout/generic/nsFrameSelection.cpp ++++ b/layout/generic/nsFrameSelection.cpp +@@ -106,23 +106,25 @@ static void printRange(nsRange* aDomRang + + //#define DEBUG_TABLE_SELECTION 1 + + nsPeekOffsetStruct::nsPeekOffsetStruct( + nsSelectionAmount aAmount, nsDirection aDirection, int32_t aStartOffset, + nsPoint aDesiredPos, bool aJumpLines, bool aScrollViewStop, + bool aIsKeyboardSelect, bool aVisual, bool aExtend, + ForceEditableRegion aForceEditableRegion, +- EWordMovementType aWordMovementType) ++ EWordMovementType aWordMovementType, ++ bool aTrimSpaces) + : mAmount(aAmount), + mDirection(aDirection), + mStartOffset(aStartOffset), + mDesiredPos(aDesiredPos), + mWordMovementType(aWordMovementType), + mJumpLines(aJumpLines), ++ mTrimSpaces(aTrimSpaces), + mScrollViewStop(aScrollViewStop), + mIsKeyboardSelect(aIsKeyboardSelect), + mVisual(aVisual), + mExtend(aExtend), + mForceEditableRegion(aForceEditableRegion == ForceEditableRegion::Yes), + mResultContent(), + mResultFrame(nullptr), + mContentOffset(0), +diff --git a/layout/generic/nsFrameSelection.h b/layout/generic/nsFrameSelection.h +--- a/layout/generic/nsFrameSelection.h ++++ b/layout/generic/nsFrameSelection.h +@@ -67,17 +67,18 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruc + Yes, + }; + + nsPeekOffsetStruct( + nsSelectionAmount aAmount, nsDirection aDirection, int32_t aStartOffset, + nsPoint aDesiredPos, bool aJumpLines, bool aScrollViewStop, + bool aIsKeyboardSelect, bool aVisual, bool aExtend, + ForceEditableRegion = ForceEditableRegion::No, +- mozilla::EWordMovementType aWordMovementType = mozilla::eDefaultBehavior); ++ mozilla::EWordMovementType aWordMovementType = mozilla::eDefaultBehavior, ++ bool aTrimSpaces = true); + + // Note: Most arguments (input and output) are only used with certain values + // of mAmount. These values are indicated for each argument below. + // Arguments with no such indication are used with all values of mAmount. + + /*** Input arguments ***/ + // Note: The value of some of the input arguments may be changed upon exit. + +@@ -114,16 +115,19 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruc + // platform-based pref "layout.word_select.eat_space_to_next_word" + mozilla::EWordMovementType mWordMovementType; + + // Whether to allow jumping across line boundaries. + // + // Used with: eSelectCharacter, eSelectWord. + bool mJumpLines; + ++ // mTrimSpaces: Whether we should trim spaces at begin/end of content ++ bool mTrimSpaces; ++ + // Whether to stop when reaching a scroll view boundary. + // + // Used with: eSelectCharacter, eSelectWord, eSelectLine. + bool mScrollViewStop; + + // Whether the peeking is done in response to a keyboard action. + // + // Used with: eSelectWord. +diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h +--- a/layout/generic/nsIFrame.h ++++ b/layout/generic/nsIFrame.h +@@ -4484,17 +4484,18 @@ class nsIFrame : public nsQueryFrame { + } + mAtStart = false; + } + }; + virtual FrameSearchResult PeekOffsetWord(bool aForward, + bool aWordSelectEatSpace, + bool aIsKeyboardSelect, + int32_t* aOffset, +- PeekWordState* aState) = 0; ++ PeekWordState* aState, ++ bool aTrimSpaces) = 0; + + /** + * Search for the first paragraph boundary before or after the given position + * @param aPos See description in nsFrameSelection.h. The following fields + * are used by this method: + * Input: mDirection + * Output: mResultContent, mContentOffset + */ +diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp +--- a/layout/generic/nsTextFrame.cpp ++++ b/layout/generic/nsTextFrame.cpp +@@ -2961,18 +2961,19 @@ nsTextFrame::TrimmedOffsets nsTextFrame: + } + + TrimmedOffsets offsets = {GetContentOffset(), GetContentLength()}; + const nsStyleText* textStyle = StyleText(); + // Note that pre-line newlines should still allow us to trim spaces + // for display + if (textStyle->WhiteSpaceIsSignificant()) return offsets; + +- if ((aFlags & TrimmedOffsetFlags::kNoPostReflow) || +- (GetStateBits() & TEXT_START_OF_LINE)) { ++ if (!(aFlags & TrimmedOffsetFlags::kNoTrimBefore) && ++ ((aFlags & TrimmedOffsetFlags::kNoPostReflow) || ++ (GetStateBits() & TEXT_START_OF_LINE))) { + int32_t whitespaceCount = + GetTrimmableWhitespaceCount(aFrag, offsets.mStart, offsets.mLength, 1); + offsets.mStart += whitespaceCount; + offsets.mLength -= whitespaceCount; + } + + if (!(aFlags & TrimmedOffsetFlags::kNoTrimAfter) && + ((aFlags & TrimmedOffsetFlags::kNoPostReflow) || +@@ -7725,17 +7726,18 @@ nsIFrame::FrameSearchResult nsTextFrame: + * to see if it's whitespace (as far as selection/caret movement is concerned), + * or punctuation, or if there is a word break before the cluster. ("Before" + * is interpreted according to aDirection, so if aDirection is -1, "before" + * means actually *after* the cluster content.) + */ + class MOZ_STACK_CLASS ClusterIterator { + public: + ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition, +- int32_t aDirection, nsString& aContext); ++ int32_t aDirection, nsString& aContext, ++ bool aTrimSpaces = true); + + bool NextCluster(); + bool IsWhitespace(); + bool IsPunctuation(); + bool HaveWordBreakBefore() { return mHaveWordBreak; } + + // Get the charIndex that corresponds to the "before" side of the current + // character, according to the direction of iteration: so for a forward +@@ -7950,30 +7952,34 @@ bool ClusterIterator::NextCluster() { + if (mWordBreaks[GetBeforeOffset() - mTextFrame->GetContentOffset()]) { + mHaveWordBreak = true; + } + if (!keepGoing) return true; + } + } + + ClusterIterator::ClusterIterator(nsTextFrame* aTextFrame, int32_t aPosition, +- int32_t aDirection, nsString& aContext) ++ int32_t aDirection, nsString& aContext, ++ bool aTrimSpaces) + : mTextFrame(aTextFrame), + mDirection(aDirection), + mCharIndex(-1), + mHaveWordBreak(false) { + mIterator = aTextFrame->EnsureTextRun(nsTextFrame::eInflated); + if (!aTextFrame->GetTextRun(nsTextFrame::eInflated)) { + mDirection = 0; // signal failure + return; + } + mIterator.SetOriginalOffset(aPosition); + + mFrag = aTextFrame->GetContent()->GetText(); +- mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag); ++ mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag, ++ aTrimSpaces ? nsTextFrame::TrimmedOffsetFlags::kDefaultTrimFlags : ++ nsTextFrame::TrimmedOffsetFlags::kNoTrimAfter | ++ nsTextFrame::TrimmedOffsetFlags::kNoTrimBefore); + + int32_t textOffset = aTextFrame->GetContentOffset(); + int32_t textLen = aTextFrame->GetContentLength(); + if (!mWordBreaks.AppendElements(textLen + 1)) { + mDirection = 0; // signal failure + return; + } + memset(mWordBreaks.Elements(), false, (textLen + 1) * sizeof(bool)); +@@ -8001,27 +8007,28 @@ ClusterIterator::ClusterIterator(nsTextF + mWordBreaks[i] |= wordBreaker->BreakInBetween( + aContext.get(), indexInText, aContext.get() + indexInText, + aContext.Length() - indexInText); + } + } + + nsIFrame::FrameSearchResult nsTextFrame::PeekOffsetWord( + bool aForward, bool aWordSelectEatSpace, bool aIsKeyboardSelect, +- int32_t* aOffset, PeekWordState* aState) { ++ int32_t* aOffset, PeekWordState* aState, bool aTrimSpaces) { + int32_t contentLength = GetContentLength(); + NS_ASSERTION(aOffset && *aOffset <= contentLength, "aOffset out of range"); + + StyleUserSelect selectStyle; + IsSelectable(&selectStyle); + if (selectStyle == StyleUserSelect::All) return CONTINUE_UNSELECTABLE; + + int32_t offset = + GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); +- ClusterIterator cIter(this, offset, aForward ? 1 : -1, aState->mContext); ++ ClusterIterator cIter(this, offset, aForward ? 1 : -1, aState->mContext, ++ aTrimSpaces); + + if (!cIter.NextCluster()) return CONTINUE_EMPTY; + + do { + bool isPunctuation = cIter.IsPunctuation(); + bool isWhitespace = cIter.IsWhitespace(); + bool isWordBreakBefore = cIter.HaveWordBreakBefore(); + if (aWordSelectEatSpace == isWhitespace && !aState->mSawBeforeType) { +diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h +--- a/layout/generic/nsTextFrame.h ++++ b/layout/generic/nsTextFrame.h +@@ -178,17 +178,18 @@ class nsTextFrame : public nsFrame { + SelectionType aSelectionType); + + FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) final; + FrameSearchResult PeekOffsetCharacter( + bool aForward, int32_t* aOffset, + PeekOffsetCharacterOptions aOptions = PeekOffsetCharacterOptions()) final; + FrameSearchResult PeekOffsetWord(bool aForward, bool aWordSelectEatSpace, + bool aIsKeyboardSelect, int32_t* aOffset, +- PeekWordState* aState) final; ++ PeekWordState* aState, bool aTrimSpaces) ++ final; + + nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, + int32_t aEndIndex, bool aRecurse, bool* aFinished, + bool* _retval) final; + + // Flags for aSetLengthFlags + enum { ALLOW_FRAME_CREATION_AND_DESTRUCTION = 0x01 }; + +@@ -571,17 +572,18 @@ class nsTextFrame : public nsFrame { + struct TrimmedOffsets { + int32_t mStart; + int32_t mLength; + int32_t GetEnd() const { return mStart + mLength; } + }; + enum class TrimmedOffsetFlags : uint8_t { + kDefaultTrimFlags = 0, + kNoPostReflow = 1 << 0, +- kNoTrimAfter = 1 << 1 ++ kNoTrimAfter = 1 << 1, ++ kNoTrimBefore = 1 << 2 + }; + TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, + TrimmedOffsetFlags aFlags = TrimmedOffsetFlags::kDefaultTrimFlags) const; + + // Similar to Reflow(), but for use from nsLineLayout + void ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, + DrawTarget* aDrawTarget, ReflowOutput& aMetrics, + nsReflowStatus& aStatus); diff --git a/firefox-patches/series-60 b/firefox-patches/series-60 index 42b676a..2634079 100644 --- a/firefox-patches/series-60 +++ b/firefox-patches/series-60 @@ -6,3 +6,4 @@ scrollto scrollsubstringto #jumpedline control-enter +text-at-offset-word diff --git a/firefox-patches/version b/firefox-patches/version index 00750ed..b8626c4 100644 --- a/firefox-patches/version +++ b/firefox-patches/version @@ -1 +1 @@ -3 +4 -- GitLab