From cc9241e019192fd261b6b03ae3d1e205f1ed82bf Mon Sep 17 00:00:00 2001 From: Morris Tseng Date: Wed, 23 Jul 2014 23:06:00 +0200 Subject: [PATCH] Bug 987040 - Part 2: Add a flag indicate whether CollectClientRects should flush layout or not. r=ehsan --- content/base/src/nsRange.cpp | 42 ++++++++++++++++++++------------- content/base/src/nsRange.h | 8 ++++--- dom/base/nsGlobalWindow.cpp | 2 +- layout/base/SelectionCarets.cpp | 2 +- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/content/base/src/nsRange.cpp b/content/base/src/nsRange.cpp index 6defd0a0b500..2fc2ca4db8d9 100644 --- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -2749,13 +2749,17 @@ static void ExtractRectFromOffset(nsIFrame* aFrame, } static nsTextFrame* -GetTextFrameForContent(nsIContent* aContent) +GetTextFrameForContent(nsIContent* aContent, bool aFlushLayout) { nsIPresShell* presShell = aContent->OwnerDoc()->GetShell(); if (presShell) { presShell->FrameConstructor()->EnsureFrameForTextNode( static_cast(aContent)); - aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout); + + if (aFlushLayout) { + aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout); + } + nsIFrame* frame = aContent->GetPrimaryFrame(); if (frame && frame->GetType() == nsGkAtoms::textFrame) { return static_cast(frame); @@ -2766,9 +2770,10 @@ GetTextFrameForContent(nsIContent* aContent) static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback, nsIContent* aContent, int32_t aStartOffset, - int32_t aEndOffset, bool aClampToEdge) + int32_t aEndOffset, bool aClampToEdge, + bool aFlushLayout) { - nsTextFrame* textFrame = GetTextFrameForContent(aContent); + nsTextFrame* textFrame = GetTextFrameForContent(aContent, aFlushLayout); if (textFrame) { nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame); for (nsTextFrame* f = textFrame; f; f = static_cast(f->GetNextContinuation())) { @@ -2801,7 +2806,7 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector, nsRange* aRange, nsINode* aStartParent, int32_t aStartOffset, nsINode* aEndParent, int32_t aEndOffset, - bool aClampToEdge) + bool aClampToEdge, bool aFlushLayout) { // Hold strong pointers across the flush nsCOMPtr startContainer = aStartParent; @@ -2812,11 +2817,12 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector, return; } - aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout); - - // Recheck whether we're still in the document - if (!aStartParent->IsInDoc()) { - return; + if (aFlushLayout) { + aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout); + // Recheck whether we're still in the document + if (!aStartParent->IsInDoc()) { + return; + } } RangeSubtreeIterator iter; @@ -2828,7 +2834,7 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector, // the range is collapsed, only continue if the cursor is in a text node nsCOMPtr content = do_QueryInterface(aStartParent); if (content && content->IsNodeOfType(nsINode::eTEXT)) { - nsTextFrame* textFrame = GetTextFrameForContent(content); + nsTextFrame* textFrame = GetTextFrameForContent(content, aFlushLayout); if (textFrame) { int32_t outOffset; nsIFrame* outFrame; @@ -2858,10 +2864,12 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector, if (node == startContainer) { int32_t offset = startContainer == endContainer ? aEndOffset : content->GetText()->GetLength(); - GetPartialTextRect(aCollector, content, aStartOffset, offset, aClampToEdge); + GetPartialTextRect(aCollector, content, aStartOffset, offset, + aClampToEdge, aFlushLayout); continue; } else if (node == endContainer) { - GetPartialTextRect(aCollector, content, 0, aEndOffset, aClampToEdge); + GetPartialTextRect(aCollector, content, 0, aEndOffset, + aClampToEdge, aFlushLayout); continue; } } @@ -2883,7 +2891,7 @@ nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult) } already_AddRefed -nsRange::GetBoundingClientRect(bool aClampToEdge) +nsRange::GetBoundingClientRect(bool aClampToEdge, bool aFlushLayout) { nsRefPtr rect = new DOMRect(ToSupports(this)); if (!mStartParent) { @@ -2892,7 +2900,7 @@ nsRange::GetBoundingClientRect(bool aClampToEdge) nsLayoutUtils::RectAccumulator accumulator; CollectClientRects(&accumulator, this, mStartParent, mStartOffset, - mEndParent, mEndOffset, aClampToEdge); + mEndParent, mEndOffset, aClampToEdge, aFlushLayout); nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect : accumulator.mResultRect; @@ -2908,7 +2916,7 @@ nsRange::GetClientRects(nsIDOMClientRectList** aResult) } already_AddRefed -nsRange::GetClientRects(bool aClampToEdge) +nsRange::GetClientRects(bool aClampToEdge, bool aFlushLayout) { if (!mStartParent) { return nullptr; @@ -2920,7 +2928,7 @@ nsRange::GetClientRects(bool aClampToEdge) nsLayoutUtils::RectListBuilder builder(rectList); CollectClientRects(&builder, this, mStartParent, mStartOffset, - mEndParent, mEndOffset, aClampToEdge); + mEndParent, mEndOffset, aClampToEdge, aFlushLayout); return rectList.forget(); } diff --git a/content/base/src/nsRange.h b/content/base/src/nsRange.h index ba2a527666d3..a7bab97ef66d 100644 --- a/content/base/src/nsRange.h +++ b/content/base/src/nsRange.h @@ -217,8 +217,10 @@ public: void SetStartAfter(nsINode& aNode, ErrorResult& aErr); void SetStartBefore(nsINode& aNode, ErrorResult& aErr); void SurroundContents(nsINode& aNode, ErrorResult& aErr); - already_AddRefed GetBoundingClientRect(bool aClampToEdge = true); - already_AddRefed GetClientRects(bool aClampToEdge = true); + already_AddRefed GetBoundingClientRect(bool aClampToEdge = true, + bool aFlushLayout = true); + already_AddRefed GetClientRects(bool aClampToEdge = true, + bool aFlushLayout = true); nsINode* GetParentObject() const { return mOwner; } virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL; @@ -260,7 +262,7 @@ public: nsRange* aRange, nsINode* aStartParent, int32_t aStartOffset, nsINode* aEndParent, int32_t aEndOffset, - bool aClampToEdge); + bool aClampToEdge, bool aFlushLayout); typedef nsTHashtable > RangeHashTable; protected: diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 19453cf6185c..f9b9e2b17199 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -9279,7 +9279,7 @@ nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, in nsresult rv = aSel->GetRangeAt(0, getter_AddRefs(range)); if (NS_SUCCEEDED(rv) && range) { nsRefPtr nsrange = static_cast(range.get()); - init.mBoundingClientRect = nsrange->GetBoundingClientRect(true); + init.mBoundingClientRect = nsrange->GetBoundingClientRect(true, false); range->ToString(init.mSelectedText); init.mReason = aReason; } diff --git a/layout/base/SelectionCarets.cpp b/layout/base/SelectionCarets.cpp index 68decdf7e190..badbfb87d6a2 100644 --- a/layout/base/SelectionCarets.cpp +++ b/layout/base/SelectionCarets.cpp @@ -382,7 +382,7 @@ SelectionCarets::UpdateSelectionCarets() nsLayoutUtils::FirstAndLastRectCollector collector; nsRange::CollectClientRects(&collector, range, range->GetStartParent(), range->StartOffset(), - range->GetEndParent(), range->EndOffset(), true); + range->GetEndParent(), range->EndOffset(), true, true); nsIFrame* canvasFrame = mPresShell->GetCanvasFrame(); nsIFrame* rootFrame = mPresShell->GetRootFrame();