Bug 89872. Implement front-end cache in outliner to avoid doing repeated RDF lookups to determine container-hood and empty state. r=varga@utcru.sk, rs=kin.

This commit is contained in:
waterson%netscape.com 2001-07-17 18:31:03 +00:00
Родитель 6b4f2b9329
Коммит 55ad1762ea
6 изменённых файлов: 128 добавлений и 8 удалений

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

@ -229,6 +229,8 @@ nsOutlinerRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex)
mRows[i + 1] = mRows[i];
mRows[aIndex].mMatch = aMatch;
mRows[aIndex].mContainerType = eContainerType_Unknown;
mRows[aIndex].mContainerState = eContainerState_Unknown;
mRows[aIndex].mSubtree = nsnull;
++mCount;

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

@ -40,6 +40,20 @@ class nsOutlinerRows
public:
enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 };
// N.B. these values are chosen to avoid problems with
// sign-extension from the bit-packed Row structure.
enum ContainerType {
eContainerType_Unknown = 0,
eContainerType_Noncontainer = 1,
eContainerType_Container = -2
};
enum ContainerState {
eContainerState_Unknown = 0,
eContainerState_Empty = 1,
eContainerState_Nonempty = -2
};
class Subtree;
/**
@ -49,6 +63,8 @@ public:
*/
struct Row {
nsTemplateMatch* mMatch;
ContainerType mContainerType : 2;
ContainerState mContainerState : 2;
Subtree* mSubtree; // XXX eventually move to hashtable
};

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

@ -229,6 +229,8 @@ nsOutlinerRows::Subtree::InsertRowAt(nsTemplateMatch* aMatch, PRInt32 aIndex)
mRows[i + 1] = mRows[i];
mRows[aIndex].mMatch = aMatch;
mRows[aIndex].mContainerType = eContainerType_Unknown;
mRows[aIndex].mContainerState = eContainerState_Unknown;
mRows[aIndex].mSubtree = nsnull;
++mCount;

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

@ -40,6 +40,20 @@ class nsOutlinerRows
public:
enum Direction { eDirection_Forwards = +1, eDirection_Backwards = -1 };
// N.B. these values are chosen to avoid problems with
// sign-extension from the bit-packed Row structure.
enum ContainerType {
eContainerType_Unknown = 0,
eContainerType_Noncontainer = 1,
eContainerType_Container = -2
};
enum ContainerState {
eContainerState_Unknown = 0,
eContainerState_Empty = 1,
eContainerState_Nonempty = -2
};
class Subtree;
/**
@ -49,6 +63,8 @@ public:
*/
struct Row {
nsTemplateMatch* mMatch;
ContainerType mContainerType : 2;
ContainerState mContainerState : 2;
Subtree* mSubtree; // XXX eventually move to hashtable
};

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

