added debug list of context graph
This commit is contained in:
peterl 1998-05-18 21:05:52 +00:00
Родитель 12db5cfc8d
Коммит 8cb0400608
3 изменённых файлов: 765 добавлений и 48 удалений

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

@ -23,7 +23,6 @@
#include "nsIFrame.h" #include "nsIFrame.h"
#include "nsHashtable.h" #include "nsHashtable.h"
static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
class ContextKey : public nsHashKey { class ContextKey : public nsHashKey {
@ -196,6 +195,14 @@ public:
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame); nsIFrame* aParentFrame);
virtual nsIStyleContext* ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
virtual nsIStyleContext* ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
// xxx style rules enumeration // xxx style rules enumeration
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
@ -208,12 +215,20 @@ private:
protected: protected:
virtual ~StyleSetImpl(); virtual ~StyleSetImpl();
PRBool EnsureArray(nsISupportsArray** aArray); PRBool EnsureArray(nsISupportsArray** aArray);
nsIStyleContext* GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules);
PRInt32 RulesMatching(nsISupportsArray* aSheets, PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext, nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsISupportsArray* aResults); nsISupportsArray* aResults);
PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults);
void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets); void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
void ListContexts(FILE* out, PRInt32 aIndent);
nsISupportsArray* mOverrideSheets; nsISupportsArray* mOverrideSheets;
nsISupportsArray* mDocSheets; nsISupportsArray* mDocSheets;
@ -445,12 +460,32 @@ PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
return ruleCount; return ruleCount;
} }
nsIStyleContext* StyleSetImpl::GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules)
{
// check for cached ruleSet to context or create
ContextKey tempKey(aParentContext, aRules);
nsIStyleContext* result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
if (nsnull == result) {
if (NS_OK == NS_NewStyleContext(&result, aRules, aPresContext, aParentFrame)) {
tempKey.SetContext(result);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller
//fprintf(stdout, "+");
}
}
else {
NS_ADDREF(result);
//fprintf(stdout, "-");
}
return result;
}
nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext, nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame) nsIFrame* aParentFrame)
{ {
nsIStyleContext* result = nsnull; nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull; nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) { if (nsnull != aParentFrame) {
@ -468,21 +503,96 @@ nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
// then check for cached ruleSet to context or create result = GetContext(aPresContext, aParentFrame, parentContext, rules);
ContextKey tempKey(parentContext, rules);
result = (nsIStyleContext*)mStyleContexts.Get(&tempKey); NS_RELEASE(rules);
if (nsnull == result) { }
if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
tempKey.SetContext(result); NS_IF_RELEASE(parentContext);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller return result;
//fprintf(stdout, "+"); }
PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults)
{
PRInt32 ruleCount = 0;
if (nsnull != aSheets) {
PRInt32 sheetCount = aSheets->Count();
PRInt32 index;
for (index = 0; index < sheetCount; index++) {
nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
ruleCount += sheet->RulesMatching(aPresContext, aPseudoTag, aParentFrame,
aResults);
NS_RELEASE(sheet);
} }
} }
else { return ruleCount;
NS_ADDREF(result); }
//fprintf(stdout, "-");
nsIStyleContext* StyleSetImpl::ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
} }
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
NS_RELEASE(rules);
}
NS_IF_RELEASE(parentContext);
return result;
}
nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
}
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
if (0 < ruleCount) {
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
}
NS_RELEASE(rules); NS_RELEASE(rules);
} }
@ -512,6 +622,135 @@ void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
List(out, aIndent, mBackstopSheets); List(out, aIndent, mBackstopSheets);
} }
struct ContextNode {
nsIStyleContext* mContext;
ContextNode* mNext;
ContextNode* mChild;
ContextNode(nsIStyleContext* aContext)
{
mContext = aContext;
mNext = nsnull;
mChild = nsnull;
}
~ContextNode(void)
{
if (nsnull != mNext) {
delete mNext;
}
if (nsnull != mChild) {
delete mChild;
}
}
};
static ContextNode* gRootNode;
static ContextNode* FindNode(nsIStyleContext* aContext, ContextNode* aStart)
{
ContextNode* node = aStart;
while (nsnull != node) {
if (node->mContext == aContext) {
return node;
}
if (nsnull != node->mChild) {
ContextNode* result = FindNode(aContext, node->mChild);
if (nsnull != result) {
return result;
}
}
node = node->mNext;
}
return nsnull;
}
PRBool GatherContexts(nsHashKey *aKey, void *aData)
{
PRBool result = PR_TRUE;
nsIStyleContext* context = (nsIStyleContext*)aData;
nsIStyleContext* parent = context->GetParent();
ContextNode* node = new ContextNode(context);
if (nsnull == gRootNode) {
gRootNode = node;
}
else {
if (nsnull == parent) { // found real root, replace temp
node->mNext = gRootNode; // orphan the old root
gRootNode = node;
}
else {
ContextNode* parentNode = FindNode(parent, gRootNode);
if (nsnull == parentNode) { // hang orhpans off root
node->mNext = gRootNode->mNext;
gRootNode->mNext = node;
}
else {
node->mNext = parentNode->mChild;
parentNode->mChild = node;
}
}
}
// graft orphans
ContextNode* prevOrphan = nsnull;
ContextNode* orphan = gRootNode;
while (nsnull != orphan) {
nsIStyleContext* orphanParent = orphan->mContext->GetParent();
if (orphanParent == context) { // found our child
if (orphan == gRootNode) {
gRootNode = orphan->mNext;
orphan->mNext = node->mChild;
node->mChild = orphan;
orphan = gRootNode;
}
else {
ContextNode* foundling = orphan;
orphan = orphan->mNext;
prevOrphan->mNext = orphan;
foundling->mNext = node->mChild;
node->mChild = foundling;
}
}
else {
prevOrphan = orphan;
orphan = orphan->mNext;
}
NS_IF_RELEASE(orphanParent);
}
NS_IF_RELEASE(parent);
return result;
}
static PRInt32 ListNode(ContextNode* aNode, FILE* out, PRInt32 aIndent)
{
PRInt32 count = 0;
ContextNode* node = aNode;
while (nsnull != node) {
node->mContext->List(out, aIndent);
count++;
if (nsnull != node->mChild) {
nsIStyleContext* childParent = node->mChild->mContext->GetParent();
NS_ASSERTION(childParent == node->mContext, "broken graph");
NS_RELEASE(childParent);
count += ListNode(node->mChild, out, aIndent + 1);
}
node = node->mNext;
}
return count;
}
void StyleSetImpl::ListContexts(FILE* out, PRInt32 aIndent)
{
mStyleContexts.Enumerate(GatherContexts);
NS_ASSERTION(gRootNode->mNext == nsnull, "dangling orphan");
PRInt32 listCount = ListNode(gRootNode, out, aIndent);
NS_ASSERTION(listCount == mStyleContexts.Count(), "graph incomplete");
delete gRootNode;
gRootNode = nsnull;
}
NS_LAYOUT nsresult NS_LAYOUT nsresult
NS_NewStyleSet(nsIStyleSet** aInstancePtrResult) NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)

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

