Bug 619273 - Move the selection state bit from frames to content nodes. r=smaug

This commit is contained in:
Mats Palmgren 2011-12-20 10:15:41 +01:00
Родитель 5fb4d8f356
Коммит 498185f3f0
25 изменённых файлов: 481 добавлений и 352 удалений

Просмотреть файл

@ -106,9 +106,7 @@ nsHTMLTableCellAccessible::NativeState()
if (frame) {
state |= states::SELECTABLE;
bool isSelected = false;
frame->GetSelected(&isSelected);
if (isSelected)
if (frame->IsSelected())
state |= states::SELECTED;
}

Просмотреть файл

@ -916,6 +916,18 @@ public:
#endif
}
/**
* Returns true if |this| node is the common ancestor of the start/end
* nodes of a Range in a Selection or a descendant of such a common ancestor.
* This node is definitely not selected when |false| is returned, but it may
* or may not be selected when |true| is returned.
*/
bool IsSelectionDescendant() const
{
return IsDescendantOfCommonAncestorForRangeInSelection() ||
IsCommonAncestorForRangeInSelection();
}
/**
* Get the root content of an editor. So, this node must be a descendant of
* an editor. Note that this should be only used for getting input or textarea
@ -1201,6 +1213,11 @@ private:
ElementHasName,
// Set if the element might have a contenteditable attribute set.
ElementMayHaveContentEditableAttr,
// Set if the node is the common ancestor of the start/end nodes of a Range
// that is in a Selection.
NodeIsCommonAncestorForRangeInSelection,
// Set if the node is a descendant of a node with the above bit set.
NodeIsDescendantOfCommonAncestorForRangeInSelection,
// Guard value
BooleanFlagCount
};
@ -1235,6 +1252,18 @@ public:
bool HasName() const { return GetBoolFlag(ElementHasName); }
bool MayHaveContentEditableAttr() const
{ return GetBoolFlag(ElementMayHaveContentEditableAttr); }
bool IsCommonAncestorForRangeInSelection() const
{ return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
void SetCommonAncestorForRangeInSelection()
{ SetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
void ClearCommonAncestorForRangeInSelection()
{ ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
bool IsDescendantOfCommonAncestorForRangeInSelection() const
{ return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
void SetDescendantOfCommonAncestorForRangeInSelection()
{ SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
void ClearDescendantOfCommonAncestorForRangeInSelection()
{ ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }

Просмотреть файл

@ -40,8 +40,10 @@
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsINode.h"
#include "nsIDOMRange.h"
#include "nsTHashtable.h"
// IID for the nsIRange interface
#define NS_IRANGE_IID \
@ -60,7 +62,8 @@ public:
mEndOffset(0),
mIsPositioned(false),
mIsDetached(false),
mMaySpanAnonymousSubtrees(false)
mMaySpanAnonymousSubtrees(false),
mInSelection(false)
{
}
@ -110,6 +113,33 @@ public:
mMaySpanAnonymousSubtrees = aMaySpanAnonymousSubtrees;
}
/**
* Return true iff this range is part of at least one Selection object
* and isn't detached.
*/
bool IsInSelection() const
{
return mInSelection;
}
/**
* Called when the range is added/removed from a Selection.
*/
void SetInSelection(bool aInSelection)
{
if (mInSelection == aInSelection || mIsDetached) {
return;
}
mInSelection = aInSelection;
nsINode* commonAncestor = GetCommonAncestor();
NS_ASSERTION(commonAncestor, "unexpected disconnected nodes");
if (mInSelection) {
RegisterCommonAncestor(commonAncestor);
} else {
UnregisterCommonAncestor(commonAncestor);
}
}
virtual nsINode* GetCommonAncestor() const = 0;
virtual void Reset() = 0;
@ -128,7 +158,12 @@ public:
// To support the font inspector API
NS_IMETHOD GetUsedFontFaces(nsIDOMFontFaceList** aResult) = 0;
typedef nsTHashtable<nsPtrHashKey<nsIRange> > RangeHashTable;
protected:
void RegisterCommonAncestor(nsINode* aNode);
void UnregisterCommonAncestor(nsINode* aNode);
nsINode* IsValidBoundary(nsINode* aNode);
nsCOMPtr<nsINode> mRoot;
nsCOMPtr<nsINode> mStartParent;
nsCOMPtr<nsINode> mEndParent;
@ -138,6 +173,7 @@ protected:
bool mIsPositioned;
bool mIsDetached;
bool mMaySpanAnonymousSubtrees;
bool mInSelection;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIRange, NS_IRANGE_IID)

Просмотреть файл

@ -63,11 +63,8 @@
// whitespace, we may need to reframe it (or its ancestors).
#define NS_REFRAME_IF_WHITESPACE (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 1))
// This bit is set to indicate that the text may be part of a selection.
#define NS_TEXT_IN_SELECTION (1 << (NODE_TYPE_SPECIFIC_BITS_OFFSET + 2))
// Make sure we have enough space for those bits
PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 2 < 32);
PR_STATIC_ASSERT(NODE_TYPE_SPECIFIC_BITS_OFFSET + 1 < 32);
class nsIDOMAttr;
class nsIDOMEventListener;

Просмотреть файл

