diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index f1eca31f109..2453417abb2 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -253,8 +253,8 @@ typedef PRUint64 nsFrameState; // frame instead of the root frame. #define NS_FRAME_REFLOW_ROOT NS_FRAME_STATE_BIT(19) -// Bits 20-31 of the frame state are reserved for implementations. -#define NS_FRAME_IMPL_RESERVED nsFrameState(0xFFF00000) +// Bits 20-31 and 60-63 of the frame state are reserved for implementations. +#define NS_FRAME_IMPL_RESERVED nsFrameState(0xF0000000FFF00000) // This bit is set on floats whose parent does not contain their // placeholder. This can happen for two reasons: (1) the float was diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index bc74251ceda..48eb8c2c5c4 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -453,6 +453,8 @@ protected: ContentOffsets GetCharacterOffsetAtFramePointInternal(const nsPoint &aPoint, PRBool aForInsertionPoint); + + void ClearFrameOffsetCache(); }; #endif diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 012913e45a4..f624be7c511 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -138,6 +138,8 @@ static void DestroyTabWidth(void* aPropertyValue) NS_DECLARE_FRAME_PROPERTY(TabWidthProperty, DestroyTabWidth) +NS_DECLARE_FRAME_PROPERTY(OffsetToFrameProperty, nsnull) + // The following flags are set during reflow // This bit is set on the first frame in a continuation indicating @@ -183,6 +185,9 @@ NS_DECLARE_FRAME_PROPERTY(TabWidthProperty, DestroyTabWidth) // nsTextFrame.h has // #define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31) +// Whether this frame is cached in the Offset Frame Cache (OffsetToFrameProperty) +#define TEXT_IN_OFFSET_CACHE NS_FRAME_STATE_BIT(63) + /* * Some general notes * @@ -3464,9 +3469,28 @@ nsTextFrame::Init(nsIContent* aContent, return nsFrame::Init(aContent, aParent, aPrevInFlow); } +void +nsTextFrame::ClearFrameOffsetCache() +{ + // See if we need to remove ourselves from the offset cache + if (GetStateBits() & TEXT_IN_OFFSET_CACHE) { + nsIFrame* primaryFrame = mContent->GetPrimaryFrame(); + if (primaryFrame) { + // The primary frame might be null here. For example, nsLineBox::DeleteLineList + // just destroys the frames in order, which means that the primary frame is already + // dead if we're a continuing text frame, in which case, all of its properties are + // gone, and we don't need to worry about deleting this property here. + primaryFrame->Properties().Delete(OffsetToFrameProperty()); + } + RemoveStateBits(TEXT_IN_OFFSET_CACHE); + } +} + void nsTextFrame::DestroyFrom(nsIFrame* aDestructRoot) { + ClearFrameOffsetCache(); + // We might want to clear NS_CREATE_FRAME_IF_NON_WHITESPACE or // NS_REFRAME_IF_WHITESPACE on mContent here, since our parent frame // type might be changing. Not clear whether it's worth it. @@ -3596,6 +3620,8 @@ nsContinuingTextFrame::Init(nsIContent* aContent, void nsContinuingTextFrame::DestroyFrom(nsIFrame* aDestructRoot) { + ClearFrameOffsetCache(); + // The text associated with this frame will become associated with our // prev-continuation. If that means the text has changed style, then // we need to wipe out the text run for the text. @@ -5282,9 +5308,29 @@ nsTextFrame::GetChildFrameContainingOffset(PRInt32 aContentOffset, NS_ASSERTION(aOutOffset && aOutFrame, "Bad out parameters"); NS_ASSERTION(aContentOffset >= 0, "Negative content offset, existing code was very broken!"); + nsIFrame* primaryFrame = mContent->GetPrimaryFrame(); + if (this != primaryFrame) { + // This call needs to happen on the primary frame + return primaryFrame->GetChildFrameContainingOffset(aContentOffset, aHint, + aOutOffset, aOutFrame); + } nsTextFrame* f = this; - if (aContentOffset >= mContentOffset) { + PRInt32 offset = mContentOffset; + + // Try to look up the offset to frame property + nsTextFrame* cachedFrame = static_cast + (Properties().Get(OffsetToFrameProperty())); + + if (cachedFrame) { + f = cachedFrame; + offset = f->GetContentOffset(); + + f->RemoveStateBits(TEXT_IN_OFFSET_CACHE); + } + + if ((aContentOffset >= offset) && + (aHint || aContentOffset != offset)) { while (PR_TRUE) { nsTextFrame* next = static_cast(f->GetNextContinuation()); if (!next || aContentOffset < next->GetContentOffset()) @@ -5314,6 +5360,11 @@ nsTextFrame::GetChildFrameContainingOffset(PRInt32 aContentOffset, *aOutOffset = aContentOffset - f->GetContentOffset(); *aOutFrame = f; + + // cache the frame we found + Properties().Set(OffsetToFrameProperty(), f); + f->AddStateBits(TEXT_IN_OFFSET_CACHE); + return NS_OK; }