@ -23,7 +23,6 @@
#include "nsIFrame.h" #include "nsIFrame.h"
#include "nsHashtable.h" #include "nsHashtable.h"
static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
class ContextKey : public nsHashKey { class ContextKey : public nsHashKey {
@ -196,6 +195,14 @@ public:
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame); nsIFrame* aParentFrame);
virtual nsIStyleContext* ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
virtual nsIStyleContext* ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
// xxx style rules enumeration // xxx style rules enumeration
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
@ -208,12 +215,20 @@ private:
protected: protected:
virtual ~StyleSetImpl(); virtual ~StyleSetImpl();
PRBool EnsureArray(nsISupportsArray** aArray); PRBool EnsureArray(nsISupportsArray** aArray);
nsIStyleContext* GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules);
PRInt32 RulesMatching(nsISupportsArray* aSheets, PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext, nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsISupportsArray* aResults); nsISupportsArray* aResults);
PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults);
void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets); void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
void ListContexts(FILE* out, PRInt32 aIndent);
nsISupportsArray* mOverrideSheets; nsISupportsArray* mOverrideSheets;
nsISupportsArray* mDocSheets; nsISupportsArray* mDocSheets;
@ -445,12 +460,32 @@ PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
return ruleCount; return ruleCount;
} }
nsIStyleContext* StyleSetImpl::GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules)
{
// check for cached ruleSet to context or create
ContextKey tempKey(aParentContext, aRules);
nsIStyleContext* result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
if (nsnull == result) {
if (NS_OK == NS_NewStyleContext(&result, aRules, aPresContext, aParentFrame)) {
tempKey.SetContext(result);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller
//fprintf(stdout, "+");
}
}
else {
NS_ADDREF(result);
//fprintf(stdout, "-");
}
return result;
}
nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext, nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame) nsIFrame* aParentFrame)
{ {
nsIStyleContext* result = nsnull; nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull; nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) { if (nsnull != aParentFrame) {
@ -468,21 +503,96 @@ nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
// then check for cached ruleSet to context or create result = GetContext(aPresContext, aParentFrame, parentContext, rules);
ContextKey tempKey(parentContext, rules);
result = (nsIStyleContext*)mStyleContexts.Get(&tempKey); NS_RELEASE(rules);
if (nsnull == result) { }
if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
tempKey.SetContext(result); NS_IF_RELEASE(parentContext);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller return result;
//fprintf(stdout, "+"); }
PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults)
{
PRInt32 ruleCount = 0;
if (nsnull != aSheets) {
PRInt32 sheetCount = aSheets->Count();
PRInt32 index;
for (index = 0; index < sheetCount; index++) {
nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
ruleCount += sheet->RulesMatching(aPresContext, aPseudoTag, aParentFrame,
aResults);
NS_RELEASE(sheet);
} }
} }
else { return ruleCount;
NS_ADDREF(result); }
//fprintf(stdout, "-");
nsIStyleContext* StyleSetImpl::ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
} }
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
NS_RELEASE(rules);
}
NS_IF_RELEASE(parentContext);
return result;
}
nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
}
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
if (0 < ruleCount) {
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
}
NS_RELEASE(rules); NS_RELEASE(rules);
} }
@ -512,6 +622,135 @@ void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
List(out, aIndent, mBackstopSheets); List(out, aIndent, mBackstopSheets);
} }
struct ContextNode {
nsIStyleContext* mContext;
ContextNode* mNext;
ContextNode* mChild;
ContextNode(nsIStyleContext* aContext)
{
mContext = aContext;
mNext = nsnull;
mChild = nsnull;
}
~ContextNode(void)
{
if (nsnull != mNext) {
delete mNext;
}
if (nsnull != mChild) {
delete mChild;
}
}
};
static ContextNode* gRootNode;
static ContextNode* FindNode(nsIStyleContext* aContext, ContextNode* aStart)
{
ContextNode* node = aStart;
while (nsnull != node) {
if (node->mContext == aContext) {
return node;
}
if (nsnull != node->mChild) {
ContextNode* result = FindNode(aContext, node->mChild);
if (nsnull != result) {
return result;
}
}
node = node->mNext;
}
return nsnull;
}
PRBool GatherContexts(nsHashKey *aKey, void *aData)
{
PRBool result = PR_TRUE;
nsIStyleContext* context = (nsIStyleContext*)aData;
nsIStyleContext* parent = context->GetParent();
ContextNode* node = new ContextNode(context);
if (nsnull == gRootNode) {
gRootNode = node;
}
else {
if (nsnull == parent) { // found real root, replace temp
node->mNext = gRootNode; // orphan the old root
gRootNode = node;
}
else {
ContextNode* parentNode = FindNode(parent, gRootNode);
if (nsnull == parentNode) { // hang orhpans off root
node->mNext = gRootNode->mNext;
gRootNode->mNext = node;
}
else {
node->mNext = parentNode->mChild;
parentNode->mChild = node;
}
}
}
// graft orphans
ContextNode* prevOrphan = nsnull;
ContextNode* orphan = gRootNode;
while (nsnull != orphan) {
nsIStyleContext* orphanParent = orphan->mContext->GetParent();
if (orphanParent == context) { // found our child
if (orphan == gRootNode) {
gRootNode = orphan->mNext;
orphan->mNext = node->mChild;
node->mChild = orphan;
orphan = gRootNode;
}
else {
ContextNode* foundling = orphan;
orphan = orphan->mNext;
prevOrphan->mNext = orphan;
foundling->mNext = node->mChild;
node->mChild = foundling;
}
}
else {
prevOrphan = orphan;
orphan = orphan->mNext;
}
NS_IF_RELEASE(orphanParent);
}
NS_IF_RELEASE(parent);
return result;
}
static PRInt32 ListNode(ContextNode* aNode, FILE* out, PRInt32 aIndent)
{
PRInt32 count = 0;
ContextNode* node = aNode;
while (nsnull != node) {
node->mContext->List(out, aIndent);
count++;
if (nsnull != node->mChild) {
nsIStyleContext* childParent = node->mChild->mContext->GetParent();
NS_ASSERTION(childParent == node->mContext, "broken graph");
NS_RELEASE(childParent);
count += ListNode(node->mChild, out, aIndent + 1);
}
node = node->mNext;
}
return count;
}
void StyleSetImpl::ListContexts(FILE* out, PRInt32 aIndent)
{
mStyleContexts.Enumerate(GatherContexts);
NS_ASSERTION(gRootNode->mNext == nsnull, "dangling orphan");
PRInt32 listCount = ListNode(gRootNode, out, aIndent);
NS_ASSERTION(listCount == mStyleContexts.Count(), "graph incomplete");
delete gRootNode;
gRootNode = nsnull;
}
NS_LAYOUT nsresult NS_LAYOUT nsresult
NS_NewStyleSet(nsIStyleSet** aInstancePtrResult) NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)

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

