Bug 1077515 - part 3 - Change desiredX (nscoord) to desiredPos (nsPoint) in nsPeekOffsetStruct, to support maintaining either vertical or horizontal position on inter-line moves. r=roc

This commit is contained in:
Jonathan Kew 2014-11-22 14:39:03 +00:00
parent b10c2f71c0
commit ad52f329e8
11 changed files with 222 additions and 198 deletions

View File

@ -508,7 +508,7 @@ HyperTextAccessible::FindOffset(uint32_t aOffset, nsDirection aDirection,
const bool kIsKeyboardSelect = true; // is keyboard selection
const bool kIsVisualBidi = false; // use visual order for bidi text
nsPeekOffsetStruct pos(aAmount, aDirection, innerContentOffset,
0, kIsJumpLinesOk, kIsScrollViewAStop,
nsPoint(0, 0), kIsJumpLinesOk, kIsScrollViewAStop,
kIsKeyboardSelect, kIsVisualBidi,
aWordMovementType);
nsresult rv = frameAtOffset->PeekOffset(&pos);

View File

@ -635,7 +635,7 @@ CompareRangeWithContentOffset(nsRange* aRange,
nsPeekOffsetStruct pos(eSelectCluster,
dir,
offset,
0,
nsPoint(0, 0),
true,
true, //limit on scrolled views
false,

View File

@ -700,7 +700,9 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
nsBidiLevel baseLevel = NS_GET_BASE_LEVEL(frameAfter);
if (baseLevel != levelAfter)
{
nsPeekOffsetStruct pos(eSelectBeginLine, eDirPrevious, 0, 0, false, true, false, true);
nsPeekOffsetStruct pos(eSelectBeginLine, eDirPrevious, 0,
nsPoint(0, 0), false, true, false,
true);
if (NS_SUCCEEDED(frameAfter->PeekOffset(&pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;
@ -733,7 +735,9 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
nsBidiLevel baseLevel = NS_GET_BASE_LEVEL(frameBefore);
if (baseLevel != levelBefore)
{
nsPeekOffsetStruct pos(eSelectEndLine, eDirNext, 0, 0, false, true, false, true);
nsPeekOffsetStruct pos(eSelectEndLine, eDirNext, 0,
nsPoint(0, 0), false, true, false,
true);
if (NS_SUCCEEDED(frameBefore->PeekOffset(&pos))) {
theFrame = pos.mResultFrame;
theFrameOffset = pos.mContentOffset;

View File

@ -3091,7 +3091,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
nsPeekOffsetStruct pos(eSelectCharacter,
eDirNext,
aStartPos,
0,
nsPoint(0, 0),
aJumpLines,
true, //limit on scrolled views
false,
@ -3107,7 +3107,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
nsPeekOffsetStruct startpos(aAmountBack,
eDirPrevious,
baseOffset,
0,
nsPoint(0, 0),
aJumpLines,
true, //limit on scrolled views
false,
@ -3119,7 +3119,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
nsPeekOffsetStruct endpos(aAmountForward,
eDirNext,
aStartPos,
0,
nsPoint(0, 0),
aJumpLines,
true, //limit on scrolled views
false,
@ -6084,8 +6084,10 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
nsPoint offset;
nsView * view; //used for call of get offset from view
aBlockFrame->GetOffsetFromView(offset,&view);
nscoord newDesiredX = aPos->mDesiredX - offset.x;//get desired x into blockframe coordinates!
result = it->FindFrameAt(searchingLine, newDesiredX, &resultFrame, &isBeforeFirstFrame, &isAfterLastFrame);
nsPoint newDesiredPos =
aPos->mDesiredPos - offset; //get desired position into blockframe coords
result = it->FindFrameAt(searchingLine, newDesiredPos, &resultFrame,
&isBeforeFirstFrame, &isAfterLastFrame);
if(NS_FAILED(result))
continue;
}
@ -6116,8 +6118,6 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
nsIFrame *storeOldResultFrame = resultFrame;
while ( !found ){
nsPoint point;
point.x = aPos->mDesiredX;
nsRect tempRect = resultFrame->GetRect();
nsPoint offset;
nsView * view; //used for call of get offset from view
@ -6125,7 +6125,13 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
if (!view) {
return NS_ERROR_FAILURE;
}
point.y = tempRect.height + offset.y;
if (resultFrame->GetWritingMode().IsVertical()) {
point.y = aPos->mDesiredPos.y;
point.x = tempRect.width + offset.x;
} else {
point.y = tempRect.height + offset.y;
point.x = aPos->mDesiredPos.x;
}
//special check. if we allow non-text selection then we can allow a hit location to fall before a table.
//otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
@ -6208,7 +6214,7 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
);
}
while ( !found ){
nsPoint point(aPos->mDesiredX, 0);
nsPoint point = aPos->mDesiredPos;
nsView* view;
nsPoint offset;
resultFrame->GetOffsetFromView(offset, &view);

View File

@ -63,7 +63,7 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruct
nsPeekOffsetStruct(nsSelectionAmount aAmount,
nsDirection aDirection,
int32_t aStartOffset,
nscoord aDesiredX,
nsPoint aDesiredPos,
bool aJumpLines,
bool aScrollViewStop,
bool aIsKeyboardSelect,
@ -96,9 +96,10 @@ struct MOZ_STACK_CLASS nsPeekOffsetStruct
// Used with: eSelectCharacter, eSelectWord
int32_t mStartOffset;
// mDesiredX: The desired x coordinate for the caret.
// Used with: eSelectLine.
nscoord mDesiredX;
// mDesiredPos: The desired inline coordinate for the caret
// (one of .x or .y will be used, depending on line's writing mode)
// Used with: eSelectLine.
nsPoint mDesiredPos;
// mWordMovementType: An enum that determines whether to prefer the start or end of a word
// or to use the default beahvior, which is a combination of
@ -645,9 +646,9 @@ private:
nsSelectionAmount aAmount,
CaretMovementStyle aMovementStyle);
nsresult FetchDesiredX(nscoord &aDesiredX); //the x position requested by the Key Handling for up down
void InvalidateDesiredX(); //do not listen to mDesiredX you must get another.
void SetDesiredX(nscoord aX); //set the mDesiredX
nsresult FetchDesiredPos(nsPoint &aDesiredPos); //the position requested by the Key Handling for up down
void InvalidateDesiredPos(); //do not listen to mDesiredPos you must get another.
void SetDesiredPos(nsPoint aPos); //set the mDesiredPos
uint32_t GetBatching() const {return mBatching; }
bool GetNotifyFrames() const { return mNotifyFrames; }
@ -714,7 +715,7 @@ private:
CaretAssociateHint mHint; //hint to tell if the selection is at the end of this line or beginning of next
nsBidiLevel mCaretBidiLevel;
int32_t mDesiredX;
nsPoint mDesiredPos;
uint32_t mDelayedMouseEventClickCount;
bool mDelayedMouseEventIsShift;
bool mDelayedMouseEventValid;
@ -724,7 +725,7 @@ private:
bool mDragSelectingCells;
bool mDragState; //for drag purposes
bool mMouseDoubleDownState; //has the doubleclick down happened
bool mDesiredXSet;
bool mDesiredPosSet;
int8_t mCaretMovementStyle;
};

View File

@ -6,7 +6,7 @@
#define nsILineIterator_h___
#include "nscore.h"
#include "nsCoord.h"
#include "nsPoint.h"
#include "mozilla/Attributes.h"
class nsIFrame;
@ -82,15 +82,16 @@ public:
virtual int32_t FindLineContaining(nsIFrame* aFrame,
int32_t aStartLine = 0) = 0;
// Given a line number and an X coordinate, find the frame on the
// line that is nearest to the X coordinate. The
// aXIsBeforeFirstFrame and aXIsAfterLastFrame flags are updated
// Given a line number and a coordinate, find the frame on the line
// that is nearest to aPos along the inline axis. (The block-axis coord
// of aPos is irrelevant.)
// The aPosIsBeforeFirstFrame and aPosIsAfterLastFrame flags are updated
// appropriately.
NS_IMETHOD FindFrameAt(int32_t aLineNumber,
nscoord aX,
nsPoint aPos,
nsIFrame** aFrameFound,
bool* aXIsBeforeFirstFrame,
bool* aXIsAfterLastFrame) = 0;
bool* aPosIsBeforeFirstFrame,
bool* aPosIsAfterLastFrame) = 0;
// Give the line iterator implementor a chance todo something more complicated than
// nsIFrame::GetNextSibling()

View File

@ -711,14 +711,14 @@ nsLineIterator::CheckLineOrder(int32_t aLine,
NS_IMETHODIMP
nsLineIterator::FindFrameAt(int32_t aLineNumber,
nscoord aX,
nsPoint aPos,
nsIFrame** aFrameFound,
bool* aXIsBeforeFirstFrame,
bool* aXIsAfterLastFrame)
bool* aPosIsBeforeFirstFrame,
bool* aPosIsAfterLastFrame)
{
NS_PRECONDITION(aFrameFound && aXIsBeforeFirstFrame && aXIsAfterLastFrame,
NS_PRECONDITION(aFrameFound && aPosIsBeforeFirstFrame && aPosIsAfterLastFrame,
"null OUT ptr");
if (!aFrameFound || !aXIsBeforeFirstFrame || !aXIsAfterLastFrame) {
if (!aFrameFound || !aPosIsBeforeFirstFrame || !aPosIsAfterLastFrame) {
return NS_ERROR_NULL_POINTER;
}
if ((aLineNumber < 0) || (aLineNumber >= mNumLines)) {
@ -728,8 +728,8 @@ nsLineIterator::FindFrameAt(int32_t aLineNumber,
nsLineBox* line = mLines[aLineNumber];
if (!line) {
*aFrameFound = nullptr;
*aXIsBeforeFirstFrame = true;
*aXIsAfterLastFrame = false;
*aPosIsBeforeFirstFrame = true;
*aPosIsAfterLastFrame = false;
return NS_OK;
}
@ -737,51 +737,58 @@ nsLineIterator::FindFrameAt(int32_t aLineNumber,
return NS_ERROR_FAILURE;
nsIFrame* frame = line->mFirstChild;
nsIFrame* closestFromLeft = nullptr;
nsIFrame* closestFromRight = nullptr;
nsIFrame* closestFromStart = nullptr;
nsIFrame* closestFromEnd = nullptr;
WritingMode wm = line->mWritingMode;
nscoord cw = line->mContainerWidth;
LogicalPoint pos(wm, aPos, cw);
int32_t n = line->GetChildCount();
while (n--) {
nsRect rect = frame->GetRect();
if (rect.width > 0) {
// If aX is inside this frame - this is it
if (rect.x <= aX && rect.XMost() > aX) {
closestFromLeft = closestFromRight = frame;
LogicalRect rect = frame->GetLogicalRect(wm, cw);
if (rect.ISize(wm) > 0) {
// If pos.I() is inside this frame - this is it
if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) {
closestFromStart = closestFromEnd = frame;
break;
}
if (rect.x < aX) {
if (!closestFromLeft ||
rect.XMost() > closestFromLeft->GetRect().XMost())
closestFromLeft = frame;
if (rect.IStart(wm) < pos.I(wm)) {
if (!closestFromStart ||
rect.IEnd(wm) > closestFromStart->GetLogicalRect(wm, cw).IEnd(wm))
closestFromStart = frame;
}
else {
if (!closestFromRight ||
rect.x < closestFromRight->GetRect().x)
closestFromRight = frame;
if (!closestFromEnd ||
rect.IStart(wm) < closestFromEnd->GetLogicalRect(wm, cw).IStart(wm))
closestFromEnd = frame;
}
}
frame = frame->GetNextSibling();
}
if (!closestFromLeft && !closestFromRight) {
if (!closestFromStart && !closestFromEnd) {
// All frames were zero-width. Just take the first one.
closestFromLeft = closestFromRight = line->mFirstChild;
closestFromStart = closestFromEnd = line->mFirstChild;
}
*aXIsBeforeFirstFrame = mRightToLeft ? !closestFromRight : !closestFromLeft;
*aXIsAfterLastFrame = mRightToLeft ? !closestFromLeft : !closestFromRight;
if (closestFromLeft == closestFromRight) {
*aFrameFound = closestFromLeft;
*aPosIsBeforeFirstFrame = mRightToLeft ? !closestFromEnd : !closestFromStart;
*aPosIsAfterLastFrame = mRightToLeft ? !closestFromStart : !closestFromEnd;
if (closestFromStart == closestFromEnd) {
*aFrameFound = closestFromStart;
}
else if (!closestFromLeft) {
*aFrameFound = closestFromRight;
else if (!closestFromStart) {
*aFrameFound = closestFromEnd;
}
else if (!closestFromRight) {
*aFrameFound = closestFromLeft;
else if (!closestFromEnd) {
*aFrameFound = closestFromStart;
}
else { // we're between two frames
nscoord delta = closestFromRight->GetRect().x - closestFromLeft->GetRect().XMost();
if (aX < closestFromLeft->GetRect().XMost() + delta/2)
*aFrameFound = closestFromLeft;
nscoord delta = closestFromEnd->GetLogicalRect(wm, cw).IStart(wm) -
closestFromStart->GetLogicalRect(wm, cw).IEnd(wm);
if (pos.I(wm) < closestFromStart->GetLogicalRect(wm, cw).IEnd(wm) + delta/2)
*aFrameFound = closestFromStart;
else
*aFrameFound = closestFromRight;
*aFrameFound = closestFromEnd;
}
return NS_OK;
}

View File

@ -1705,10 +1705,10 @@ public:
uint32_t* aLineFlags) MOZ_OVERRIDE;
virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) MOZ_OVERRIDE;
NS_IMETHOD FindFrameAt(int32_t aLineNumber,
nscoord aX,
nsPoint aPos,
nsIFrame** aFrameFound,
bool* aXIsBeforeFirstFrame,
bool* aXIsAfterLastFrame) MOZ_OVERRIDE;
bool* aPosIsBeforeFirstFrame,
bool* aPosIsAfterLastFrame) MOZ_OVERRIDE;
NS_IMETHOD GetNextSiblingOnLine(nsIFrame*& aFrame, int32_t aLineNumber) MOZ_OVERRIDE;
NS_IMETHOD CheckLineOrder(int32_t aLine,

View File

@ -48,7 +48,6 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "mozilla/Preferences.h"
#include "nsDOMClassInfoID.h"
//included for desired x position;
#include "nsPresContext.h"
#include "nsIPresShell.h"
#include "nsCaret.h"
@ -108,7 +107,7 @@ static void printRange(nsRange *aDomRange);
nsPeekOffsetStruct::nsPeekOffsetStruct(nsSelectionAmount aAmount,
nsDirection aDirection,
int32_t aStartOffset,
nscoord aDesiredX,
nsPoint aDesiredPos,
bool aJumpLines,
bool aScrollViewStop,
bool aIsKeyboardSelect,
@ -117,7 +116,7 @@ nsPeekOffsetStruct::nsPeekOffsetStruct(nsSelectionAmount aAmount,
: mAmount(aAmount)
, mDirection(aDirection)
, mStartOffset(aStartOffset)
, mDesiredX(aDesiredX)
, mDesiredPos(aDesiredPos)
, mWordMovementType(aWordMovementType)
, mJumpLines(aJumpLines)
, mScrollViewStop(aScrollViewStop)
@ -436,57 +435,55 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsFrameSelection, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsFrameSelection, Release)
// Get the x (or y, in vertical writing mode) position requested
// by the Key Handling for line-up/down
nsresult
nsFrameSelection::FetchDesiredX(nscoord &aDesiredX) //the x position requested by the Key Handling for up down
nsFrameSelection::FetchDesiredPos(nsPoint &aDesiredPos)
{
if (!mShell)
{
NS_ERROR("fetch desired X failed");
if (!mShell) {
NS_ERROR("fetch desired position failed");
return NS_ERROR_FAILURE;
}
if (mDesiredXSet)
{
aDesiredX = mDesiredX;
if (mDesiredPosSet) {
aDesiredPos = mDesiredPos;
return NS_OK;
}
nsRefPtr<nsCaret> caret = mShell->GetCaret();
if (!caret)
if (!caret) {
return NS_ERROR_NULL_POINTER;
}
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
caret->SetSelection(mDomSelections[index]);
nsRect coord;
nsIFrame* caretFrame = caret->GetGeometry(&coord);
if (!caretFrame)
if (!caretFrame) {
return NS_ERROR_FAILURE;
}
nsPoint viewOffset(0, 0);
nsView* view = nullptr;
caretFrame->GetOffsetFromView(viewOffset, &view);
if (view)
coord.x += viewOffset.x;
aDesiredX = coord.x;
if (view) {
coord += viewOffset;
}
aDesiredPos = coord.TopLeft();
return NS_OK;
}
void
nsFrameSelection::InvalidateDesiredX() //do not listen to mDesiredX you must get another.
nsFrameSelection::InvalidateDesiredPos() // do not listen to mDesiredPos;
// you must get another.
{
mDesiredXSet = false;
mDesiredPosSet = false;
}
void
nsFrameSelection::SetDesiredX(nscoord aX) //set the mDesiredX
nsFrameSelection::SetDesiredPos(nsPoint aPos)
{
mDesiredX = aX;
mDesiredXSet = true;
mDesiredPos = aPos;
mDesiredPosSet = true;
}
nsresult
@ -718,7 +715,7 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter)
{
mShell = aShell;
mDragState = false;
mDesiredXSet = false;
mDesiredPosSet = false;
mLimiter = aLimiter;
mCaretMovementStyle =
Preferences::GetInt("bidi.edit.caret_movement_style", 2);
@ -766,7 +763,7 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
return NS_ERROR_FAILURE;
bool isCollapsed;
nscoord desiredX = 0; //we must keep this around and revalidate it when its just UP/DOWN
nsPoint desiredPos(0, 0); //we must keep this around and revalidate it when its just UP/DOWN
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsRefPtr<Selection> sel = mDomSelections[index];
@ -786,13 +783,15 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
}
nsresult result = sel->GetIsCollapsed(&isCollapsed);
if (NS_FAILED(result))
if (NS_FAILED(result)) {
return result;
}
if (aAmount == eSelectLine) {
result = FetchDesiredX(desiredX);
if (NS_FAILED(result))
result = FetchDesiredPos(desiredPos);
if (NS_FAILED(result)) {
return result;
SetDesiredX(desiredX);
}
SetDesiredPos(desiredPos);
}
int32_t caretStyle = Preferences::GetInt("layout.selection.caret_style", 0);
@ -850,7 +849,7 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
//set data using mLimiter to stop on scroll views. If we have a limiter then we stop peeking
//when we hit scrollable views. If no limiter then just let it go ahead
nsPeekOffsetStruct pos(aAmount, eDirPrevious, offsetused, desiredX,
nsPeekOffsetStruct pos(aAmount, eDirPrevious, offsetused, desiredPos,
true, mLimiter != nullptr, true, visualMovement);
nsBidiDirection paraDir = nsBidiPresUtils::ParagraphDirection(frame);
@ -861,7 +860,7 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
case eSelectCluster:
case eSelectWord:
case eSelectWordNoSpace:
InvalidateDesiredX();
InvalidateDesiredPos();
pos.mAmount = aAmount;
pos.mDirection = (visualMovement && paraDir == NSBIDI_RTL)
? nsDirection(1 - aDirection) : aDirection;
@ -872,7 +871,7 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
break;
case eSelectBeginLine:
case eSelectEndLine:
InvalidateDesiredX();
InvalidateDesiredPos();
pos.mAmount = aAmount;
pos.mDirection = (visualMovement && paraDir == NSBIDI_RTL)
? nsDirection(1 - aDirection) : aDirection;
@ -1369,7 +1368,7 @@ nsFrameSelection::HandleClick(nsIContent* aNewFocus,
if (!aNewFocus)
return NS_ERROR_INVALID_ARG;
InvalidateDesiredX();
InvalidateDesiredPos();
if (!aContinueSelection) {
mMaintainRange = nullptr;
@ -1441,15 +1440,16 @@ nsFrameSelection::HandleDrag(nsIFrame *aFrame, nsPoint aPoint)
if (frame && amount == eSelectWord && direction == eDirPrevious) {
// To avoid selecting the previous word when at start of word,
// first move one character forward.
nsPeekOffsetStruct charPos(eSelectCharacter, eDirNext, offset, 0,
false, mLimiter != nullptr, false, false);
nsPeekOffsetStruct charPos(eSelectCharacter, eDirNext, offset,
nsPoint(0, 0), false, mLimiter != nullptr,
false, false);
if (NS_SUCCEEDED(frame->PeekOffset(&charPos))) {
frame = charPos.mResultFrame;
offset = charPos.mContentOffset;
}
}
nsPeekOffsetStruct pos(amount, direction, offset, 0,
nsPeekOffsetStruct pos(amount, direction, offset, nsPoint(0, 0),
false, mLimiter != nullptr, false, false);
if (frame && NS_SUCCEEDED(frame->PeekOffset(&pos)) && pos.mResultContent) {
@ -1538,17 +1538,16 @@ nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
mDomSelections[index]->AddRange(newRange);
mBatching = batching;
mChangesDuringBatching = changes;
}
else
{
bool oldDesiredXSet = mDesiredXSet; //need to keep old desired X if it was set.
} else {
bool oldDesiredPosSet = mDesiredPosSet; //need to keep old desired position if it was set.
mDomSelections[index]->Collapse(aNewFocus, aContentOffset);
mDesiredXSet = oldDesiredXSet; //now reset desired X back.
mDesiredPosSet = oldDesiredPosSet; //now reset desired pos back.
mBatching = batching;
mChangesDuringBatching = changes;
}
if (aContentEndOffset != aContentOffset)
if (aContentEndOffset != aContentOffset) {
mDomSelections[index]->Extend(aNewFocus, aContentEndOffset);
}
//find out if we are inside a table. if so, find out which one and which cell
//once we do that, the next time we get a takefocus, check the parent tree.
@ -1857,10 +1856,11 @@ nsFrameSelection::CommonPageMove(bool aForward,
return;
// find out where the caret is.
// we should know mDesiredX value of nsFrameSelection, but I havent seen that behavior in other windows applications yet.
// we should know mDesiredPos value of nsFrameSelection, but I havent seen that behavior in other windows applications yet.
nsISelection* domSel = GetSelection(nsISelectionController::SELECTION_NORMAL);
if (!domSel)
if (!domSel) {
return;
}
nsRect caretPos;
nsIFrame* caretFrame = nsCaret::GetGeometry(domSel, &caretPos);
@ -4592,7 +4592,7 @@ Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
nsCOMPtr<nsINode> kungfuDeathGrip = &aParentNode;
mFrameSelection->InvalidateDesiredX();
mFrameSelection->InvalidateDesiredPos();
if (!IsValidSelectionPoint(mFrameSelection, &aParentNode)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
@ -5887,9 +5887,9 @@ Selection::SelectionLanguageChange(bool aLangRTL)
mFrameSelection->SetCaretBidiLevel(levelAfter);
}
// The caret might have moved, so invalidate the desired X position
// The caret might have moved, so invalidate the desired position
// for future usages of up-arrow or down-arrow
mFrameSelection->InvalidateDesiredX();
mFrameSelection->InvalidateDesiredPos();
return NS_OK;
}

View File

@ -1732,84 +1732,89 @@ nsTableRowGroupFrame::CheckLineOrder(int32_t aLine,
NS_IMETHODIMP
nsTableRowGroupFrame::FindFrameAt(int32_t aLineNumber,
nscoord aX,
nsPoint aPos,
nsIFrame** aFrameFound,
bool* aXIsBeforeFirstFrame,
bool* aXIsAfterLastFrame)
bool* aPosIsBeforeFirstFrame,
bool* aPosIsAfterLastFrame)
{
nsTableFrame* table = nsTableFrame::GetTableFrame(this);
nsTableCellMap* cellMap = table->GetCellMap();
*aFrameFound = nullptr;
*aXIsBeforeFirstFrame = true;
*aXIsAfterLastFrame = false;
nsTableFrame* table = nsTableFrame::GetTableFrame(this);
nsTableCellMap* cellMap = table->GetCellMap();
aLineNumber += GetStartRowIndex();
int32_t numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
if (numCells == 0) {
return NS_OK;
}
WritingMode wm = table->GetWritingMode();
nscoord cw = table->GetRect().width;
LogicalPoint pos(wm, aPos, cw);
nsIFrame* frame = nullptr;
int32_t colCount = table->GetColCount();
for (int32_t i = 0; i < colCount; i++) {
CellData* data = cellMap->GetDataAt(aLineNumber, i);
if (data && data->IsOrig()) {
frame = (nsIFrame*)data->GetCellFrame();
break;
}
}
NS_ASSERTION(frame, "cellmap is lying");
bool isRTL = (NS_STYLE_DIRECTION_RTL ==
table->StyleVisibility()->mDirection);
nsIFrame* closestFromLeft = nullptr;
nsIFrame* closestFromRight = nullptr;
int32_t n = numCells;
nsIFrame* firstFrame = frame;
while (n--) {
nsRect rect = frame->GetRect();
if (rect.width > 0) {
// If aX is inside this frame - this is it
if (rect.x <= aX && rect.XMost() > aX) {
closestFromLeft = closestFromRight = frame;
break;
}
if (rect.x < aX) {
if (!closestFromLeft ||
rect.XMost() > closestFromLeft->GetRect().XMost())
closestFromLeft = frame;
}
else {
if (!closestFromRight ||
rect.x < closestFromRight->GetRect().x)
closestFromRight = frame;
}
}
frame = frame->GetNextSibling();
}
if (!closestFromLeft && !closestFromRight) {
// All frames were zero-width. Just take the first one.
closestFromLeft = closestFromRight = firstFrame;
}
*aXIsBeforeFirstFrame = isRTL ? !closestFromRight : !closestFromLeft;
*aXIsAfterLastFrame = isRTL ? !closestFromLeft : !closestFromRight;
if (closestFromLeft == closestFromRight) {
*aFrameFound = closestFromLeft;
}
else if (!closestFromLeft) {
*aFrameFound = closestFromRight;
}
else if (!closestFromRight) {
*aFrameFound = closestFromLeft;
}
else { // we're between two frames
nscoord delta = closestFromRight->GetRect().x -
closestFromLeft->GetRect().XMost();
if (aX < closestFromLeft->GetRect().XMost() + delta/2)
*aFrameFound = closestFromLeft;
else
*aFrameFound = closestFromRight;
*aFrameFound = nullptr;
*aPosIsBeforeFirstFrame = true;
*aPosIsAfterLastFrame = false;
aLineNumber += GetStartRowIndex();
int32_t numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
if (numCells == 0) {
return NS_OK;
}
nsIFrame* frame = nullptr;
int32_t colCount = table->GetColCount();
for (int32_t i = 0; i < colCount; i++) {
CellData* data = cellMap->GetDataAt(aLineNumber, i);
if (data && data->IsOrig()) {
frame = (nsIFrame*)data->GetCellFrame();
break;
}
}
NS_ASSERTION(frame, "cellmap is lying");
bool isRTL = (NS_STYLE_DIRECTION_RTL ==
table->StyleVisibility()->mDirection);
nsIFrame* closestFromStart = nullptr;
nsIFrame* closestFromEnd = nullptr;
int32_t n = numCells;
nsIFrame* firstFrame = frame;
while (n--) {
LogicalRect rect = frame->GetLogicalRect(wm, cw);
if (rect.ISize(wm) > 0) {
// If pos.I() is inside this frame - this is it
if (rect.IStart(wm) <= pos.I(wm) && rect.IEnd(wm) > pos.I(wm)) {
closestFromStart = closestFromEnd = frame;
break;
}
if (rect.IStart(wm) < pos.I(wm)) {
if (!closestFromStart ||
rect.IEnd(wm) > closestFromStart->GetLogicalRect(wm, cw).IEnd(wm))
closestFromStart = frame;
}
else {
if (!closestFromEnd ||
rect.IStart(wm) < closestFromEnd->GetLogicalRect(wm, cw).IStart(wm))
closestFromEnd = frame;
}
}
frame = frame->GetNextSibling();
}
if (!closestFromStart && !closestFromEnd) {
// All frames were zero-width. Just take the first one.
closestFromStart = closestFromEnd = firstFrame;
}
*aPosIsBeforeFirstFrame = isRTL ? !closestFromEnd : !closestFromStart;
*aPosIsAfterLastFrame = isRTL ? !closestFromStart : !closestFromEnd;
if (closestFromStart == closestFromEnd) {
*aFrameFound = closestFromStart;
}
else if (!closestFromStart) {
*aFrameFound = closestFromEnd;
}
else if (!closestFromEnd) {
*aFrameFound = closestFromStart;
}
else { // we're between two frames
nscoord delta = closestFromEnd->GetLogicalRect(wm, cw).IStart(wm) -
closestFromStart->GetLogicalRect(wm, cw).IEnd(wm);
if (pos.I(wm) < closestFromStart->GetLogicalRect(wm, cw).IEnd(wm) + delta/2) {
*aFrameFound = closestFromStart;
} else {
*aFrameFound = closestFromEnd;
}
}
return NS_OK;
}

View File

@ -228,21 +228,21 @@ public:
virtual int32_t FindLineContaining(nsIFrame* aFrame, int32_t aStartLine = 0) MOZ_OVERRIDE;
/** Find the orginating cell frame on a row that is the nearest to the
* coordinate X.
* inline-dir coordinate of aPos.
* @param aLineNumber - the index of the row relative to the row group
* @param aX - X coordinate in twips relative to the
* @param aPos - coordinate in twips relative to the
* origin of the row group
* @param aFrameFound - pointer to the cellframe
* @param aXIsBeforeFirstFrame - the point is before the first originating
* @param aPosIsBeforeFirstFrame - the point is before the first originating
* cellframe
* @param aXIsAfterLastFrame - the point is after the last originating
* @param aPosIsAfterLastFrame - the point is after the last originating
* cellframe
*/
NS_IMETHOD FindFrameAt(int32_t aLineNumber,
nscoord aX,
nsPoint aPos,
nsIFrame** aFrameFound,
bool* aXIsBeforeFirstFrame,
bool* aXIsAfterLastFrame) MOZ_OVERRIDE;
bool* aPosIsBeforeFirstFrame,
bool* aPosIsAfterLastFrame) MOZ_OVERRIDE;
/** Check whether visual and logical order of cell frames within a line are
* identical. As the layout will reorder them this is always the case