@ -454,7 +454,19 @@ nsXULOutlinerBuilder::IsContainer(PRInt32 aIndex, PRBool* aResult)
if (aIndex < 0 || aIndex >= mRows.Count())
return NS_ERROR_INVALID_ARG;
return CheckContainer(GetResourceFor(aIndex), aResult, nsnull);
nsOutlinerRows::iterator iter = mRows[aIndex];
if (iter->mContainerType == nsOutlinerRows::eContainerType_Unknown) {
PRBool isContainer;
CheckContainer(GetResourceFor(aIndex), &isContainer, nsnull);
iter->mContainerType = isContainer
? nsOutlinerRows::eContainerType_Container
: nsOutlinerRows::eContainerType_Noncontainer;
}
*aResult = (iter->mContainerType == nsOutlinerRows::eContainerType_Container);
return NS_OK;
}
NS_IMETHODIMP
@ -474,7 +486,21 @@ nsXULOutlinerBuilder::IsContainerEmpty(PRInt32 aIndex, PRBool* aResult)
if (aIndex < 0 || aIndex >= mRows.Count())
return NS_ERROR_INVALID_ARG;
return CheckContainer(GetResourceFor(aIndex), nsnull, aResult);
nsOutlinerRows::iterator iter = mRows[aIndex];
NS_ASSERTION(iter->mContainerType == nsOutlinerRows::eContainerType_Container,
"asking for empty state on non-container");
if (iter->mContainerState == nsOutlinerRows::eContainerState_Unknown) {
PRBool isEmpty;
CheckContainer(GetResourceFor(aIndex), nsnull, &isEmpty);
iter->mContainerState = isEmpty
? nsOutlinerRows::eContainerState_Empty
: nsOutlinerRows::eContainerState_Nonempty;
}
*aResult = (iter->mContainerState == nsOutlinerRows::eContainerState_Empty);
return NS_OK;
}
NS_IMETHODIMP
@ -928,6 +954,10 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember,
PRInt32 delta = mRows.GetSubtreeSizeFor(iter);
mRows.RemoveRowAt(iter);
// XXX Could potentially invalidate the iterator's
// mContainer[Type|State] caching here, but it'll work
// itself out.
// Notify the box object
mBoxObject->RowCountChanged(row, -delta);
}
@ -960,14 +990,26 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember,
nsXULContentUtils::true_,
PR_TRUE,
&open);
if (open)
if (open) {
parent = mRows.EnsureSubtreeFor(iter);
}
else if ((iter->mContainerType != nsOutlinerRows::eContainerType_Container) ||
(iter->mContainerState != nsOutlinerRows::eContainerState_Nonempty)) {
// The container is closed, but we know something has
// just been inserted into it.
iter->mContainerType = nsOutlinerRows::eContainerType_Container;
iter->mContainerState = nsOutlinerRows::eContainerState_Nonempty;
mBoxObject->InvalidateRow(iter.GetRowIndex());
}
}
else
parent = mRows.GetRoot();
if (parent) {
// By default, place the new element at the end of the container
// If we get here, then we're inserting into an open
// container. By default, place the new element at the
// end of the container
PRInt32 index = parent->Count();
if (mSortVariable) {

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

@ -454,7 +454,19 @@ nsXULOutlinerBuilder::IsContainer(PRInt32 aIndex, PRBool* aResult)
if (aIndex < 0 || aIndex >= mRows.Count())
return NS_ERROR_INVALID_ARG;
return CheckContainer(GetResourceFor(aIndex), aResult, nsnull);
nsOutlinerRows::iterator iter = mRows[aIndex];
if (iter->mContainerType == nsOutlinerRows::eContainerType_Unknown) {
PRBool isContainer;
CheckContainer(GetResourceFor(aIndex), &isContainer, nsnull);
iter->mContainerType = isContainer
? nsOutlinerRows::eContainerType_Container
: nsOutlinerRows::eContainerType_Noncontainer;
}
*aResult = (iter->mContainerType == nsOutlinerRows::eContainerType_Container);
return NS_OK;
}
NS_IMETHODIMP
@ -474,7 +486,21 @@ nsXULOutlinerBuilder::IsContainerEmpty(PRInt32 aIndex, PRBool* aResult)
if (aIndex < 0 || aIndex >= mRows.Count())
return NS_ERROR_INVALID_ARG;
return CheckContainer(GetResourceFor(aIndex), nsnull, aResult);
nsOutlinerRows::iterator iter = mRows[aIndex];
NS_ASSERTION(iter->mContainerType == nsOutlinerRows::eContainerType_Container,
"asking for empty state on non-container");
if (iter->mContainerState == nsOutlinerRows::eContainerState_Unknown) {
PRBool isEmpty;
CheckContainer(GetResourceFor(aIndex), nsnull, &isEmpty);
iter->mContainerState = isEmpty
? nsOutlinerRows::eContainerState_Empty
: nsOutlinerRows::eContainerState_Nonempty;
}
*aResult = (iter->mContainerState == nsOutlinerRows::eContainerState_Empty);
return NS_OK;
}
NS_IMETHODIMP
@ -928,6 +954,10 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember,
PRInt32 delta = mRows.GetSubtreeSizeFor(iter);
mRows.RemoveRowAt(iter);
// XXX Could potentially invalidate the iterator's
// mContainer[Type|State] caching here, but it'll work
// itself out.
// Notify the box object
mBoxObject->RowCountChanged(row, -delta);
}
@ -960,14 +990,26 @@ nsXULOutlinerBuilder::ReplaceMatch(nsIRDFResource* aMember,
nsXULContentUtils::true_,
PR_TRUE,
&open);
if (open)
if (open) {
parent = mRows.EnsureSubtreeFor(iter);
}
else if ((iter->mContainerType != nsOutlinerRows::eContainerType_Container) ||
(iter->mContainerState != nsOutlinerRows::eContainerState_Nonempty)) {
// The container is closed, but we know something has
// just been inserted into it.
iter->mContainerType = nsOutlinerRows::eContainerType_Container;
iter->mContainerState = nsOutlinerRows::eContainerState_Nonempty;
mBoxObject->InvalidateRow(iter.GetRowIndex());
}
}
else
parent = mRows.GetRoot();
if (parent) {
// By default, place the new element at the end of the container
// If we get here, then we're inserting into an open
// container. By default, place the new element at the
// end of the container
PRInt32 index = parent->Count();
if (mSortVariable) {