@ -23,7 +23,6 @@
#include "nsIFrame.h" #include "nsIFrame.h"
#include "nsHashtable.h" #include "nsHashtable.h"
static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID); static NS_DEFINE_IID(kIStyleSetIID, NS_ISTYLE_SET_IID);
class ContextKey : public nsHashKey { class ContextKey : public nsHashKey {
@ -196,6 +195,14 @@ public:
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame); nsIFrame* aParentFrame);
virtual nsIStyleContext* ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
virtual nsIStyleContext* ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame);
// xxx style rules enumeration // xxx style rules enumeration
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0); virtual void List(FILE* out = stdout, PRInt32 aIndent = 0);
@ -208,12 +215,20 @@ private:
protected: protected:
virtual ~StyleSetImpl(); virtual ~StyleSetImpl();
PRBool EnsureArray(nsISupportsArray** aArray); PRBool EnsureArray(nsISupportsArray** aArray);
nsIStyleContext* GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules);
PRInt32 RulesMatching(nsISupportsArray* aSheets, PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext, nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame, nsIFrame* aParentFrame,
nsISupportsArray* aResults); nsISupportsArray* aResults);
PRInt32 RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults);
void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets); void List(FILE* out, PRInt32 aIndent, nsISupportsArray* aSheets);
void ListContexts(FILE* out, PRInt32 aIndent);
nsISupportsArray* mOverrideSheets; nsISupportsArray* mOverrideSheets;
nsISupportsArray* mDocSheets; nsISupportsArray* mDocSheets;
@ -445,12 +460,32 @@ PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
return ruleCount; return ruleCount;
} }
nsIStyleContext* StyleSetImpl::GetContext(nsIPresContext* aPresContext, nsIFrame* aParentFrame,
nsIStyleContext* aParentContext, nsISupportsArray* aRules)
{
// check for cached ruleSet to context or create
ContextKey tempKey(aParentContext, aRules);
nsIStyleContext* result = (nsIStyleContext*)mStyleContexts.Get(&tempKey);
if (nsnull == result) {
if (NS_OK == NS_NewStyleContext(&result, aRules, aPresContext, aParentFrame)) {
tempKey.SetContext(result);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller
//fprintf(stdout, "+");
}
}
else {
NS_ADDREF(result);
//fprintf(stdout, "-");
}
return result;
}
nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext, nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
nsIContent* aContent, nsIContent* aContent,
nsIFrame* aParentFrame) nsIFrame* aParentFrame)
{ {
nsIStyleContext* result = nsnull; nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull; nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) { if (nsnull != aParentFrame) {
@ -468,21 +503,96 @@ nsIStyleContext* StyleSetImpl::ResolveStyleFor(nsIPresContext* aPresContext,
ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mDocSheets, aPresContext, aContent, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules); ruleCount += RulesMatching(mBackstopSheets, aPresContext, aContent, aParentFrame, rules);
// then check for cached ruleSet to context or create result = GetContext(aPresContext, aParentFrame, parentContext, rules);
ContextKey tempKey(parentContext, rules);
result = (nsIStyleContext*)mStyleContexts.Get(&tempKey); NS_RELEASE(rules);
if (nsnull == result) { }
if (NS_OK == NS_NewStyleContext(&result, rules, aPresContext, aContent, aParentFrame)) {
tempKey.SetContext(result); NS_IF_RELEASE(parentContext);
mStyleContexts.Put(&tempKey, result); // hashtable clones key, so this is OK (table gets first ref)
NS_ADDREF(result); // add ref for the caller return result;
//fprintf(stdout, "+"); }
PRInt32 StyleSetImpl::RulesMatching(nsISupportsArray* aSheets,
nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame,
nsISupportsArray* aResults)
{
PRInt32 ruleCount = 0;
if (nsnull != aSheets) {
PRInt32 sheetCount = aSheets->Count();
PRInt32 index;
for (index = 0; index < sheetCount; index++) {
nsIStyleSheet* sheet = (nsIStyleSheet*)aSheets->ElementAt(index);
ruleCount += sheet->RulesMatching(aPresContext, aPseudoTag, aParentFrame,
aResults);
NS_RELEASE(sheet);
} }
} }
else { return ruleCount;
NS_ADDREF(result); }
//fprintf(stdout, "-");
nsIStyleContext* StyleSetImpl::ResolvePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
} }
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
NS_RELEASE(rules);
}
NS_IF_RELEASE(parentContext);
return result;
}
nsIStyleContext* StyleSetImpl::ProbePseudoStyleFor(nsIPresContext* aPresContext,
nsIAtom* aPseudoTag,
nsIFrame* aParentFrame)
{
nsIStyleContext* result = nsnull;
nsIStyleContext* parentContext = nsnull;
if (nsnull != aParentFrame) {
aParentFrame->GetStyleContext(aPresContext, parentContext);
NS_ASSERTION(nsnull != parentContext, "parent must have style context");
}
// want to check parent frame's context for cached child context first
// then do a brute force rule search
nsISupportsArray* rules = nsnull;
if (NS_OK == NS_NewISupportsArray(&rules)) {
PRInt32 ruleCount = RulesMatching(mOverrideSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mDocSheets, aPresContext, aPseudoTag, aParentFrame, rules);
ruleCount += RulesMatching(mBackstopSheets, aPresContext, aPseudoTag, aParentFrame, rules);
if (0 < ruleCount) {
result = GetContext(aPresContext, aParentFrame, parentContext, rules);
}
NS_RELEASE(rules); NS_RELEASE(rules);
} }
@ -512,6 +622,135 @@ void StyleSetImpl::List(FILE* out, PRInt32 aIndent)
List(out, aIndent, mBackstopSheets); List(out, aIndent, mBackstopSheets);
} }
struct ContextNode {
nsIStyleContext* mContext;
ContextNode* mNext;
ContextNode* mChild;
ContextNode(nsIStyleContext* aContext)
{
mContext = aContext;
mNext = nsnull;
mChild = nsnull;
}
~ContextNode(void)
{
if (nsnull != mNext) {
delete mNext;
}
if (nsnull != mChild) {
delete mChild;
}
}
};
static ContextNode* gRootNode;
static ContextNode* FindNode(nsIStyleContext* aContext, ContextNode* aStart)
{
ContextNode* node = aStart;
while (nsnull != node) {
if (node->mContext == aContext) {
return node;
}
if (nsnull != node->mChild) {
ContextNode* result = FindNode(aContext, node->mChild);
if (nsnull != result) {
return result;
}
}
node = node->mNext;
}
return nsnull;
}
PRBool GatherContexts(nsHashKey *aKey, void *aData)
{
PRBool result = PR_TRUE;
nsIStyleContext* context = (nsIStyleContext*)aData;
nsIStyleContext* parent = context->GetParent();
ContextNode* node = new ContextNode(context);
if (nsnull == gRootNode) {
gRootNode = node;
}
else {
if (nsnull == parent) { // found real root, replace temp
node->mNext = gRootNode; // orphan the old root
gRootNode = node;
}
else {
ContextNode* parentNode = FindNode(parent, gRootNode);
if (nsnull == parentNode) { // hang orhpans off root
node->mNext = gRootNode->mNext;
gRootNode->mNext = node;
}
else {
node->mNext = parentNode->mChild;
parentNode->mChild = node;
}
}
}
// graft orphans
ContextNode* prevOrphan = nsnull;
ContextNode* orphan = gRootNode;
while (nsnull != orphan) {
nsIStyleContext* orphanParent = orphan->mContext->GetParent();
if (orphanParent == context) { // found our child
if (orphan == gRootNode) {
gRootNode = orphan->mNext;
orphan->mNext = node->mChild;
node->mChild = orphan;
orphan = gRootNode;
}
else {
ContextNode* foundling = orphan;
orphan = orphan->mNext;
prevOrphan->mNext = orphan;
foundling->mNext = node->mChild;
node->mChild = foundling;
}
}
else {
prevOrphan = orphan;
orphan = orphan->mNext;
}
NS_IF_RELEASE(orphanParent);
}
NS_IF_RELEASE(parent);
return result;
}
static PRInt32 ListNode(ContextNode* aNode, FILE* out, PRInt32 aIndent)
{
PRInt32 count = 0;
ContextNode* node = aNode;
while (nsnull != node) {
node->mContext->List(out, aIndent);
count++;
if (nsnull != node->mChild) {
nsIStyleContext* childParent = node->mChild->mContext->GetParent();
NS_ASSERTION(childParent == node->mContext, "broken graph");
NS_RELEASE(childParent);
count += ListNode(node->mChild, out, aIndent + 1);
}
node = node->mNext;
}
return count;
}
void StyleSetImpl::ListContexts(FILE* out, PRInt32 aIndent)
{
mStyleContexts.Enumerate(GatherContexts);
NS_ASSERTION(gRootNode->mNext == nsnull, "dangling orphan");
PRInt32 listCount = ListNode(gRootNode, out, aIndent);
NS_ASSERTION(listCount == mStyleContexts.Count(), "graph incomplete");
delete gRootNode;
gRootNode = nsnull;
}
NS_LAYOUT nsresult NS_LAYOUT nsresult
NS_NewStyleSet(nsIStyleSet** aInstancePtrResult) NS_NewStyleSet(nsIStyleSet** aInstancePtrResult)