mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1423331: Prevent selection from leaking from blocks. r=mats
MozReview-Commit-ID: EFLXSQ8Zvze --HG-- extra : rebase_source : 10b8ff4c0712e6880c69eafc49cf1a78d4dff4bd
This commit is contained in:
parent
714ba3c60d
commit
d563b8100b
@ -4705,37 +4705,40 @@ struct MOZ_STACK_CLASS FrameContentRange {
|
||||
|
||||
// Retrieve the content offsets of a frame
|
||||
static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
|
||||
nsCOMPtr<nsIContent> content, parent;
|
||||
content = aFrame->GetContent();
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
if (!content) {
|
||||
NS_WARNING("Frame has no content");
|
||||
return FrameContentRange(nullptr, -1, -1);
|
||||
}
|
||||
|
||||
LayoutFrameType type = aFrame->Type();
|
||||
if (type == LayoutFrameType::Text) {
|
||||
int32_t offset, offsetEnd;
|
||||
aFrame->GetOffsets(offset, offsetEnd);
|
||||
return FrameContentRange(content, offset, offsetEnd);
|
||||
}
|
||||
|
||||
if (type == LayoutFrameType::Br) {
|
||||
parent = content->GetParent();
|
||||
nsIContent* parent = content->GetParent();
|
||||
int32_t beginOffset = parent->IndexOf(content);
|
||||
return FrameContentRange(parent, beginOffset, beginOffset);
|
||||
}
|
||||
// Loop to deal with anonymous content, which has no index; this loop
|
||||
// probably won't run more than twice under normal conditions
|
||||
do {
|
||||
parent = content->GetParent();
|
||||
if (parent) {
|
||||
int32_t beginOffset = parent->IndexOf(content);
|
||||
if (beginOffset >= 0)
|
||||
return FrameContentRange(parent, beginOffset, beginOffset + 1);
|
||||
content = parent;
|
||||
}
|
||||
} while (parent);
|
||||
|
||||
// The root content node must act differently
|
||||
return FrameContentRange(content, 0, content->GetChildCount());
|
||||
while (content->IsRootOfAnonymousSubtree()) {
|
||||
content = content->GetParent();
|
||||
}
|
||||
|
||||
nsIContent* parent = content->GetParent();
|
||||
if (nsLayoutUtils::GetAsBlock(aFrame) || !parent) {
|
||||
return FrameContentRange(content, 0, content->GetChildCount());
|
||||
}
|
||||
|
||||
// TODO(emilio): Revise this in presence of Shadow DOM / display: contents,
|
||||
// it's likely that we don't want to just walk the light tree, and we need to
|
||||
// change the representation of FrameContentRange.
|
||||
int32_t index = parent->IndexOf(content);
|
||||
MOZ_ASSERT(index >= 0);
|
||||
return FrameContentRange(parent, index, index + 1);
|
||||
}
|
||||
|
||||
// The FrameTarget represents the closest frame to a point that can be selected
|
||||
@ -4743,20 +4746,22 @@ static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
|
||||
// frame is the result (in which case different handling is needed), and
|
||||
// afterFrame says which end is repersented if frameEdge is true
|
||||
struct FrameTarget {
|
||||
FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
|
||||
bool aEmptyBlock = false) :
|
||||
frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
|
||||
emptyBlock(aEmptyBlock) { }
|
||||
FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame)
|
||||
: frame(aFrame)
|
||||
, frameEdge(aFrameEdge)
|
||||
, afterFrame(aAfterFrame)
|
||||
{}
|
||||
|
||||
static FrameTarget Null() {
|
||||
return FrameTarget(nullptr, false, false);
|
||||
}
|
||||
|
||||
bool IsNull() {
|
||||
return !frame;
|
||||
}
|
||||
nsIFrame* frame;
|
||||
bool frameEdge;
|
||||
bool afterFrame;
|
||||
bool emptyBlock;
|
||||
};
|
||||
|
||||
// See function implementation for information
|
||||
@ -4846,11 +4851,12 @@ static FrameTarget GetSelectionClosestFrameForLine(
|
||||
const nsPoint& aPoint,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
nsIFrame *frame = aLine->mFirstChild;
|
||||
// Account for end of lines (any iterator from the block is valid)
|
||||
if (aLine == aParent->LinesEnd())
|
||||
return DrillDownToSelectionFrame(aParent, true, aFlags);
|
||||
nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr;
|
||||
nsIFrame* frame = aLine->mFirstChild;
|
||||
nsIFrame* closestFromIStart = nullptr;
|
||||
nsIFrame* closestFromIEnd = nullptr;
|
||||
nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
|
||||
WritingMode wm = aLine->mWritingMode;
|
||||
LogicalPoint pt(wm, aPoint, aLine->mContainerSize);
|
||||
@ -4909,62 +4915,56 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
|
||||
return FrameTarget::Null();
|
||||
|
||||
// This code searches for the correct line
|
||||
nsBlockFrame::LineIterator firstLine = bf->LinesBegin();
|
||||
nsBlockFrame::LineIterator end = bf->LinesEnd();
|
||||
if (firstLine == end) {
|
||||
nsIContent *blockContent = aFrame->GetContent();
|
||||
if (blockContent) {
|
||||
// Return with empty flag true.
|
||||
return FrameTarget(aFrame, false, false, true);
|
||||
}
|
||||
return FrameTarget::Null();
|
||||
}
|
||||
nsBlockFrame::LineIterator curLine = firstLine;
|
||||
nsBlockFrame::LineIterator curLine = bf->LinesBegin();
|
||||
nsBlockFrame::LineIterator closestLine = end;
|
||||
// Convert aPoint into a LogicalPoint in the writing-mode of this block
|
||||
WritingMode wm = curLine->mWritingMode;
|
||||
LogicalPoint pt(wm, aPoint, curLine->mContainerSize);
|
||||
while (curLine != end) {
|
||||
// Check to see if our point lies within the line's block-direction bounds
|
||||
nscoord BCoord = pt.B(wm) - curLine->BStart();
|
||||
nscoord BSize = curLine->BSize();
|
||||
if (BCoord >= 0 && BCoord < BSize) {
|
||||
closestLine = curLine;
|
||||
break; // We found the line; stop looking
|
||||
}
|
||||
if (BCoord < 0)
|
||||
break;
|
||||
++curLine;
|
||||
}
|
||||
|
||||
if (closestLine == end) {
|
||||
nsBlockFrame::LineIterator prevLine = curLine.prev();
|
||||
nsBlockFrame::LineIterator nextLine = curLine;
|
||||
// Avoid empty lines
|
||||
while (nextLine != end && nextLine->IsEmpty())
|
||||
++nextLine;
|
||||
while (prevLine != end && prevLine->IsEmpty())
|
||||
--prevLine;
|
||||
if (curLine != end) {
|
||||
// Convert aPoint into a LogicalPoint in the writing-mode of this block
|
||||
WritingMode wm = curLine->mWritingMode;
|
||||
LogicalPoint pt(wm, aPoint, curLine->mContainerSize);
|
||||
do {
|
||||
// Check to see if our point lies within the line's block-direction bounds
|
||||
nscoord BCoord = pt.B(wm) - curLine->BStart();
|
||||
nscoord BSize = curLine->BSize();
|
||||
if (BCoord >= 0 && BCoord < BSize) {
|
||||
closestLine = curLine;
|
||||
break; // We found the line; stop looking
|
||||
}
|
||||
if (BCoord < 0)
|
||||
break;
|
||||
++curLine;
|
||||
} while (curLine != end);
|
||||
|
||||
// This hidden pref dictates whether a point above or below all lines comes
|
||||
// up with a line or the beginning or end of the frame; 0 on Windows,
|
||||
// 1 on other platforms by default at the writing of this code
|
||||
int32_t dragOutOfFrame =
|
||||
Preferences::GetInt("browser.drag_out_of_frame_style");
|
||||
if (closestLine == end) {
|
||||
nsBlockFrame::LineIterator prevLine = curLine.prev();
|
||||
nsBlockFrame::LineIterator nextLine = curLine;
|
||||
// Avoid empty lines
|
||||
while (nextLine != end && nextLine->IsEmpty())
|
||||
++nextLine;
|
||||
while (prevLine != end && prevLine->IsEmpty())
|
||||
--prevLine;
|
||||
|
||||
if (prevLine == end) {
|
||||
if (dragOutOfFrame == 1 || nextLine == end)
|
||||
return DrillDownToSelectionFrame(aFrame, false, aFlags);
|
||||
closestLine = nextLine;
|
||||
} else if (nextLine == end) {
|
||||
if (dragOutOfFrame == 1)
|
||||
return DrillDownToSelectionFrame(aFrame, true, aFlags);
|
||||
closestLine = prevLine;
|
||||
} else { // Figure out which line is closer
|
||||
if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
|
||||
closestLine = prevLine;
|
||||
else
|
||||
// This hidden pref dictates whether a point above or below all lines comes
|
||||
// up with a line or the beginning or end of the frame; 0 on Windows,
|
||||
// 1 on other platforms by default at the writing of this code
|
||||
int32_t dragOutOfFrame =
|
||||
Preferences::GetInt("browser.drag_out_of_frame_style");
|
||||
|
||||
if (prevLine == end) {
|
||||
if (dragOutOfFrame == 1 || nextLine == end)
|
||||
return DrillDownToSelectionFrame(aFrame, false, aFlags);
|
||||
closestLine = nextLine;
|
||||
} else if (nextLine == end) {
|
||||
if (dragOutOfFrame == 1)
|
||||
return DrillDownToSelectionFrame(aFrame, true, aFlags);
|
||||
closestLine = prevLine;
|
||||
} else { // Figure out which line is closer
|
||||
if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
|
||||
closestLine = prevLine;
|
||||
else
|
||||
closestLine = nextLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4975,6 +4975,7 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
|
||||
return target;
|
||||
++closestLine;
|
||||
} while (closestLine != end);
|
||||
|
||||
// Fall back to just targeting the last targetable place
|
||||
return DrillDownToSelectionFrame(aFrame, true, aFlags);
|
||||
}
|
||||
@ -5112,17 +5113,6 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(const nsPoint& aPo
|
||||
FrameTarget closest =
|
||||
GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
|
||||
|
||||
if (closest.emptyBlock) {
|
||||
ContentOffsets offsets;
|
||||
NS_ASSERTION(closest.frame,
|
||||
"closest.frame must not be null when it's empty");
|
||||
offsets.content = closest.frame->GetContent();
|
||||
offsets.offset = 0;
|
||||
offsets.secondaryOffset = 0;
|
||||
offsets.associate = CARET_ASSOCIATE_AFTER;
|
||||
return offsets;
|
||||
}
|
||||
|
||||
// If the correct offset is at one end of a frame, use offset-based
|
||||
// calculation method
|
||||
if (closest.frameEdge) {
|
||||
@ -8345,7 +8335,7 @@ nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
|
||||
nsIFrame* frame = this;
|
||||
nsContentAndOffset blockFrameOrBR;
|
||||
blockFrameOrBR.mContent = nullptr;
|
||||
bool reachedBlockAncestor = false;
|
||||
bool reachedBlockAncestor = !!nsLayoutUtils::GetAsBlock(frame);
|
||||
|
||||
// Go through containing frames until reaching a block frame.
|
||||
// In each step, search the previous (or next) siblings for the closest
|
||||
@ -8396,7 +8386,7 @@ nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
|
||||
break;
|
||||
}
|
||||
frame = parent;
|
||||
reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
|
||||
reachedBlockAncestor = !!nsLayoutUtils::GetAsBlock(frame);
|
||||
}
|
||||
if (reachedBlockAncestor) { // no "stop frame" found
|
||||
aPos->mResultContent = frame->GetContent();
|
||||
|
Loading…
Reference in New Issue
Block a user