@ -91,6 +91,9 @@
#endif /* MOZ_XUL */
#include "nsFrameManager.h"
#include "nsFrameSelection.h"
#ifdef DEBUG
#include "nsIRange.h"
#endif
#include "nsBindingManager.h"
#include "nsXBLBinding.h"
@ -4932,6 +4935,11 @@ nsGenericElement::List(FILE* out, PRInt32 aIndent,
fprintf(out, " state=[%llx]", State().GetInternalValue());
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
if (IsCommonAncestorForRangeInSelection()) {
nsIRange::RangeHashTable* ranges =
static_cast<nsIRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
}
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
fprintf(out, " refcount=%d<", mRefCnt.get());

Просмотреть файл

@ -836,6 +836,7 @@ GK_ATOM(queryset, "queryset")
GK_ATOM(querytype, "querytype")
GK_ATOM(radio, "radio")
GK_ATOM(radiogroup, "radiogroup")
GK_ATOM(range, "range")
GK_ATOM(readonly, "readonly")
GK_ATOM(rect, "rect")
GK_ATOM(rectangle, "rectangle")

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mats Palmgren <matspal@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -156,6 +157,69 @@ nsRange::CompareNodeToRange(nsINode* aNode, nsIRange* aRange,
return NS_OK;
}
struct FindSelectedRangeData
{
nsINode* mNode;
nsIRange* mResult;
PRUint32 mStartOffset;
PRUint32 mEndOffset;
};
static PLDHashOperator
FindSelectedRange(nsPtrHashKey<nsIRange>* aEntry, void* userArg)
{
nsIRange* range = aEntry->GetKey();
if (range->IsInSelection() && !range->Collapsed()) {
FindSelectedRangeData* data = static_cast<FindSelectedRangeData*>(userArg);
PRInt32 cmp = nsContentUtils::ComparePoints(data->mNode, data->mEndOffset,
range->GetStartParent(),
range->StartOffset());
if (cmp == 1) {
cmp = nsContentUtils::ComparePoints(data->mNode, data->mStartOffset,
range->GetEndParent(),
range->EndOffset());
if (cmp == -1) {
data->mResult = range;
return PL_DHASH_STOP;
}
}
}
return PL_DHASH_NEXT;
}
static nsINode*
GetNextRangeCommonAncestor(nsINode* aNode)
{
while (aNode && !aNode->IsCommonAncestorForRangeInSelection()) {
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
return nsnull;
}
aNode = aNode->GetNodeParent();
}
return aNode;
}
/* static */ bool
nsRange::IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
PRUint32 aEndOffset)
{
NS_PRECONDITION(aNode, "bad arg");
FindSelectedRangeData data = { aNode, nsnull, aStartOffset, aEndOffset };
nsINode* n = GetNextRangeCommonAncestor(aNode);
NS_ASSERTION(n || !aNode->IsSelectionDescendant(),
"orphan selection descendant");
for (; n; n = GetNextRangeCommonAncestor(n->GetNodeParent())) {
RangeHashTable* ranges =
static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
ranges->EnumerateEntries(FindSelectedRange, &data);
if (data.mResult) {
return true;
}
}
return false;
}
/******************************************************
* non members
******************************************************/
@ -225,8 +289,10 @@ NS_NewRange(nsIDOMRange** aResult)
nsRange::~nsRange()
{
DoSetRange(nsnull, 0, nsnull, 0, nsnull);
NS_ASSERTION(!IsInSelection(), "deleting nsRange that is in use");
// we want the side effects (releases and list removals)
DoSetRange(nsnull, 0, nsnull, 0, nsnull);
}
/******************************************************
@ -260,6 +326,94 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsRange)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
static void
RangeHashTableDtor(void* aObject, nsIAtom* aPropertyName, void* aPropertyValue,
void* aData)
{
nsIRange::RangeHashTable* ranges =
static_cast<nsIRange::RangeHashTable*>(aPropertyValue);
delete ranges;
}
static void MarkDescendants(nsINode* aNode)
{
// Set NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
// descendants unless aNode is already marked as a range common ancestor
// or a descendant of one, in which case all of our descendants have the
// bit set already.
if (!aNode->IsSelectionDescendant()) {
// don't set the Descendant bit on |aNode| itself
nsINode* node = aNode->GetNextNode(aNode);
while (node) {
node->SetDescendantOfCommonAncestorForRangeInSelection();
if (!node->IsCommonAncestorForRangeInSelection()) {
node = node->GetNextNode(aNode);
} else {
// optimize: skip this sub-tree since it's marked already.
node = node->GetNextNonChildNode(aNode);
}
}
}
}
static void UnmarkDescendants(nsINode* aNode)
{
// Unset NodeIsDescendantOfCommonAncestorForRangeInSelection on aNode's
// descendants unless aNode is a descendant of another range common ancestor.
// Also, exclude descendants of range common ancestors (but not the common
// ancestor itself).
if (!aNode->IsDescendantOfCommonAncestorForRangeInSelection()) {
// we know |aNode| doesn't have any bit set
nsINode* node = aNode->GetNextNode(aNode);
while (node) {
node->ClearDescendantOfCommonAncestorForRangeInSelection();
if (!node->IsCommonAncestorForRangeInSelection()) {
node = node->GetNextNode(aNode);
} else {
// We found an ancestor of an overlapping range, skip its descendants.
node = node->GetNextNonChildNode(aNode);
}
}
}
}
void
nsIRange::RegisterCommonAncestor(nsINode* aNode)
{
NS_PRECONDITION(aNode, "bad arg");
NS_ASSERTION(IsInSelection(), "registering range not in selection");
MarkDescendants(aNode);
RangeHashTable* ranges =
static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
if (!ranges) {
ranges = new RangeHashTable;
ranges->Init();
aNode->SetProperty(nsGkAtoms::range, ranges, RangeHashTableDtor);
}
ranges->PutEntry(this);
aNode->SetCommonAncestorForRangeInSelection();
}
void
nsIRange::UnregisterCommonAncestor(nsINode* aNode)
{
NS_PRECONDITION(aNode, "bad arg");
NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
RangeHashTable* ranges =
static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
NS_ASSERTION(ranges->GetEntry(this), "unknown range");
if (ranges->Count() == 1) {
aNode->ClearCommonAncestorForRangeInSelection();
aNode->DeleteProperty(nsGkAtoms::range);
UnmarkDescendants(aNode);
} else {
ranges->RemoveEntry(this);
}
}
/******************************************************
* nsIMutationObserver implementation
******************************************************/
@ -293,6 +447,15 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
if (NS_UNLIKELY(aContent == mRoot)) {
newRoot = IsValidBoundary(newStartNode);
}
bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
if (isCommonAncestor) {
UnregisterCommonAncestor(mStartParent);
RegisterCommonAncestor(newStartNode);
}
if (mStartParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
newStartNode->SetDescendantOfCommonAncestorForRangeInSelection();
}
} else {
// If boundary is inside changed text, position it before change
// else adjust start offset for the change in length.
@ -317,6 +480,16 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
"mEndOffset is beyond the end of this node");
newEndOffset = static_cast<PRUint32>(mEndOffset) - aInfo->mChangeStart;
newEndNode = aInfo->mDetails->mNextSibling;
bool isCommonAncestor = IsInSelection() && mStartParent == mEndParent;
if (isCommonAncestor && !newStartNode) {
// The split occurs inside the range.
UnregisterCommonAncestor(mStartParent);
RegisterCommonAncestor(mStartParent->GetParent());
newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
} else if (mEndParent->IsDescendantOfCommonAncestorForRangeInSelection()) {
newEndNode->SetDescendantOfCommonAncestorForRangeInSelection();
}
} else {
mEndOffset = static_cast<PRUint32>(mEndOffset) <= aInfo->mChangeEnd ?
aInfo->mChangeStart :
@ -355,11 +528,29 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument,
newEndOffset = mEndOffset;
}
DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset,
newRoot ? newRoot : mRoot.get()
#ifdef DEBUG
, !newEndNode->GetParent() || !newStartNode->GetParent()
#endif
);
newRoot ? newRoot : mRoot.get(),
!newEndNode->GetParent() || !newStartNode->GetParent());
}
}
void
nsRange::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aFirstNewContent,
PRInt32 aNewIndexInContainer)
{
NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
nsINode* container = NODE_FROM(aContainer, aDocument);
if (container->IsSelectionDescendant() && IsInSelection()) {
nsINode* child = aFirstNewContent;
while (child) {
if (!child->IsDescendantOfCommonAncestorForRangeInSelection()) {
MarkDescendants(child);
child->SetDescendantOfCommonAncestorForRangeInSelection();
}
child = child->GetNextSibling();
}
}
}
@ -380,6 +571,11 @@ nsRange::ContentInserted(nsIDocument* aDocument,
if (container == mEndParent && aIndexInContainer < mEndOffset) {
++mEndOffset;
}
if (container->IsSelectionDescendant() &&
!aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
MarkDescendants(aChild);
aChild->SetDescendantOfCommonAncestorForRangeInSelection();
}
}
void
@ -392,6 +588,8 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
NS_ASSERTION(mIsPositioned, "shouldn't be notified if not positioned");
nsINode* container = NODE_FROM(aContainer, aDocument);
bool gravitateStart = false;
bool gravitateEnd = false;
// Adjust position if a sibling was removed...
if (container == mStartParent) {
@ -401,8 +599,7 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
}
// ...or gravitate if an ancestor was removed.
else if (nsContentUtils::ContentIsDescendantOf(mStartParent, aChild)) {
mStartParent = container;
mStartOffset = aIndexInContainer;
gravitateStart = true;
}
// Do same thing for end boundry.
@ -412,8 +609,20 @@ nsRange::ContentRemoved(nsIDocument* aDocument,
}
}
else if (nsContentUtils::ContentIsDescendantOf(mEndParent, aChild)) {
mEndParent = container;
mEndOffset = aIndexInContainer;
gravitateEnd = true;
}
if (gravitateStart || gravitateEnd) {
DoSetRange(gravitateStart ? container : mStartParent.get(),
gravitateStart ? aIndexInContainer : mStartOffset,
gravitateEnd ? container : mEndParent.get(),
gravitateEnd ? aIndexInContainer : mEndOffset,
mRoot);
}
if (container->IsSelectionDescendant() &&
aChild->IsDescendantOfCommonAncestorForRangeInSelection()) {
aChild->ClearDescendantOfCommonAncestorForRangeInSelection();
UnmarkDescendants(aChild);
}
}
@ -507,11 +716,7 @@ static PRUint32 GetNodeLength(nsINode *aNode)
void
nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
nsINode* aEndN, PRInt32 aEndOffset,
nsINode* aRoot
#ifdef DEBUG
, bool aNotInsertedYet
#endif
)
nsINode* aRoot, bool aNotInsertedYet)
{
NS_PRECONDITION((aStartN && aEndN && aRoot) ||
(!aStartN && !aEndN && !aRoot),
@ -545,12 +750,29 @@ nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
aRoot->AddMutationObserver(this);
}
}
bool checkCommonAncestor = (mStartParent != aStartN || mEndParent != aEndN) &&
IsInSelection() && !aNotInsertedYet;
nsINode* oldCommonAncestor = checkCommonAncestor ? GetCommonAncestor() : nsnull;
mStartParent = aStartN;
mStartOffset = aStartOffset;
mEndParent = aEndN;
mEndOffset = aEndOffset;
mIsPositioned = !!mStartParent;
if (checkCommonAncestor) {
nsINode* newCommonAncestor = GetCommonAncestor();
if (newCommonAncestor != oldCommonAncestor) {
if (oldCommonAncestor) {
UnregisterCommonAncestor(oldCommonAncestor);
}
if (newCommonAncestor) {
RegisterCommonAncestor(newCommonAncestor);
} else {
NS_ASSERTION(mIsDetached, "unexpected disconnected nodes");
mInSelection = false;
}
}
}
// This needs to be the last thing this function does. See comment
// in ParentChainChanged.
mRoot = aRoot;
@ -664,7 +886,7 @@ nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
return NS_ERROR_NOT_INITIALIZED;
}
nsINode* nsRange::IsValidBoundary(nsINode* aNode)
nsINode* nsIRange::IsValidBoundary(nsINode* aNode)
{
if (!aNode) {
return nsnull;

Просмотреть файл

@ -77,9 +77,7 @@ class nsRange : public nsIRange,
public nsStubMutationObserver
{
public:
nsRange()
{
}
nsRange(){}
virtual ~nsRange();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -116,14 +114,13 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
private:
// no copy's or assigns
nsRange(const nsRange&);
nsRange& operator=(const nsRange&);
nsINode* IsValidBoundary(nsINode* aNode);
/**
* Cut or delete the range's contents.
*
@ -157,16 +154,17 @@ public:
bool *outNodeBefore,
bool *outNodeAfter);
static bool IsNodeSelected(nsINode* aNode, PRUint32 aStartOffset,
PRUint32 aEndOffset);
protected:
// CharacterDataChanged set aNotInsertedYet to true to disable an assertion
// and suppress re-registering a range common ancestor node since
// the new text node of a splitText hasn't been inserted yet.
// CharacterDataChanged does the re-registering when needed.
void DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
nsINode* aEndN, PRInt32 aEndOffset,
nsINode* aRoot
#ifdef DEBUG
// CharacterDataChanged use this to disable an assertion since
// the new text node of a splitText hasn't been inserted yet.
, bool aNotInsertedYet = false
#endif
);
nsINode* aRoot, bool aNotInsertedYet = false);
};
// Make a new nsIDOMRange object

Просмотреть файл

@ -46,6 +46,9 @@
#include "nsIAttribute.h"
#include "nsIDocument.h"
#include "nsThreadUtils.h"
#ifdef DEBUG
#include "nsIRange.h"
#endif
using namespace mozilla::dom;
@ -224,6 +227,12 @@ nsTextNode::List(FILE* out, PRInt32 aIndent) const
fprintf(out, "Text@%p", static_cast<const void*>(this));
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
if (IsCommonAncestorForRangeInSelection()) {
typedef nsTHashtable<nsPtrHashKey<nsIRange> > RangeHashTable;
RangeHashTable* ranges =
static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
}
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
fprintf(out, " refcount=%d<", mRefCnt.get());

Просмотреть файл

@ -217,8 +217,8 @@ public:
void SetIncludeAllOutOfFlows() { mIncludeAllOutOfFlows = true; }
bool GetIncludeAllOutOfFlows() const { return mIncludeAllOutOfFlows; }
/**
* Calling this setter makes us exclude all leaf frames that does
* not have the NS_FRAME_SELECTED_CONTENT bit.
* Calling this setter makes us exclude all leaf frames that aren't
* selected.
*/
void SetSelectedFramesOnly() { mSelectedFramesOnly = true; }
bool GetSelectedFramesOnly() { return mSelectedFramesOnly; }

Просмотреть файл

@ -91,6 +91,7 @@
#include "nsFrameTraversal.h"
#include "nsStyleChangeList.h"
#include "nsIDOMRange.h"
#include "nsRange.h"
#include "nsITableLayout.h" //selection necessity
#include "nsITableCellLayout.h"// "
#include "nsITextControlFrame.h"
@ -444,8 +445,7 @@ nsFrame::Init(nsIContent* aContent,
nsFrameState state = aPrevInFlow->GetStateBits();
// Make bits that are currently off (see constructor) the same:
mState |= state & (NS_FRAME_SELECTED_CONTENT |
NS_FRAME_INDEPENDENT_SELECTION |
mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
NS_FRAME_IS_SPECIAL |
NS_FRAME_MAY_BE_TRANSFORMED);
}
@ -568,8 +568,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
shell->NotifyDestroyingFrame(this);
if ((mState & NS_FRAME_EXTERNAL_REFERENCE) ||
(mState & NS_FRAME_SELECTED_CONTENT)) {
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
shell->ClearFrameRefs(this);
}
@ -1204,10 +1203,7 @@ nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList,
PRUint16 aContentType)
{
//check frame selection state
if ((GetStateBits() & NS_FRAME_SELECTED_CONTENT) != NS_FRAME_SELECTED_CONTENT)
return NS_OK;
if (!IsVisibleForPainting(aBuilder))
if (!IsSelected() || !IsVisibleForPainting(aBuilder))
return NS_OK;
nsPresContext* presContext = PresContext();
@ -1922,7 +1918,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
if (childType != nsGkAtoms::placeholderFrame &&
aBuilder->GetSelectedFramesOnly() &&
child->IsLeaf() &&
!(child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)) {
!aChild->IsSelected()) {
return NS_OK;
}
@ -2493,9 +2489,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
// drag the selected region to some other app.
SelectionDetails *details = 0;
bool isSelected = ((GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT);
if (isSelected)
if (GetContent()->IsSelectionDescendant())
{
bool inSelection = false;
details = frameselection->LookUpSelection(offsets.content, 0,
@ -5199,8 +5193,9 @@ nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
bool
nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
{
if ((mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT)
return true;
if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
return false;
}
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
bool vis;
@ -5256,11 +5251,11 @@ nsIFrame::GetFrameSelection()
}
const nsFrameSelection*
nsIFrame::GetConstFrameSelection()
nsIFrame::GetConstFrameSelection() const
{
nsIFrame *frame = this;
nsIFrame* frame = const_cast<nsIFrame*>(this);
while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
nsITextControlFrame *tcf = do_QueryFrame(frame);
nsITextControlFrame* tcf = do_QueryFrame(frame);
if (tcf) {
return tcf->GetOwnedFrameSelection();
}
@ -5338,39 +5333,13 @@ nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, PRInt32
}
#endif
void
nsIFrame::SetSelected(bool aSelected, SelectionType aType)
bool
nsIFrame::IsFrameSelected() const
{
NS_ASSERTION(!GetPrevContinuation(),
"Should only be called on first in flow");
if (aType != nsISelectionController::SELECTION_NORMAL)
return;
// check whether style allows selection
bool selectable;
IsSelectable(&selectable, nsnull);
if (!selectable)
return;
for (nsIFrame* f = this; f; f = f->GetNextContinuation()) {
if (aSelected) {
AddStateBits(NS_FRAME_SELECTED_CONTENT);
} else {
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
// Repaint this frame subtree's entire area
InvalidateFrameSubtree();
}
}
NS_IMETHODIMP
nsFrame::GetSelected(bool *aSelected) const
{
if (!aSelected )
return NS_ERROR_NULL_POINTER;
*aSelected = !!(mState & NS_FRAME_SELECTED_CONTENT);
return NS_OK;
NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
"use the public IsSelected() instead");
return nsRange::IsNodeSelected(GetContent(), 0,
GetContent()->GetChildCount());
}
NS_IMETHODIMP

Просмотреть файл

@ -232,7 +232,6 @@ public:
NS_IMETHOD GetOffsetFromView(nsPoint& aOffset, nsIView** aView) const;
virtual nsIAtom* GetType() const;
NS_IMETHOD GetSelected(bool *aSelected) const;
NS_IMETHOD IsSelectable(bool* aIsSelectable, PRUint8* aSelectStyle) const;
NS_IMETHOD GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon);

Просмотреть файл

@ -596,7 +596,6 @@ public:
*/
nsresult MaintainSelection(nsSelectionAmount aAmount = eSelectNoAmount);
nsFrameSelection();
void StartBatchChanges();
@ -606,7 +605,7 @@ public:
nsIPresShell *GetShell()const { return mShell; }
void DisconnectFromPresShell() { StopAutoScrollTimer(); mShell = nsnull; }
void DisconnectFromPresShell();
private:
nsresult TakeFocus(nsIContent *aNewFocus,
PRUint32 aContentOffset,

Просмотреть файл

@ -199,8 +199,8 @@ typedef PRUint64 nsFrameState;
// e.g., it is absolutely positioned or floated
#define NS_FRAME_OUT_OF_FLOW NS_FRAME_STATE_BIT(8)
// If this bit is set, then the frame reflects content that may be selected
#define NS_FRAME_SELECTED_CONTENT NS_FRAME_STATE_BIT(9)
// This bit is available for re-use.
//#define NS_FRAME_SELECTED_CONTENT NS_FRAME_STATE_BIT(9)
// If this bit is set, then the frame is dirty and needs to be reflowed.
// This bit is set when the frame is first created.
@ -261,6 +261,7 @@ typedef PRUint64 nsFrameState;
// Bits 20-31 and 60-63 of the frame state are reserved for implementations.
#define NS_FRAME_IMPL_RESERVED nsFrameState(0xF0000000FFF00000)
#define NS_FRAME_RESERVED ~NS_FRAME_IMPL_RESERVED
// This bit is set on floats whose parent does not contain their
// placeholder. This can happen for two reasons: (1) the float was
@ -297,9 +298,6 @@ typedef PRUint64 nsFrameState;
// This is only set during painting
#define NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO NS_FRAME_STATE_BIT(40)
// Bits 0-19 and bits 32-59 of the frame state are reserved by this API.
#define NS_FRAME_RESERVED ~NS_FRAME_IMPL_RESERVED
// Box layout bits
#define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22)
#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31)
@ -579,6 +577,12 @@ public:
void Destroy() { DestroyFrom(this); }
protected:
/**
* Return true if the frame is part of a Selection.
* Helper method to implement the public IsSelected() API.
*/
virtual bool IsFrameSelected() const;
/**
* Implements Destroy(). Do not call this directly except from within a
* DestroyFrom() implementation.
@ -2305,25 +2309,13 @@ public:
*/
virtual PRIntn GetSkipSides() const { return 0; }
/** Selection related calls
/**
* @returns true if this frame is selected.
*/
/**
* Called to set the selection status of the frame.
*
* This must be called on the primary frame, but all continuations
* will be affected the same way.
*
* This sets or clears NS_FRAME_SELECTED_CONTENT for each frame in the
* continuation chain, if the frames are currently selectable.
* The frames are unconditionally invalidated, if this selection type
* is supported at all.
* @param aSelected is it selected?
* @param aType the selection type of the selection that you are setting on the frame
*/
virtual void SetSelected(bool aSelected,
SelectionType aType);
NS_IMETHOD GetSelected(bool *aSelected) const = 0;
bool IsSelected() const {
return (GetContent() && GetContent()->IsSelectionDescendant()) ?
IsFrameSelected() : false;
}
/**
* called to discover where this frame, or a parent frame has user-select style
@ -2352,10 +2344,7 @@ public:
* GetConstFrameSelection returns an object which methods are safe to use for
* example in nsIFrame code.
*/
const nsFrameSelection* GetConstFrameSelection();
/** EndSelection related calls
*/
const nsFrameSelection* GetConstFrameSelection() const;
/**
* called to find the previous/next character, word, or line returns the actual

Просмотреть файл

@ -267,7 +267,6 @@ public:
nsresult StopAutoScrollTimer();
private:
friend class nsAutoScrollTimer;
@ -1702,8 +1701,8 @@ nsFrameSelection::HandleDrag(nsIFrame *aFrame, nsPoint aPoint)
if (!offsets.content)
return;
if ((newFrame->GetStateBits() & NS_FRAME_SELECTED_CONTENT) &&
AdjustForMaintainedSelection(offsets.content, offsets.offset))
if (newFrame->IsSelected() &&
AdjustForMaintainedSelection(offsets.content, offsets.offset))
return;
// Adjust offsets according to maintained amount
@ -1911,7 +1910,6 @@ printf(" * TakeFocus - moving into new cell\n");
}
SelectionDetails*
nsFrameSelection::LookUpSelection(nsIContent *aContent,
PRInt32 aContentOffset,
@ -2478,8 +2476,7 @@ printf("HandleTableSelection: Mouse down event\n");
// Check if new cell is already selected
nsIFrame *cellFrame = childContent->GetPrimaryFrame();
if (!cellFrame) return NS_ERROR_NULL_POINTER;
result = cellFrame->GetSelected(&isSelected);
if (NS_FAILED(result)) return result;
isSelected = cellFrame->IsSelected();
}
else
{
@ -3377,6 +3374,16 @@ nsFrameSelection::GetDelayedCaretData()
return nsnull;
}
void
nsFrameSelection::DisconnectFromPresShell()
{
StopAutoScrollTimer();
for (PRInt32 i = 0; i < nsISelectionController::NUM_SELECTIONTYPES; i++) {
mDomSelections[i]->Clear(nsnull);
}
mShell = nsnull;
}
//END nsISelection interface implementations
#if 0
@ -3406,6 +3413,11 @@ nsTypedSelection::~nsTypedSelection()
{
setAnchorFocusRange(-1);
PRUint32 count = mRanges.Length();
for (PRUint32 i = 0; i < count; ++i) {
mRanges[i].mRange->SetInSelection(false);
}
if (mAutoScrollTimer) {
mAutoScrollTimer->Stop();
mAutoScrollTimer = nsnull;
@ -3730,6 +3742,8 @@ nsTypedSelection::AddItem(nsIRange *aItem, PRInt32 *aOutIndex)
if (mRanges.Length() == 0) {
if (!mRanges.AppendElement(RangeData(aItem)))
return NS_ERROR_OUT_OF_MEMORY;
aItem->SetInSelection(true);
if (aOutIndex)
*aOutIndex = 0;
return NS_OK;
@ -3767,6 +3781,7 @@ nsTypedSelection::AddItem(nsIRange *aItem, PRInt32 *aOutIndex)
// The new range doesn't overlap any existing ranges
if (!mRanges.InsertElementAt(startIndex, RangeData(aItem)))
return NS_ERROR_OUT_OF_MEMORY;
aItem->SetInSelection(true);
if (aOutIndex)
*aOutIndex = startIndex;
return NS_OK;
@ -3788,6 +3803,9 @@ nsTypedSelection::AddItem(nsIRange *aItem, PRInt32 *aOutIndex)
}
// Remove all the overlapping ranges
for (PRInt32 i = startIndex; i < endIndex; ++i) {
mRanges[i].mRange->SetInSelection(false);
}
mRanges.RemoveElementsAt(startIndex, endIndex - startIndex);
nsTArray<RangeData> temp;
@ -3811,6 +3829,10 @@ nsTypedSelection::AddItem(nsIRange *aItem, PRInt32 *aOutIndex)
if (!mRanges.InsertElementsAt(startIndex, temp))
return NS_ERROR_OUT_OF_MEMORY;
for (PRUint32 i = 0; i < temp.Length(); ++i) {
temp[i].mRange->SetInSelection(true);
}
*aOutIndex = startIndex + insertionPoint;
return NS_OK;
}
@ -3837,6 +3859,7 @@ nsTypedSelection::RemoveItem(nsIRange *aItem)
return NS_ERROR_INVALID_ARG;
mRanges.RemoveElementAt(idx);
aItem->SetInSelection(false);
return NS_OK;
}
@ -3860,8 +3883,9 @@ nsTypedSelection::Clear(nsPresContext* aPresContext)
{
setAnchorFocusRange(-1);
for (PRInt32 i = 0; i < (PRInt32)mRanges.Length(); i ++) {
selectFrames(aPresContext, mRanges[i].mRange, 0);
for (PRUint32 i = 0; i < mRanges.Length(); ++i) {
mRanges[i].mRange->SetInSelection(false);
selectFrames(aPresContext, mRanges[i].mRange, false);
}
mRanges.Clear();
@ -4274,42 +4298,29 @@ nsTypedSelection::SelectAllFramesForContent(nsIContentIterator *aInnerIter,
nsIContent *aContent,
bool aSelected)
{
if (!mFrameSelection)
return NS_OK; // nothing to do
nsIPresShell* shell = mFrameSelection->GetShell();
if (!shell)
return NS_OK;
nsresult result;
if (!aInnerIter)
return NS_ERROR_NULL_POINTER;
result = aInnerIter->Init(aContent);
nsresult result = aInnerIter->Init(aContent);
nsIFrame *frame;
if (NS_SUCCEEDED(result))
{
// First select frame of content passed in
frame = aContent->GetPrimaryFrame();
if (frame)
{
frame->SetSelected(aSelected, mType);
if (mFrameSelection->GetTableCellSelection())
{
nsITableCellLayout *tcl = do_QueryFrame(frame);
if (tcl)
{
return NS_OK;
}
}
if (frame && frame->GetType() == nsGkAtoms::textFrame) {
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
textFrame->SetSelectedRange(0, aContent->GetText()->GetLength(), aSelected, mType);
}
// Now iterated through the child frames and set them
while (!aInnerIter->IsDone())
{
while (!aInnerIter->IsDone()) {
nsCOMPtr<nsIContent> innercontent =
do_QueryInterface(aInnerIter->GetCurrentNode());
frame = innercontent->GetPrimaryFrame();
if (frame)
{
frame->SetSelected(aSelected, mType);
if (frame) {
if (frame->GetType() == nsGkAtoms::textFrame) {
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
textFrame->SetSelectedRange(0, innercontent->GetText()->GetLength(), aSelected, mType);
} else {
frame->InvalidateFrameSubtree(); // frame continuations?
}
}
aInnerIter->Next();
@ -4321,21 +4332,23 @@ nsTypedSelection::SelectAllFramesForContent(nsIContentIterator *aInnerIter,
return NS_ERROR_FAILURE;
}
//the idea of this helper method is to select, deselect "top to bottom" traversing through the frames
nsresult
nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bool aFlags)
{
if (!mFrameSelection || !aPresContext)
if (!mFrameSelection || !aPresContext || !aPresContext->GetPresShell())
return NS_OK; // nothing to do
nsIPresShell *presShell = aPresContext->GetPresShell();
if (!presShell)
return NS_OK;
nsCOMPtr<nsIDOMRange> domRange = do_QueryInterface(aRange);
if (!domRange || !aPresContext)
return NS_ERROR_NULL_POINTER;
if (mFrameSelection->GetTableCellSelection()) {
nsINode* node = aRange->GetCommonAncestor();
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
nsIFrame* frame = content ? content->GetPrimaryFrame()
: aPresContext->FrameManager()->GetRootFrame();
if (frame) {
frame->InvalidateFrameSubtree();
}
return NS_OK;
}
nsresult result;
nsCOMPtr<nsIContentIterator> iter = do_CreateInstance(
@ -4348,8 +4361,7 @@ nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bo
kCContentIteratorCID,
&result);
if ((NS_SUCCEEDED(result)) && iter && inneriter)
{
if ((NS_SUCCEEDED(result)) && iter) {
result = iter->Init(aRange);
// loop through the content iterator for each content node
@ -4360,8 +4372,7 @@ nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bo
if (!content)
return NS_ERROR_UNEXPECTED;
if (content->IsNodeOfType(nsINode::eTEXT))
{
if (content->IsNodeOfType(nsINode::eTEXT)) {
nsIFrame* frame = content->GetPrimaryFrame();
// The frame could be an SVG text frame, in which case we'll ignore
// it.
@ -4380,13 +4391,9 @@ nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bo
}
iter->First();
while (!iter->IsDone())
{
while (!iter->IsDone()) {
content = do_QueryInterface(iter->GetCurrentNode());
SelectAllFramesForContent(inneriter, content, aFlags);
iter->Next();
}
@ -4413,6 +4420,7 @@ nsTypedSelection::selectFrames(nsPresContext* aPresContext, nsIRange *aRange, bo
return result;
}
// nsTypedSelection::LookUpSelection
//
// This function is called when a node wants to know where the selection is
@ -4785,13 +4793,7 @@ nsTypedSelection::AddRange(nsIRange* aRange)
nsRefPtr<nsPresContext> presContext;
GetPresContext(getter_AddRefs(presContext));
// Ensure all frames are properly constructed for selectFrames, bug 602331.
nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nsnull;
if (presShell) {
presShell->FlushPendingNotifications(Flush_Frames);
}
selectFrames(presContext, aRange, true);
selectFrames(presContext, aRange, true);
if (!mFrameSelection)
return NS_OK;//nothing to do
@ -4926,27 +4928,21 @@ nsTypedSelection::Collapse(nsINode* aParentNode, PRInt32 aOffset)
return result;
#ifdef DEBUG_SELECTION
if (aParentNode)
{
nsCOMPtr<nsIContent>content;
content = do_QueryInterface(aParentNode);
if (!content)
return NS_ERROR_FAILURE;
printf ("Sel. Collapse to %p %s %d\n", content.get(),
nsAtomCString(content->Tag()).get(), aOffset);
}
else {
printf ("Sel. Collapse set to null parent.\n");
if (aParentNode) {
nsCOMPtr<nsIContent> content = do_QueryInterface(aParentNode);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aParentNode);
printf ("Sel. Collapse to %p %s %d\n", aParentNode,
content ? nsAtomCString(content->Tag()).get()
: (doc ? "DOCUMENT" : "???"),
aOffset);
}
#endif
result = AddItem(range);
setAnchorFocusRange(0);
selectFrames(presContext, range, true);
if (NS_FAILED(result))
return result;
setAnchorFocusRange(0);
selectFrames(presContext, range, true);
return mFrameSelection->NotifySelectionListeners(GetType());
}

Просмотреть файл

@ -165,11 +165,7 @@ public:
* false otherwise
* @param aType the type of selection added or removed
*/
virtual void SetSelected(bool aSelected,
SelectionType aType);
void SetSelectedRange(PRUint32 aStart,
PRUint32 aEnd,
bool aSelected,
void SetSelectedRange(PRUint32 aStart, PRUint32 aEnd, bool aSelected,
SelectionType aType);
virtual bool PeekOffsetNoAmount(bool aForward, PRInt32* aOffset);
@ -476,6 +472,12 @@ protected:
nscoord mAscent;
gfxTextRun* mTextRun;
/**
* Return true if the frame is part of a Selection.
* Helper method to implement the public IsSelected() API.
*/
virtual bool IsFrameSelected() const;
// The caller of this method must call DestroySelectionDetails() on the
// return value, if that return value is not null. Calling
// DestroySelectionDetails() on a null value is still OK, just not necessary.

Просмотреть файл

@ -92,6 +92,7 @@
#include "nsFrameSelection.h"
#include "nsISelection.h"
#include "nsIDOMRange.h"
#include "nsRange.h"
#include "nsCSSRendering.h"
#include "nsContentUtils.h"
#include "nsLineBreaker.h"
@ -3689,6 +3690,7 @@ nsTextFrame::Init(nsIContent* aContent,
// Since our content has a frame now, this flag is no longer needed.
aContent->UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE);
// We're not a continuing frame.
// mContentOffset = 0; not necessary since we get zeroed out at init
return nsFrame::Init(aContent, aParent, aPrevInFlow);
@ -4314,6 +4316,9 @@ SelectionDetails*
nsTextFrame::GetSelectionDetails()
{
const nsFrameSelection* frameSelection = GetConstFrameSelection();
if (frameSelection->GetTableCellSelection()) {
return nsnull;
}
if (!(GetStateBits() & NS_FRAME_GENERATED_CONTENT)) {
SelectionDetails* details =
frameSelection->LookUpSelection(mContent, GetContentOffset(),
@ -4575,7 +4580,7 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
}
// When this frame is not selected, the text-decoration area must be in
// frame bounds.
if (!(GetStateBits() & NS_FRAME_SELECTED_CONTENT) ||
if (!IsSelected() ||
!CombineSelectionUnderlineRect(aPresContext, *aVisualOverflowRect))
return;
AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED);
@ -5025,13 +5030,7 @@ nsTextFrame::PaintTextWithSelectionColors(gfxContext* aCtx,
*aAllTypes = allTypes;
if (!allTypes) {
// Nothing is selected in the given text range.
if (aContentLength == aProvider.GetOriginalLength()) {
// It's the full text range so we can remove the FRAME_SELECTED_CONTENT
// bit to avoid going through this slow path until something is selected
// in this frame again.
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
// Nothing is selected in the given text range. XXX can this still occur?
return false;
}
@ -5179,14 +5178,10 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
nsTextPaintStyle& aTextPaintStyle,
const nsCharClipDisplayItem::ClipEdges& aClipEdges)
{
NS_ASSERTION(GetContent()->IsSelectionDescendant(), "wrong paint path");
SelectionDetails* details = GetSelectionDetails();
if (!details) {
if (aContentLength == aProvider.GetOriginalLength()) {
// It's the full text range so we can remove the FRAME_SELECTED_CONTENT
// bit to avoid going through this slow path until something is selected
// in this frame again.
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
return false;
}
@ -5194,8 +5189,7 @@ nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
if (!PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
aProvider, aContentOffset, aContentLength,
aTextPaintStyle, details, &allTypes,
aClipEdges))
{
aClipEdges)) {
DestroySelectionDetails(details);
return false;
}
@ -5412,15 +5406,16 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
aDirtyRect.width, aDirtyRect.height);
// Fork off to the (slower) paint-with-selection path if necessary.
if (nsLayoutUtils::GetNonGeneratedAncestor(this)->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
if (IsSelected()) {
gfxSkipCharsIterator tmp(provider.GetStart());
PRInt32 contentOffset = tmp.ConvertSkippedToOriginal(startOffset);
PRInt32 contentLength =
tmp.ConvertSkippedToOriginal(startOffset + maxLength) - contentOffset;
if (PaintTextWithSelection(ctx, framePt, textBaselinePt, dirtyRect,
provider, contentOffset, contentLength,
textPaintStyle, clipEdges))
textPaintStyle, clipEdges)) {
return;
}
}
nscolor foregroundColor = textPaintStyle.GetTextColor();
@ -5610,8 +5605,7 @@ bool
nsTextFrame::IsVisibleInSelection(nsISelection* aSelection)
{
// Check the quick way first
bool isSelected = (mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
if (!isSelected)
if (!GetContent()->IsSelectionDescendant())
return false;
SelectionDetails* details = GetSelectionDetails();
@ -5801,17 +5795,17 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
return !aRect.IsEmpty() && !givenRect.Contains(aRect);
}
void
nsTextFrame::SetSelected(bool aSelected,
SelectionType aType)
bool
nsTextFrame::IsFrameSelected() const
{
SetSelectedRange(0, mContent->GetText()->GetLength(), aSelected, aType);
NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
"use the public IsSelected() instead");
return nsRange::IsNodeSelected(GetContent(), GetContentOffset(),
GetContentEnd());
}
void
nsTextFrame::SetSelectedRange(PRUint32 aStart,
PRUint32 aEnd,
bool aSelected,
nsTextFrame::SetSelectedRange(PRUint32 aStart, PRUint32 aEnd, bool aSelected,
SelectionType aType)
{
NS_ASSERTION(!GetPrevContinuation(), "Should only be called for primary frame");
@ -5825,35 +5819,18 @@ nsTextFrame::SetSelectedRange(PRUint32 aStart,
// check whether style allows selection
bool selectable;
IsSelectable(&selectable, nsnull);
if (!selectable)
if (!selectable) {
return;
}
}
bool anySelected = false;
nsTextFrame* f = this;
while (f && f->GetContentEnd() <= PRInt32(aStart)) {
if (f->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
anySelected = true;
}
f = static_cast<nsTextFrame*>(f->GetNextContinuation());
}
nsPresContext* presContext = PresContext();
while (f && f->GetContentOffset() < PRInt32(aEnd)) {
if (aSelected) {
f->AddStateBits(NS_FRAME_SELECTED_CONTENT);
anySelected = true;
} else { // we need to see if any other selection is available.
SelectionDetails *details = f->GetSelectionDetails();
if (details) {
anySelected = true;
DestroySelectionDetails(details);
} else {
f->RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
}
// We may need to reflow to recompute the overflow area for
// spellchecking or IME underline if their underline is thicker than
// the normal decoration line.
@ -5874,22 +5851,6 @@ nsTextFrame::SetSelectedRange(PRUint32 aStart,
f = static_cast<nsTextFrame*>(f->GetNextContinuation());
}
// Scan remaining continuations to see if any are selected
while (f && !anySelected) {
if (f->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
anySelected = true;
}
f = static_cast<nsTextFrame*>(f->GetNextContinuation());
}
if (anySelected) {
mContent->SetFlags(NS_TEXT_IN_SELECTION);
} else {
// This is only legal because there is only one presentation for the
// content with a selection
mContent->UnsetFlags(NS_TEXT_IN_SELECTION);
}
}
NS_IMETHODIMP
@ -7623,16 +7584,6 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
if (mContent->HasFlag(NS_TEXT_IN_SELECTION)) {
SelectionDetails* details = GetSelectionDetails();
if (details) {
AddStateBits(NS_FRAME_SELECTED_CONTENT);
DestroySelectionDetails(details);
} else {
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
}
Invalidate(aMetrics.VisualOverflow());
#ifdef NOISY_REFLOW
@ -7996,12 +7947,9 @@ nsTextFrame::List(FILE* out, PRInt32 aIndent) const
// Output the rect and state
fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
if (0 != mState) {
if (mState & NS_FRAME_SELECTED_CONTENT) {
fprintf(out, " [state=%016llx] SELECTED", mState);
} else {
fprintf(out, " [state=%016llx]", mState);
}
fprintf(out, " [state=%016llx]", mState);
if (IsSelected()) {
fprintf(out, " SELECTED");
}
fprintf(out, " [content=%p]", static_cast<void*>(mContent));
if (HasOverflowAreas()) {

Просмотреть файл

@ -89,12 +89,7 @@ bool
nsMathMLmoFrame::IsFrameInSelection(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "null arg");
if (!aFrame)
return false;
bool isSelected = false;
aFrame->GetSelected(&isSelected);
if (!isSelected)
if (!aFrame || !aFrame->IsSelected())
return false;
const nsFrameSelection* frameSelection = aFrame->GetConstFrameSelection();

Просмотреть файл

@ -2546,15 +2546,7 @@ nsPrintEngine::FindSelectionBoundsWithList(nsPresContext* aPresContext,
aRect += aParentFrame->GetPosition();
for (; !aChildFrames.AtEnd(); aChildFrames.Next()) {
nsIFrame* child = aChildFrames.get();
// only leaf frames have this bit flipped
// then check the hard way
bool isSelected = (child->GetStateBits() & NS_FRAME_SELECTED_CONTENT)
== NS_FRAME_SELECTED_CONTENT;
if (isSelected) {
isSelected = child->IsVisibleForPainting();
}
if (isSelected) {
if (child->IsSelected() && child->IsVisibleForPainting()) {
nsRect r = child->GetRect();
if (aStartFrame == nsnull) {
aStartFrame = child;

Просмотреть файл

@ -271,42 +271,6 @@ nsSVGGlyphFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
}
}
void
nsSVGGlyphFrame::SetSelected(bool aSelected,
SelectionType aType)
{
#if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
printf("nsSVGGlyphFrame(%p)::SetSelected()\n", this);
#endif
if (aType != nsISelectionController::SELECTION_NORMAL)
return;
// check whether style allows selection
bool selectable;
IsSelectable(&selectable, nsnull);
if (!selectable)
return;
if (aSelected) {
AddStateBits(NS_FRAME_SELECTED_CONTENT);
} else {
RemoveStateBits(NS_FRAME_SELECTED_CONTENT);
}
nsSVGUtils::UpdateGraphic(this);
}
NS_IMETHODIMP
nsSVGGlyphFrame::GetSelected(bool *aSelected) const
{
nsresult rv = nsSVGGlyphFrameBase::GetSelected(aSelected);
#if defined(DEBUG) && defined(SVG_DEBUG_SELECTION)
printf("nsSVGGlyphFrame(%p)::GetSelected()=%d\n", this, *aSelected);
#endif
return rv;
}
NS_IMETHODIMP
nsSVGGlyphFrame::IsSelectable(bool* aIsSelectable,
PRUint8* aSelectStyle) const
@ -984,9 +948,7 @@ nsSVGGlyphFrame::GetHighlight(PRUint32 *charnum, PRUint32 *nchars,
*charnum=0;
*nchars=0;
bool hasHighlight =
(mState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
bool hasHighlight = IsSelected();
if (!hasHighlight) {
NS_ERROR("nsSVGGlyphFrame::GetHighlight() called by renderer when there is no highlight");
return NS_ERROR_FAILURE;

Просмотреть файл

@ -135,9 +135,6 @@ public:
virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext);
virtual void SetSelected(bool aSelected,
SelectionType aType);
NS_IMETHOD GetSelected(bool *aSelected) const;
NS_IMETHOD IsSelectable(bool* aIsSelectable, PRUint8* aSelectStyle) const;
NS_IMETHOD Init(nsIContent* aContent,

Просмотреть файл

@ -318,8 +318,7 @@ void
nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
nsPoint aPt)
{
NS_ASSERTION(GetStateBits() & NS_FRAME_SELECTED_CONTENT,
"Should only be called for selected cells");
NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
PRInt16 displaySelection;
nsPresContext* presContext = PresContext();
displaySelection = DisplaySelection(presContext);
@ -499,9 +498,7 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
// and display the selection border if we need to
bool isSelected =
(GetStateBits() & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
if (isSelected) {
if (IsSelected()) {
nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
"TableCellSelection",

Просмотреть файл

@ -3667,7 +3667,7 @@ nsTableFrame::GetCellDataAt(PRInt32 aRowIndex,
PRInt32& aColSpan,
PRInt32& aActualRowSpan,
PRInt32& aActualColSpan,
bool& aIsSelected)
bool& aIsSelected)
{
// Initialize out params
aCell = nsnull;
@ -3700,8 +3700,7 @@ nsTableFrame::GetCellDataAt(PRInt32 aRowIndex,
if (aActualRowSpan == 0 || aActualColSpan == 0)
return NS_ERROR_FAILURE;
result = cellFrame->GetSelected(&aIsSelected);
if (NS_FAILED(result)) return result;
aIsSelected = cellFrame->IsSelected();
// do this last, because it addrefs,
// and we don't want the caller leaking it on error

Просмотреть файл

@ -371,14 +371,6 @@ nsTableOuterFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder* aBuilde
return NS_OK;
}
void
nsTableOuterFrame::SetSelected(bool aSelected,
SelectionType aType)
{
nsFrame::SetSelected(aSelected, aType);
InnerTableFrame()->SetSelected(aSelected, aType);
}
nsIFrame*
nsTableOuterFrame::GetParentStyleContextFrame()
{

Просмотреть файл

@ -159,11 +159,6 @@ public:
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif
/** SetSelected needs to be overridden to talk to inner tableframe
*/
void SetSelected(bool aSelected,
SelectionType aType);
virtual nsIFrame* GetParentStyleContextFrame();
/*---------------- nsITableLayout methods ------------------------*/