Bug 758179. Part 3: Support SKIP_HIDDEN flag. r=mats

This commit is contained in:
Robert O'Callahan 2012-05-30 01:13:36 +12:00
parent 05d68e6828
commit 6b23199749

View File

@ -3091,12 +3091,17 @@ struct FrameTarget {
};
// See function implementation for information
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint);
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
PRUint32 aFlags);
static bool SelfIsSelectable(nsIFrame* aFrame)
static bool SelfIsSelectable(nsIFrame* aFrame, PRUint32 aFlags)
{
return !(aFrame->IsGeneratedContentFrame() ||
aFrame->GetStyleUIReset()->mUserSelect == NS_STYLE_USER_SELECT_NONE);
if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
!aFrame->GetStyleVisibility()->IsVisible()) {
return false;
}
return !aFrame->IsGeneratedContentFrame() &&
aFrame->GetStyleUIReset()->mUserSelect != NS_STYLE_USER_SELECT_NONE;
}
static bool SelectionDescendToKids(nsIFrame* aFrame) {
@ -3118,12 +3123,13 @@ static bool SelectionDescendToKids(nsIFrame* aFrame) {
}
static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
nsPoint aPoint)
nsPoint aPoint,
PRUint32 aFlags)
{
nsIFrame* parent = aChild->GetParent();
if (SelectionDescendToKids(aChild)) {
nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
return GetSelectionClosestFrame(aChild, pt);
return GetSelectionClosestFrame(aChild, pt, aFlags);
}
return FrameTarget(aChild, false, false);
}
@ -3134,12 +3140,12 @@ static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
// blocks, because that's not where it's expected.
// Note that this method is guaranteed to succeed.
static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
bool aEndFrame) {
bool aEndFrame, PRUint32 aFlags) {
if (SelectionDescendToKids(aFrame)) {
nsIFrame* result = nsnull;
nsIFrame *frame = aFrame->GetFirstPrincipalChild();
if (!aEndFrame) {
while (frame && (!SelfIsSelectable(frame) ||
while (frame && (!SelfIsSelectable(frame, aFlags) ||
frame->IsEmpty()))
frame = frame->GetNextSibling();
if (frame)
@ -3150,13 +3156,13 @@ static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
// XXX I have a feeling this could be slow for long blocks, although
// I can't find any slowdowns
while (frame) {
if (!frame->IsEmpty() && SelfIsSelectable(frame))
if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
result = frame;
frame = frame->GetNextSibling();
}
}
if (result)
return DrillDownToSelectionFrame(result, aEndFrame);
return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
}
// If the current frame has no targetable children, target the current frame
return FrameTarget(aFrame, true, aEndFrame);
@ -3167,23 +3173,24 @@ static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
static FrameTarget GetSelectionClosestFrameForLine(
nsBlockFrame* aParent,
nsBlockFrame::line_iterator aLine,
nsPoint aPoint)
nsPoint aPoint,
PRUint32 aFlags)
{
nsIFrame *frame = aLine->mFirstChild;
// Account for end of lines (any iterator from the block is valid)
if (aLine == aParent->end_lines())
return DrillDownToSelectionFrame(aParent, true);
return DrillDownToSelectionFrame(aParent, true, aFlags);
nsIFrame *closestFromLeft = nsnull, *closestFromRight = nsnull;
nsRect rect = aLine->mBounds;
nscoord closestLeft = rect.x, closestRight = rect.XMost();
for (PRInt32 n = aLine->GetChildCount(); n;
--n, frame = frame->GetNextSibling()) {
if (!SelfIsSelectable(frame) || frame->IsEmpty())
if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty())
continue;
nsRect frameRect = frame->GetRect();
if (aPoint.x >= frameRect.x) {
if (aPoint.x < frameRect.XMost()) {
return GetSelectionClosestFrameForChild(frame, aPoint);
return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
}
if (frameRect.XMost() >= closestLeft) {
closestFromLeft = frame;
@ -3204,9 +3211,9 @@ static FrameTarget GetSelectionClosestFrameForLine(
if (closestFromLeft &&
(!closestFromRight ||
(abs(aPoint.x - closestLeft) <= abs(aPoint.x - closestRight)))) {
return GetSelectionClosestFrameForChild(closestFromLeft, aPoint);
return GetSelectionClosestFrameForChild(closestFromLeft, aPoint, aFlags);
}
return GetSelectionClosestFrameForChild(closestFromRight, aPoint);
return GetSelectionClosestFrameForChild(closestFromRight, aPoint, aFlags);
}
// This method is for the special handling we do for block frames; they're
@ -3215,7 +3222,8 @@ static FrameTarget GetSelectionClosestFrameForLine(
// frame tree. Returns a null FrameTarget for frames which are not
// blocks or blocks with no lines except editable one.
static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
nsPoint aPoint)
nsPoint aPoint,
PRUint32 aFlags)
{
nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
if (!bf)
@ -3265,11 +3273,11 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
if (prevLine == end) {
if (dragOutOfFrame == 1 || nextLine == end)
return DrillDownToSelectionFrame(aFrame, false);
return DrillDownToSelectionFrame(aFrame, false, aFlags);
closestLine = nextLine;
} else if (nextLine == end) {
if (dragOutOfFrame == 1)
return DrillDownToSelectionFrame(aFrame, true);
return DrillDownToSelectionFrame(aFrame, true, aFlags);
closestLine = prevLine;
} else { // Figure out which line is closer
if (aPoint.y - prevLine->mBounds.YMost() < nextLine->mBounds.y - aPoint.y)
@ -3281,13 +3289,13 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
do {
FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
aPoint);
aPoint, aFlags);
if (!target.IsNull())
return target;
++closestLine;
} while (closestLine != end);
// Fall back to just targeting the last targetable place
return DrillDownToSelectionFrame(aFrame, true);
return DrillDownToSelectionFrame(aFrame, true, aFlags);
}
// GetSelectionClosestFrame is the helper function that calculates the closest
@ -3297,11 +3305,12 @@ static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
// Cannot handle overlapping frames correctly, so it should receive the output
// of GetFrameForPoint
// Guaranteed to return a valid FrameTarget
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
PRUint32 aFlags)
{
{
// Handle blocks; if the frame isn't a block, the method fails
FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint);
FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
if (!target.IsNull())
return target;
}
@ -3318,7 +3327,7 @@ static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
nsIFrame *closestFrame = nsnull;
for (; kid; kid = kid->GetNextSibling()) {
if (!SelfIsSelectable(kid) || kid->IsEmpty())
if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
continue;
nsRect rect = kid->GetRect();
@ -3356,7 +3365,7 @@ static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint)
}
}
if (closestFrame)
return GetSelectionClosestFrameForChild(closestFrame, aPoint);
return GetSelectionClosestFrameForChild(closestFrame, aPoint, aFlags);
}
return FrameTarget(aFrame, false, false);
}
@ -3447,7 +3456,8 @@ nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
FrameTarget closest = GetSelectionClosestFrame(adjustedFrame, adjustedPoint);
FrameTarget closest =
GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
if (closest.emptyBlock) {
ContentOffsets offsets;
@ -5833,7 +5843,7 @@ nsIFrame::GetExtremeCaretPosition(bool aStart)
{
CaretPosition result;
FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart);
FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
FrameContentRange range = GetRangeForFrame(targetFrame.frame);
result.mResultContent = range.content;
result.mContentOffset = aStart ? range.start : range.end;
@ -6284,7 +6294,7 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
if (!baseFrame)
return NS_ERROR_FAILURE;
FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
endOfLine);
endOfLine, 0);
FrameContentRange range = GetRangeForFrame(targetFrame.frame);
aPos->mResultContent = range.content;
aPos->mContentOffset = endOfLine ? range.end : range.start;