Bug 1314080 Part 4: Implement the new text retrieval behavior. r?smaug
MozReview-Commit-ID: 7j5BjruBNb9
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -2900,37 +2900,59 @@ GetTextFrameForContent(nsIContent* aCont
static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
mozilla::dom::DOMStringList* aTextList,
nsIContent* aContent, int32_t aStartOffset,
int32_t aEndOffset, bool aClampToEdge,
bool aFlushLayout)
{
nsTextFrame* textFrame = GetTextFrameForContent(aContent, aFlushLayout);
if (textFrame) {
+ // If we'll need it later, collect the full content text now.
+ nsAutoString textContent;
+ if (aTextList) {
+ mozilla::ErrorResult err; // ignored
+ aContent->GetTextContent(textContent, err);
+ }
+
nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
if (fend <= aStartOffset || fstart >= aEndOffset)
continue;
+ // Calculate the text content offsets we'll need if text is requested.
+ int32_t textContentStart = fstart;
+ int32_t textContentEnd = fend;
+
// overlapping with the offset we want
f->EnsureTextRun(nsTextFrame::eInflated);
NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY);
bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft();
nsRect r = f->GetRectRelativeToSelf();
if (fstart < aStartOffset) {
// aStartOffset is within this frame
ExtractRectFromOffset(f, aStartOffset, &r, rtl, aClampToEdge);
+ textContentStart = aStartOffset;
}
if (fend > aEndOffset) {
// aEndOffset is in the middle of this frame
ExtractRectFromOffset(f, aEndOffset, &r, !rtl, aClampToEdge);
+ textContentEnd = aEndOffset;
}
r = nsLayoutUtils::TransformFrameRectToAncestor(f, r, relativeTo);
aCallback->AddRect(r);
+
+ // Finally capture the text, if requested.
+ if (aTextList) {
+ const nsAString& textSubstring =
+ Substring(textContent,
+ textContentStart,
+ (textContentEnd - textContentStart));
+ aTextList->Add(textSubstring);
+ }
}
}
return NS_OK;
}
/* static */ void
nsRange::CollectClientRectsAndText(nsLayoutUtils::RectCallback* aCollector,
mozilla::dom::DOMStringList* aTextList,
@@ -3002,18 +3024,19 @@ nsRange::CollectClientRectsAndText(nsLay
GetPartialTextRect(aCollector, aTextList, content, 0, aEndOffset,
aClampToEdge, aFlushLayout);
continue;
}
}
nsIFrame* frame = content->GetPrimaryFrame();
if (frame) {
- nsLayoutUtils::GetAllInFlowRects(frame,
+ nsLayoutUtils::GetAllInFlowRectsAndTexts(frame,
nsLayoutUtils::GetContainingBlockForClientRect(frame), aCollector,
+ aTextList,
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
}
} while (!iter.IsDone());
}
NS_IMETHODIMP
nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
{
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -65,16 +65,17 @@
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsICanvasRenderingContextInternal.h"
#include "gfxPlatform.h"
#include <algorithm>
#include <limits>
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/DOMRect.h"
+#include "mozilla/dom/DOMStringList.h"
#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "imgIRequest.h"
#include "nsIImageLoadingContent.h"
#include "nsCOMPtr.h"
#include "nsCSSProps.h"
#include "nsListControlFrame.h"
#include "mozilla/dom/Element.h"
@@ -3933,24 +3934,53 @@ struct BoxToRect : public nsLayoutUtils:
r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
} else {
r += outer->GetOffsetTo(mRelativeTo);
}
mCallback->AddRect(r);
}
};
+struct BoxToRectAndText : public BoxToRect {
+ mozilla::dom::DOMStringList* mTextList;
+
+ BoxToRectAndText(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
+ mozilla::dom::DOMStringList* aTextList, uint32_t aFlags)
+ : BoxToRect(aRelativeTo, aCallback, aFlags), mTextList(aTextList) {}
+
+ virtual void AddBox(nsIFrame* aFrame) override {
+ BoxToRect::AddBox(aFrame);
+ if (mTextList) {
+ nsIContent* content = aFrame->GetContent();
+ nsAutoString textContent;
+ mozilla::ErrorResult err; // ignored
+ content->GetTextContent(textContent, err);
+ mTextList->Add(textContent);
+ }
+ }
+};
+
void
nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
RectCallback* aCallback, uint32_t aFlags)
{
BoxToRect converter(aRelativeTo, aCallback, aFlags);
GetAllInFlowBoxes(aFrame, &converter);
}
+void
+nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
+ RectCallback* aCallback,
+ mozilla::dom::DOMStringList* aTextList,
+ uint32_t aFlags)
+{
+ BoxToRectAndText converter(aRelativeTo, aCallback, aTextList, aFlags);
+ GetAllInFlowBoxes(aFrame, &converter);
+}
+
nsLayoutUtils::RectAccumulator::RectAccumulator() : mSeenFirstRect(false) {}
void nsLayoutUtils::RectAccumulator::AddRect(const nsRect& aRect) {
mResultRect.UnionRect(mResultRect, aRect);
if (!mSeenFirstRect) {
mSeenFirstRect = true;
mFirstRect = aRect;
}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1193,16 +1193,21 @@ public:
* and SVG transforms) are taken into account.
* If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
* or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
* Otherwise (by default), the border box is used.
*/
static void GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
RectCallback* aCallback, uint32_t aFlags = 0);
+ static void GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
+ RectCallback* aCallback,
+ mozilla::dom::DOMStringList* aTextList,
+ uint32_t aFlags = 0);
+
/**
* Computes the union of all rects returned by GetAllInFlowRects. If
* the union is empty, returns the first rect.
* If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
* the boxes into aRelativeTo coordinates, transforms (including CSS
* and SVG transforms) are taken into account.
* If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
* or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.