Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
nsCSSStyleSheet.cpp File Reference
#include "nsCSSStyleSheet.h"
#include "plarena.h"
#include "nsCRT.h"
#include "nsIAtom.h"
#include "nsIURL.h"
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "pldhash.h"
#include "nsHashtable.h"
#include "nsICSSPseudoComparator.h"
#include "nsCSSRuleProcessor.h"
#include "nsICSSStyleRule.h"
#include "nsICSSNameSpaceRule.h"
#include "nsICSSGroupRule.h"
#include "nsICSSImportRule.h"
#include "nsIMediaList.h"
#include "nsIStyledContent.h"
#include "nsIDocument.h"
#include "nsPresContext.h"
#include "nsIEventStateManager.h"
#include "nsHTMLAtoms.h"
#include "nsLayoutAtoms.h"
#include "nsIFrame.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsVoidArray.h"
#include "nsIUnicharInputStream.h"
#include "nsIDOMHTMLInputElement.h"
#include "nsIDOMHTMLOptionElement.h"
#include "nsIDOMStyleSheetList.h"
#include "nsIDOMCSSStyleSheet.h"
#include "nsIDOMCSSRule.h"
#include "nsIDOMCSSImportRule.h"
#include "nsIDOMCSSRuleList.h"
#include "nsIDOMMediaList.h"
#include "nsIDOMNode.h"
#include "nsDOMError.h"
#include "nsIPresShell.h"
#include "nsICSSParser.h"
#include "nsICSSLoader.h"
#include "nsICSSLoaderObserver.h"
#include "nsRuleWalker.h"
#include "nsCSSPseudoClasses.h"
#include "nsINameSpaceManager.h"
#include "nsXMLNameSpaceMap.h"
#include "nsITextContent.h"
#include "prlog.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsStyleUtil.h"
#include "nsQuickSort.h"
#include "nsContentUtils.h"
#include "nsIJSContextStack.h"
#include "nsIScriptSecurityManager.h"
#include "nsAttrValue.h"

Go to the source code of this file.

Classes

struct  RuleValue
struct  RuleHashTableEntry
class  RuleHash
struct  AttributeSelectorEntry
struct  RuleCascadeData
class  CSSRuleListImpl
class  CSSImportsCollectionImpl
struct  StateEnumData
struct  RuleArrayData

Defines

#define PL_ARENA_CONST_ALIGN_MASK   7
#define NS_RULEHASH_ARENA_BLOCK_SIZE   (256)
#define RULE_HASH_STAT_INCREMENT(var_)   PR_BEGIN_MACRO PR_END_MACRO
#define MIN_ENUM_LIST_SIZE   8
#define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_)   PR_BEGIN_MACRO PR_END_MACRO
#define BEGIN_MEDIA_CHANGE(sheet, doc)
#define END_MEDIA_CHANGE(sheet, doc)
#define STATE_CHECK(_state)
#define NS_IS_GREEDY_OPERATOR(ch)   (ch == PRUnichar(0) || ch == PRUnichar('~'))

Typedefs

typedef void(* RuleEnumFunc )(nsICSSStyleRule *aRule, nsCSSSelector *aSelector, void *aData)

Functions

 RuleHash_CIHashKey (PLDHashTable *table, const void *key)
 RuleHash_CIMatchEntry (PLDHashTable *table, const PLDHashEntryHdr *hdr, const void *key)
 RuleHash_CSMatchEntry (PLDHashTable *table, const PLDHashEntryHdr *hdr, const void *key)
 RuleHash_TagTable_GetKey (PLDHashTable *table, PLDHashEntryHdr *hdr)
 RuleHash_ClassTable_GetKey (PLDHashTable *table, PLDHashEntryHdr *hdr)
 RuleHash_IdTable_GetKey (PLDHashTable *table, PLDHashEntryHdr *hdr)
 RuleHash_NameSpaceTable_GetKey (PLDHashTable *table, PLDHashEntryHdr *hdr)
 RuleHash_NameSpaceTable_HashKey (PLDHashTable *table, const void *key)
 RuleHash_NameSpaceTable_MatchEntry (PLDHashTable *table, const PLDHashEntryHdr *hdr, const void *key)
 AttributeSelectorClearEntry (PLDHashTable *table, PLDHashEntryHdr *hdr)
static PRBool SetStyleSheetReference (nsISupports *aElement, void *aSheet)
static PRBool CloneRuleInto (nsISupports *aRule, void *aArray)
static PRBool CreateNameSpace (nsISupports *aRule, void *aNameSpacePtr)
static PRBool PR_CALLBACK EnumClearRuleCascades (void *aProcessor, void *aData)
nsresult NS_NewCSSStyleSheet (nsICSSStyleSheet **aInstancePtrResult)
static PRBool ValueIncludes (const nsSubstring &aValueList, const nsSubstring &aValue, const nsStringComparator &aComparator)
PRBool IsEventPseudo (nsIAtom *aAtom)
PRBool IsLinkPseudo (nsIAtom *aAtom)
PRBool IsQuirkEventSensitive (nsIAtom *aContentTag)
static PRBool IsSignificantChild (nsIContent *aChild, PRBool aTextIsSignificant, PRBool aWhitespaceIsSignificant)
static PRBool AttrMatchesValue (const nsAttrSelector *aAttrSelector, const nsString &aValue)
static PRBool SelectorMatches (RuleProcessorData &data, nsCSSSelector *aSelector, PRInt32 aStateMask, nsIAtom *aAttribute, PRInt8 aNegationIndex)
static PRBool SelectorMatchesTree (RuleProcessorData &aPrevData, nsCSSSelector *aSelector)
static void ContentEnumFunc (nsICSSStyleRule *aRule, nsCSSSelector *aSelector, void *aData)
static void PseudoEnumFunc (nsICSSStyleRule *aRule, nsCSSSelector *aSelector, void *aData)
PRBool IsSiblingOperator (PRUnichar oper)
 PR_STATIC_CALLBACK (PRBool) StateEnumFunc(void *aSelector
static PRBool InsertRuleByWeight (nsISupports *aRule, void *aData)
static PRBool CascadeSheetRulesInto (nsICSSStyleSheet *aSheet, void *aData)
 PR_STATIC_CALLBACK (int) CompareArrayData(const void *aArg1
 FillArray (nsHashKey *aKey, void *aData, void *aClosure)
static void PutRulesInList (nsObjectHashtable *aRuleArrays, nsVoidArray *aWeightedRules)
 Takes the hashtable of arrays (keyed by weight, in order sort) and puts them all in one big array which has a primary sort by weight and secondary sort by order.

Variables

static PLDHashTableOps RuleHash_TagTable_Ops
static PLDHashTableOps RuleHash_ClassTable_CSOps
static PLDHashTableOps RuleHash_ClassTable_CIOps
static PLDHashTableOps RuleHash_IdTable_CSOps
static PLDHashTableOps RuleHash_IdTable_CIOps
static PLDHashTableOps RuleHash_NameSpaceTable_Ops
static PLDHashTableOps AttributeSelectorOps
static const PRUnichar kNullCh = PRUnichar('\0')
const voidaArg2

Class Documentation

struct RuleArrayData

Definition at line 3859 of file nsCSSStyleSheet.cpp.

Class Members
nsVoidArray * mRuleArray
PRInt32 mWeight

Define Documentation

#define BEGIN_MEDIA_CHANGE (   sheet,
  doc 
)
Value:
if (sheet) {                                                 \
    rv = sheet->GetOwningDocument(*getter_AddRefs(doc));       \
    NS_ENSURE_SUCCESS(rv, rv);                                 \
  }                                                            \
  mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE);    \
  if (sheet) {                                                 \
    rv = sheet->WillDirty();                                   \
    NS_ENSURE_SUCCESS(rv, rv);                                 \
  }

Definition at line 916 of file nsCSSStyleSheet.cpp.

#define END_MEDIA_CHANGE (   sheet,
  doc 
)
Value:
if (sheet) {                                                 \
    sheet->DidDirty();                                         \
  }                                                            \
  /* XXXldb Pass something meaningful? */                      \
  if (doc) {                                                   \
    doc->StyleRuleChanged(sheet, nsnull, nsnull);              \
  }

Definition at line 927 of file nsCSSStyleSheet.cpp.

Definition at line 525 of file nsCSSStyleSheet.cpp.

#define NS_IS_GREEDY_OPERATOR (   ch)    (ch == PRUnichar(0) || ch == PRUnichar('~'))

Definition at line 3357 of file nsCSSStyleSheet.cpp.

Definition at line 44 of file nsCSSStyleSheet.cpp.

Definition at line 43 of file nsCSSStyleSheet.cpp.

Definition at line 334 of file nsCSSStyleSheet.cpp.

Definition at line 531 of file nsCSSStyleSheet.cpp.

#define STATE_CHECK (   _state)
Value:
((aStateMask & (_state)) ||                                \
   (localTrue == (0 != (data.mEventState & (_state)))))

Definition at line 2920 of file nsCSSStyleSheet.cpp.


Typedef Documentation

typedef void(* RuleEnumFunc)(nsICSSStyleRule *aRule, nsCSSSelector *aSelector, void *aData)

Definition at line 338 of file nsCSSStyleSheet.cpp.


Function Documentation

Definition at line 656 of file nsCSSStyleSheet.cpp.

Here is the call graph for this function:

static PRBool AttrMatchesValue ( const nsAttrSelector aAttrSelector,
const nsString aValue 
) [static]

Definition at line 2892 of file nsCSSStyleSheet.cpp.

{
  NS_PRECONDITION(aAttrSelector, "Must have an attribute selector");
  const nsDefaultStringComparator defaultComparator;
  const nsCaseInsensitiveStringComparator ciComparator;
  const nsStringComparator& comparator = aAttrSelector->mCaseSensitive
                ? NS_STATIC_CAST(const nsStringComparator&, defaultComparator)
                : NS_STATIC_CAST(const nsStringComparator&, ciComparator);
  switch (aAttrSelector->mFunction) {
    case NS_ATTR_FUNC_EQUALS: 
      return aValue.Equals(aAttrSelector->mValue, comparator);
    case NS_ATTR_FUNC_INCLUDES: 
      return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
    case NS_ATTR_FUNC_DASHMATCH: 
      return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
    case NS_ATTR_FUNC_ENDSMATCH:
      return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
    case NS_ATTR_FUNC_BEGINSMATCH:
      return StringBeginsWith(aValue, aAttrSelector->mValue, comparator);
    case NS_ATTR_FUNC_CONTAINSMATCH:
      return FindInReadable(aAttrSelector->mValue, aValue, comparator);
    default:
      NS_NOTREACHED("Shouldn't be ending up here");
      return PR_FALSE;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool CascadeSheetRulesInto ( nsICSSStyleSheet aSheet,
void aData 
) [static]

Definition at line 3838 of file nsCSSStyleSheet.cpp.

{
  nsCSSStyleSheet*  sheet = NS_STATIC_CAST(nsCSSStyleSheet*, aSheet);
  CascadeEnumData* data = NS_STATIC_CAST(CascadeEnumData*, aData);
  PRBool bSheetApplicable = PR_TRUE;
  sheet->GetApplicable(bSheetApplicable);

  if (bSheetApplicable && sheet->UseForMedium(data->mPresContext)) {
    nsCSSStyleSheet* child = sheet->mFirstChild;
    while (child) {
      CascadeSheetRulesInto(child, data);
      child = child->mNext;
    }

    if (sheet->mInner && sheet->mInner->mOrderedRules) {
      sheet->mInner->mOrderedRules->EnumerateForwards(InsertRuleByWeight, data);
    }
  }
  return PR_TRUE;
}

Here is the caller graph for this function:

static PRBool CloneRuleInto ( nsISupports *  aRule,
void aArray 
) [static]

Definition at line 1155 of file nsCSSStyleSheet.cpp.

{
  nsICSSRule* rule = (nsICSSRule*)aRule;
  nsICSSRule* clone = nsnull;
  rule->Clone(clone);
  if (clone) {
    nsISupportsArray* array = (nsISupportsArray*)aArray;
    array->AppendElement(clone);
    NS_RELEASE(clone);
  }
  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ContentEnumFunc ( nsICSSStyleRule aRule,
nsCSSSelector aSelector,
void aData 
) [static]

Definition at line 3444 of file nsCSSStyleSheet.cpp.

{
  ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;

  if (SelectorMatches(*data, aSelector, 0, nsnull, 0)) {
    nsCSSSelector *next = aSelector->mNext;
    if (!next || SelectorMatchesTree(*data, next)) {
      // for performance, require that every implementation of
      // nsICSSStyleRule return the same pointer for nsIStyleRule (why
      // would anything multiply inherit nsIStyleRule anyway?)
#ifdef DEBUG
      nsCOMPtr<nsIStyleRule> iRule = do_QueryInterface(aRule);
      NS_ASSERTION(NS_STATIC_CAST(nsIStyleRule*, aRule) == iRule.get(),
                   "Please fix QI so this performance optimization is valid");
#endif
      data->mRuleWalker->Forward(NS_STATIC_CAST(nsIStyleRule*, aRule));
      // nsStyleSet will deal with the !important rule
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool CreateNameSpace ( nsISupports *  aRule,
void aNameSpacePtr 
) [static]

Definition at line 1234 of file nsCSSStyleSheet.cpp.

{
  nsICSSRule* rule = (nsICSSRule*)aRule;
  PRInt32 type = nsICSSRule::UNKNOWN_RULE;
  rule->GetType(type);
  if (nsICSSRule::NAMESPACE_RULE == type) {
    nsICSSNameSpaceRule*  nameSpaceRule = (nsICSSNameSpaceRule*)rule;
    nsXMLNameSpaceMap *nameSpaceMap =
      NS_STATIC_CAST(nsXMLNameSpaceMap*, aNameSpacePtr);

    nsIAtom*      prefix = nsnull;
    nsAutoString  urlSpec;
    nameSpaceRule->GetPrefix(prefix);
    nameSpaceRule->GetURLSpec(urlSpec);

    nameSpaceMap->AddPrefix(prefix, urlSpec);
    return PR_TRUE;
  }
  // stop if not namespace, import or charset because namespace can't follow anything else
  return (((nsICSSRule::CHARSET_RULE == type) || 
           (nsICSSRule::IMPORT_RULE)) ? PR_TRUE : PR_FALSE); 
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PR_CALLBACK EnumClearRuleCascades ( void aProcessor,
void aData 
) [static]

Definition at line 1992 of file nsCSSStyleSheet.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

FillArray ( nsHashKey *  aKey,
void aData,
void aClosure 
)

Definition at line 3884 of file nsCSSStyleSheet.cpp.

{
  nsPRUint32Key* key = NS_STATIC_CAST(nsPRUint32Key*, aKey);
  nsVoidArray* weightArray = NS_STATIC_CAST(nsVoidArray*, aData);
  FillArrayData* data = NS_STATIC_CAST(FillArrayData*, aClosure);

  RuleArrayData& ruleData = data->mArrayData[data->mIndex++];
  ruleData.mRuleArray = weightArray;
  ruleData.mWeight = key->GetValue();

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool InsertRuleByWeight ( nsISupports *  aRule,
void aData 
) [static]

Definition at line 3801 of file nsCSSStyleSheet.cpp.

{
  nsICSSRule* rule = (nsICSSRule*)aRule;
  CascadeEnumData* data = (CascadeEnumData*)aData;
  PRInt32 type = nsICSSRule::UNKNOWN_RULE;
  rule->GetType(type);

  if (nsICSSRule::STYLE_RULE == type) {
    nsICSSStyleRule* styleRule = (nsICSSStyleRule*)rule;

    for (nsCSSSelectorList *sel = styleRule->Selector();
         sel; sel = sel->mNext) {
      PRInt32 weight = sel->mWeight;
      nsPRUint32Key key(weight);
      nsAutoVoidArray *rules =
        NS_STATIC_CAST(nsAutoVoidArray*, data->mRuleArrays.Get(&key));
      if (!rules) {
        rules = new nsAutoVoidArray();
        if (!rules) return PR_FALSE; // out of memory
        data->mRuleArrays.Put(&key, rules);
      }
      RuleValue *info =
        new (data->mArena) RuleValue(styleRule, sel->mSelectors);
      rules->AppendElement(info);
    }
  }
  else if (nsICSSRule::MEDIA_RULE == type ||
           nsICSSRule::DOCUMENT_RULE == type) {
    nsICSSGroupRule* groupRule = (nsICSSGroupRule*)rule;
    if (groupRule->UseForPresentation(data->mPresContext))
      groupRule->EnumerateRulesForwards(InsertRuleByWeight, aData);
  }
  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool IsEventPseudo ( nsIAtom aAtom) [inline]

Definition at line 2830 of file nsCSSStyleSheet.cpp.

{
  return nsCSSPseudoClasses::active == aAtom || 
         nsCSSPseudoClasses::mozDragOver == aAtom || 
         nsCSSPseudoClasses::focus == aAtom || 
         nsCSSPseudoClasses::hover == aAtom ||
         nsCSSPseudoClasses::target == aAtom; 
         // XXX selected, enabled, disabled, selection?
}

Here is the caller graph for this function:

PRBool IsLinkPseudo ( nsIAtom aAtom) [inline]

Definition at line 2840 of file nsCSSStyleSheet.cpp.

{
  return PRBool ((nsCSSPseudoClasses::link == aAtom) || 
                 (nsCSSPseudoClasses::visited == aAtom) ||
                 (nsCSSPseudoClasses::mozAnyLink == aAtom));
}

Here is the caller graph for this function:

PRBool IsQuirkEventSensitive ( nsIAtom aContentTag) [inline]

Definition at line 2851 of file nsCSSStyleSheet.cpp.

{
  return PRBool ((nsHTMLAtoms::button == aContentTag) ||
                 (nsHTMLAtoms::img == aContentTag)    ||
                 (nsHTMLAtoms::input == aContentTag)  ||
                 (nsHTMLAtoms::label == aContentTag)  ||
                 (nsHTMLAtoms::select == aContentTag) ||
                 (nsHTMLAtoms::textarea == aContentTag));
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool IsSiblingOperator ( PRUnichar  oper) [inline]

Definition at line 3552 of file nsCSSStyleSheet.cpp.

{
  return oper == PRUnichar('+') || oper == PRUnichar('~');
}
static PRBool IsSignificantChild ( nsIContent aChild,
PRBool  aTextIsSignificant,
PRBool  aWhitespaceIsSignificant 
) [static]

Definition at line 2862 of file nsCSSStyleSheet.cpp.

{
  NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant,
               "Nonsensical arguments");

  PRBool isText = aChild->IsContentOfType(nsIContent::eTEXT);

  if (!isText && !aChild->IsContentOfType(nsIContent::eCOMMENT) &&
      !aChild->IsContentOfType(nsIContent::ePROCESSING_INSTRUCTION)) {
    return PR_TRUE;
  }

  if (aTextIsSignificant && isText) {
    if (!aWhitespaceIsSignificant) {
       nsCOMPtr<nsITextContent> text = do_QueryInterface(aChild);
      
       if (text && !text->IsOnlyWhitespace())
         return PR_TRUE;
    }
    else {
      return PR_TRUE;
    }
  }

  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult NS_NewCSSStyleSheet ( nsICSSStyleSheet **  aInstancePtrResult)

Definition at line 2607 of file nsCSSStyleSheet.cpp.

{
  nsCSSStyleSheet  *it = new nsCSSStyleSheet();

  if (nsnull == it) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  NS_ADDREF(it);
  *aInstancePtrResult = it;
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PR_STATIC_CALLBACK ( int  ) const
static void PseudoEnumFunc ( nsICSSStyleRule aRule,
nsCSSSelector aSelector,
void aData 
) [static]

Definition at line 3490 of file nsCSSStyleSheet.cpp.

{
  PseudoRuleProcessorData* data = (PseudoRuleProcessorData*)aData;

  NS_ASSERTION(aSelector->mTag == data->mPseudoTag, "RuleHash failure");
  PRBool matches = PR_TRUE;
  if (data->mComparator)
    data->mComparator->PseudoMatches(data->mPseudoTag, aSelector, &matches);

  if (matches) {
    nsCSSSelector *selector = aSelector->mNext;

    if (selector) { // test next selector specially
      if (PRUnichar('+') == selector->mOperator) {
        return; // not valid here, can't match
      }
      if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
        selector = selector->mNext;
      }
      else {
        if (PRUnichar('>') == selector->mOperator) {
          return; // immediate parent didn't match
        }
      }
    }

    if (selector && 
        (! SelectorMatchesTree(*data, selector))) {
      return; // remaining selectors didn't match
    }

    // for performance, require that every implementation of
    // nsICSSStyleRule return the same pointer for nsIStyleRule (why
    // would anything multiply inherit nsIStyleRule anyway?)
#ifdef DEBUG
    nsCOMPtr<nsIStyleRule> iRule = do_QueryInterface(aRule);
    NS_ASSERTION(NS_STATIC_CAST(nsIStyleRule*, aRule) == iRule.get(),
                 "Please fix QI so this performance optimization is valid");
#endif
    data->mRuleWalker->Forward(NS_STATIC_CAST(nsIStyleRule*, aRule));
    // nsStyleSet will deal with the !important rule
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PutRulesInList ( nsObjectHashtable *  aRuleArrays,
nsVoidArray aWeightedRules 
) [static]

Takes the hashtable of arrays (keyed by weight, in order sort) and puts them all in one big array which has a primary sort by weight and secondary sort by order.

Definition at line 3902 of file nsCSSStyleSheet.cpp.

{
  PRInt32 arrayCount = aRuleArrays->Count();
  RuleArrayData* arrayData = new RuleArrayData[arrayCount];
  FillArrayData faData(arrayData);
  aRuleArrays->Enumerate(FillArray, &faData);
  NS_QuickSort(arrayData, arrayCount, sizeof(RuleArrayData),
               CompareArrayData, nsnull);
  for (PRInt32 i = 0; i < arrayCount; ++i)
    aWeightedRules->AppendElements(*arrayData[i].mRuleArray);

  delete [] arrayData;
}

Here is the call graph for this function:

Here is the caller graph for this function:

RuleHash_CIHashKey ( PLDHashTable table,
const void key 
)

Definition at line 155 of file nsCSSStyleSheet.cpp.

{
  nsIAtom *atom = NS_CONST_CAST(nsIAtom*, NS_STATIC_CAST(const nsIAtom*, key));

  nsAutoString str;
  atom->ToString(str);
  ToUpperCase(str);
  return HashString(str);
}

Here is the call graph for this function:

Definition at line 166 of file nsCSSStyleSheet.cpp.

{
  nsIAtom *match_atom = NS_CONST_CAST(nsIAtom*, NS_STATIC_CAST(const nsIAtom*,
                            key));
  // Use the |getKey| callback to avoid code duplication.
  // XXX Ugh!  Why does |getKey| have different |const|-ness?
  nsIAtom *entry_atom = NS_CONST_CAST(nsIAtom*, NS_STATIC_CAST(const nsIAtom*,
             table->ops->getKey(table, NS_CONST_CAST(PLDHashEntryHdr*, hdr))));

  // Check for case-sensitive match first.
  if (match_atom == entry_atom)
    return PR_TRUE;

  const char *match_str, *entry_str;
  match_atom->GetUTF8String(&match_str);
  entry_atom->GetUTF8String(&entry_str);

  return (nsCRT::strcasecmp(entry_str, match_str) == 0);
}

Here is the call graph for this function:

Definition at line 209 of file nsCSSStyleSheet.cpp.

Definition at line 188 of file nsCSSStyleSheet.cpp.

{
  nsIAtom *match_atom = NS_CONST_CAST(nsIAtom*, NS_STATIC_CAST(const nsIAtom*,
                            key));
  // Use the |getKey| callback to avoid code duplication.
  // XXX Ugh!  Why does |getKey| have different |const|-ness?
  nsIAtom *entry_atom = NS_CONST_CAST(nsIAtom*, NS_STATIC_CAST(const nsIAtom*,
             table->ops->getKey(table, NS_CONST_CAST(PLDHashEntryHdr*, hdr))));

  return match_atom == entry_atom;
}

Definition at line 216 of file nsCSSStyleSheet.cpp.

Definition at line 230 of file nsCSSStyleSheet.cpp.

{
  return NS_PTR_TO_INT32(key);
}

Definition at line 236 of file nsCSSStyleSheet.cpp.

Definition at line 202 of file nsCSSStyleSheet.cpp.

static PRBool SelectorMatches ( RuleProcessorData data,
nsCSSSelector aSelector,
PRInt32  aStateMask,
nsIAtom aAttribute,
PRInt8  aNegationIndex 
) [static]

Definition at line 2929 of file nsCSSStyleSheet.cpp.

{
  // if we are dealing with negations, reverse the values of PR_TRUE and PR_FALSE
  PRBool localFalse = 0 < aNegationIndex;
  PRBool localTrue = 0 == aNegationIndex;
  PRBool result = localTrue;

  // Do not perform the test if aNegationIndex==1
  // because it then contains only negated IDs, classes, attributes and pseudo-
  // classes
  if (1 != aNegationIndex) {
    if (kNameSpaceID_Unknown != aSelector->mNameSpace) {
      if (data.mNameSpaceID != aSelector->mNameSpace) {
        result = localFalse;
      }
    }
    if (localTrue == result) {
      if ((nsnull != aSelector->mTag) && (aSelector->mTag != data.mContentTag)) {
        result = localFalse;
      }
    }
    // optimization : bail out early if we can
    if (!result) {
      return PR_FALSE;
    }
  }

  result = PR_TRUE;

  // test for pseudo class match
  // first-child, root, lang, active, focus, hover, link, visited...
  // XXX disabled, enabled, selected, selection
  for (nsAtomStringList* pseudoClass = aSelector->mPseudoClassList;
       pseudoClass && result; pseudoClass = pseudoClass->mNext) {
    if ((nsCSSPseudoClasses::firstChild == pseudoClass->mAtom) ||
        (nsCSSPseudoClasses::firstNode == pseudoClass->mAtom) ) {
      nsIContent *firstChild = nsnull;
      nsIContent *parent = data.mParentContent;
      if (parent) {
        PRBool acceptNonWhitespace =
          nsCSSPseudoClasses::firstNode == pseudoClass->mAtom;
        PRInt32 index = -1;
        do {
          firstChild = parent->GetChildAt(++index);
          // stop at first non-comment and non-whitespace node (and
          // non-text node for firstChild)
        } while (firstChild &&
                 !IsSignificantChild(firstChild, acceptNonWhitespace, PR_FALSE));
      }
      result = localTrue == (data.mContent == firstChild);
    }
    else if ((nsCSSPseudoClasses::lastChild == pseudoClass->mAtom) ||
             (nsCSSPseudoClasses::lastNode == pseudoClass->mAtom)) {
      nsIContent *lastChild = nsnull;
      nsIContent *parent = data.mParentContent;
      if (parent) {
        PRBool acceptNonWhitespace =
          nsCSSPseudoClasses::lastNode == pseudoClass->mAtom;
        PRUint32 index = parent->GetChildCount();
        do {
          lastChild = parent->GetChildAt(--index);
          // stop at first non-comment and non-whitespace node (and
          // non-text node for lastChild)
        } while (lastChild &&
                 !IsSignificantChild(lastChild, acceptNonWhitespace, PR_FALSE));
      }
      result = localTrue == (data.mContent == lastChild);
    }
    else if (nsCSSPseudoClasses::onlyChild == pseudoClass->mAtom) {
      nsIContent *onlyChild = nsnull;
      nsIContent *moreChild = nsnull;
      nsIContent *parent = data.mParentContent;
      if (parent) {
        PRInt32 index = -1;
        do {
          onlyChild = parent->GetChildAt(++index);
          // stop at first non-comment, non-whitespace and non-text node
        } while (onlyChild &&
                 !IsSignificantChild(onlyChild, PR_FALSE, PR_FALSE));
        if (data.mContent == onlyChild) {
          // see if there's any more
          do {
            moreChild = parent->GetChildAt(++index);
          } while (moreChild && !IsSignificantChild(moreChild, PR_FALSE, PR_FALSE));
        }
      }
      result = localTrue == (data.mContent == onlyChild &&
                             moreChild == nsnull);
    }
    else if (nsCSSPseudoClasses::empty == pseudoClass->mAtom ||
             nsCSSPseudoClasses::mozOnlyWhitespace == pseudoClass->mAtom) {
      nsIContent *child = nsnull;
      nsIContent *element = data.mContent;
      PRBool isWhitespaceSignificant =
        nsCSSPseudoClasses::empty == pseudoClass->mAtom;
      PRInt32 index = -1;

      do {
        child = element->GetChildAt(++index);
        // stop at first non-comment (and non-whitespace for
        // :-moz-only-whitespace) node        
      } while (child && !IsSignificantChild(child, PR_TRUE, isWhitespaceSignificant));
      result = localTrue == (child == nsnull);
    }
    else if (nsCSSPseudoClasses::root == pseudoClass->mAtom) {
      if (data.mParentContent) {
        result = localFalse;
      }
      else {
        result = localTrue;
      }
    }
    else if (nsCSSPseudoClasses::mozBoundElement == pseudoClass->mAtom) {
      // XXXldb How do we know where the selector came from?  And what
      // if there are multiple bindings, and we should be matching the
      // outer one?
      result = (data.mScopedRoot && data.mScopedRoot == data.mContent)
                 ? localTrue : localFalse;
    }
    else if (nsCSSPseudoClasses::lang == pseudoClass->mAtom) {
      NS_ASSERTION(nsnull != pseudoClass->mString, "null lang parameter");
      result = localFalse;
      if (pseudoClass->mString && *pseudoClass->mString) {
        // We have to determine the language of the current element.  Since
        // this is currently no property and since the language is inherited
        // from the parent we have to be prepared to look at all parent
        // nodes.  The language itself is encoded in the LANG attribute.
        const nsString* lang = data.GetLang();
        if (lang && !lang->IsEmpty()) { // null check for out-of-memory
          result = localTrue == nsStyleUtil::DashMatchCompare(*lang,
                                    nsDependentString(pseudoClass->mString), 
                                    nsCaseInsensitiveStringComparator());
        }
        else {
          nsIDocument* doc = data.mContent->GetDocument();
          if (doc) {
            // Try to get the language from the HTTP header or if this
            // is missing as well from the preferences.
            // The content language can be a comma-separated list of
            // language codes.
            nsAutoString language;
            doc->GetContentLanguage(language);

            nsDependentString langString(pseudoClass->mString);
            language.StripWhitespace();
            PRInt32 begin = 0;
            PRInt32 len = language.Length();
            while (begin < len) {
              PRInt32 end = language.FindChar(PRUnichar(','), begin);
              if (end == kNotFound) {
                end = len;
              }
              if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end-begin),
                                   langString,
                                   nsCaseInsensitiveStringComparator())) {
                result = localTrue;
                break;
              }
              begin = end + 1;
            }
          }
        }
      }
    }
    else if (IsEventPseudo(pseudoClass->mAtom)) {
      // check if the element is event-sensitive
      if (data.mCompatMode == eCompatibility_NavQuirks &&
          // global selector (but don't check .class):
          !aSelector->mTag && !aSelector->mIDList && !aSelector->mAttrList &&
          // This (or the other way around) both make :not() asymmetric
          // in quirks mode (and it's hard to work around since we're
          // testing the current mNegations, not the first
          // (unnegated)). This at least makes it closer to the spec.
          aNegationIndex == 0 &&
          // :hover or :active
          (nsCSSPseudoClasses::active == pseudoClass->mAtom ||
           nsCSSPseudoClasses::hover == pseudoClass->mAtom) &&
          // important for |IsQuirkEventSensitive|:
          data.mIsHTMLContent && !data.mIsHTMLLink &&
          !IsQuirkEventSensitive(data.mContentTag)) {
        // In quirks mode, only make certain elements sensitive to
        // selectors ":hover" and ":active".
        result = localFalse;
      } else {
        if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
          result = STATE_CHECK(NS_EVENT_STATE_ACTIVE);
        }
        else if (nsCSSPseudoClasses::focus == pseudoClass->mAtom) {
          result = STATE_CHECK(NS_EVENT_STATE_FOCUS);
        }
        else if (nsCSSPseudoClasses::hover == pseudoClass->mAtom) {
          result = STATE_CHECK(NS_EVENT_STATE_HOVER);
        }
        else if (nsCSSPseudoClasses::mozDragOver == pseudoClass->mAtom) {
          result = STATE_CHECK(NS_EVENT_STATE_DRAGOVER);
        }
        else if (nsCSSPseudoClasses::target == pseudoClass->mAtom) {
          result = STATE_CHECK(NS_EVENT_STATE_URLTARGET);
        }
      } 
    }
    else if (IsLinkPseudo(pseudoClass->mAtom)) {
      if (data.mIsHTMLLink || data.mIsSimpleXLink) {
        if (nsCSSPseudoClasses::mozAnyLink == pseudoClass->mAtom) {
          result = localTrue;
        }
        else if (nsCSSPseudoClasses::link == pseudoClass->mAtom) {
          result = (aStateMask & NS_EVENT_STATE_VISITED) ||
            localTrue == (eLinkState_Unvisited == data.mLinkState);
        }
        else if (nsCSSPseudoClasses::visited == pseudoClass->mAtom) {
          result = (aStateMask & NS_EVENT_STATE_VISITED) ||
            localTrue == (eLinkState_Visited == data.mLinkState);
        }
      }
      else {
        result = localFalse;  // not a link
      }
    }
    else if (nsCSSPseudoClasses::checked == pseudoClass->mAtom) {
      // This pseudoclass matches the selected state on the following elements:
      //  <option>
      //  <input type=checkbox>
      //  <input type=radio>
      result = STATE_CHECK(NS_EVENT_STATE_CHECKED);
    }
    else if (nsCSSPseudoClasses::enabled == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_ENABLED);
    }
    else if (nsCSSPseudoClasses::disabled == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_DISABLED);
    }
    else if (nsCSSPseudoClasses::required == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_REQUIRED);
    }
    else if (nsCSSPseudoClasses::optional == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_OPTIONAL);
    }
    else if (nsCSSPseudoClasses::valid == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_VALID);
    }
    else if (nsCSSPseudoClasses::invalid == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_INVALID);
    }
    else if (nsCSSPseudoClasses::inRange == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_INRANGE);
    }
    else if (nsCSSPseudoClasses::outOfRange == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_OUTOFRANGE);
    }
    else if (nsCSSPseudoClasses::mozReadOnly == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_MOZ_READONLY);
    }
    else if (nsCSSPseudoClasses::mozReadWrite == pseudoClass->mAtom) {
      result = STATE_CHECK(NS_EVENT_STATE_MOZ_READWRITE);
    }
    else if (nsCSSPseudoClasses::mozIsHTML == pseudoClass->mAtom) {
      result =
        (data.mIsHTMLContent &&
         data.mContent->GetNameSpaceID() == kNameSpaceID_None) ? localTrue :
                                                                 localFalse;
    }
    else {
      NS_ERROR("CSS parser parsed a pseudo-class that we do not handle");
      result = PR_FALSE;  // unknown pseudo class
    }
  }

  // namespace/tag match

  if (result && aSelector->mAttrList) {
    // test for attribute match
    if (!data.mHasAttributes && !aAttribute) {
      // if no attributes on the content, no match
      result = localFalse;
    } else {
      result = localTrue;
      nsAttrSelector* attr = aSelector->mAttrList;
      do {
        if (attr->mAttr == aAttribute) {
          // XXX we should really have a namespace, not just an attr
          // name, in HasAttributeDependentStyle!
          result = PR_TRUE;
        }
        else if (attr->mNameSpace == kNameSpaceID_Unknown) {
          // Attr selector with a wildcard namespace.  We have to examine all
          // the attributes on our content node....  This sort of selector is
          // essentially a boolean OR, over all namespaces, of equivalent attr
          // selectors with those namespaces.  So to evaluate whether it
          // matches, evaluate for each namespace (the only namespaces that
          // have a chance at matching, of course, are ones that the element
          // actually has attributes in), short-circuiting if we ever match.
          // Then deal with the localFalse/localTrue stuff.
          PRUint32 attrCount = data.mContent->GetAttrCount();
          PRInt32 nameSpaceID;
          nsCOMPtr<nsIAtom> name;
          nsCOMPtr<nsIAtom> prefix;
          PRBool attrSelectorMatched = PR_FALSE;
          for (PRUint32 i = 0; i < attrCount; ++i) {
#ifdef DEBUG
            nsresult attrState =
#endif
              data.mContent->GetAttrNameAt(i, &nameSpaceID,
                                           getter_AddRefs(name),
                                           getter_AddRefs(prefix));
            NS_ASSERTION(NS_SUCCEEDED(attrState),
                         "GetAttrCount lied or GetAttrNameAt failed");
            if (name != attr->mAttr) {
              continue;
            }
            if (attr->mFunction == NS_ATTR_FUNC_SET) {
              attrSelectorMatched = PR_TRUE;
            } else {
              nsAutoString value;
#ifdef DEBUG
              attrState =
#endif
                data.mContent->GetAttr(nameSpaceID, name, value);
              NS_ASSERTION(NS_SUCCEEDED(attrState) &&
                           NS_CONTENT_ATTR_NOT_THERE != attrState,
                           "GetAttrNameAt lied or GetAttr failed");
              attrSelectorMatched = AttrMatchesValue(attr, value);
            }

            // At this point |attrSelectorMatched| has been set by us
            // explicitly in this loop.  If it's PR_FALSE, we may still match
            // -- the content may have another attribute with the same name but
            // in a different namespace.  But if it's PR_TRUE, we are done (we
            // can short-circuit the boolean OR described above).
            if (attrSelectorMatched) {
              break;
            }
          }
          
          // Now adjust for a possible negation
          result = localTrue == attrSelectorMatched;
        }
        else if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
          result = localFalse;
        }
        else if (attr->mFunction != NS_ATTR_FUNC_SET) {
          nsAutoString value;
#ifdef DEBUG
          nsresult attrState =
#endif
              data.mContent->GetAttr(attr->mNameSpace, attr->mAttr, value);
          NS_ASSERTION(NS_SUCCEEDED(attrState) &&
                       NS_CONTENT_ATTR_NOT_THERE != attrState,
                       "HasAttr lied or GetAttr failed");
          result = localTrue == AttrMatchesValue(attr, value);
        }
        
        attr = attr->mNext;
      } while (attr && result);
    }
  }
  if (result && (aSelector->mIDList || aSelector->mClassList)) {
    // test for ID & class match
    result = localFalse;
    if (data.mStyledContent) {
      // case sensitivity: bug 93371
      PRBool isCaseSensitive = data.mCompatMode != eCompatibility_NavQuirks;
      nsAtomList* IDList = aSelector->mIDList;
      if (nsnull == IDList ||
          (aAttribute && aAttribute == data.mContent->GetIDAttributeName())) {
        result = PR_TRUE;
      }
      else if (nsnull != data.mContentID) {
        result = PR_TRUE;
        if (isCaseSensitive) {
          do {
            if (localTrue == (IDList->mAtom != data.mContentID)) {
              result = PR_FALSE;
              break;
            }
            IDList = IDList->mNext;
          } while (IDList);
        } else {
          const char* id1Str;
          data.mContentID->GetUTF8String(&id1Str);
          nsDependentCString id1(id1Str);
          do {
            const char* id2Str;
            IDList->mAtom->GetUTF8String(&id2Str);
            nsDependentCString id2(id2Str);
            if (localTrue !=
                id1.Equals(id2, nsCaseInsensitiveCStringComparator())) {
              result = PR_FALSE;
              break;
            }
            IDList = IDList->mNext;
          } while (IDList);
        }
      }
      
      if (result &&
          (!aAttribute || aAttribute != data.mStyledContent->GetClassAttributeName())) {
        nsAtomList* classList = aSelector->mClassList;
        while (nsnull != classList) {
          if (localTrue == (!data.mStyledContent->HasClass(classList->mAtom, isCaseSensitive))) {
            result = PR_FALSE;
            break;
          }
          classList = classList->mNext;
        }
      }
    }
  }
  
  // apply SelectorMatches to the negated selectors in the chain
  if (result && (nsnull != aSelector->mNegations)) {
    result = SelectorMatches(data, aSelector->mNegations, aStateMask,
                             aAttribute, aNegationIndex+1);
  }
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool SelectorMatchesTree ( RuleProcessorData aPrevData,
nsCSSSelector aSelector 
) [static]

Definition at line 3359 of file nsCSSStyleSheet.cpp.

{
  nsCSSSelector* selector = aSelector;
  RuleProcessorData* prevdata = &aPrevData;
  while (selector) { // check compound selectors
    // If we don't already have a RuleProcessorData for the next
    // appropriate content (whether parent or previous sibling), create
    // one.

    // for adjacent sibling combinators, the content to test against the
    // selector is the previous sibling *element*
    RuleProcessorData* data;
    if (PRUnichar('+') == selector->mOperator ||
        PRUnichar('~') == selector->mOperator) {
      data = prevdata->mPreviousSiblingData;
      if (!data) {
        nsIContent* content = prevdata->mContent;
        nsIContent* parent = content->GetParent();
        if (parent) {
          PRInt32 index = parent->IndexOf(content);
          while (0 <= --index) {
            content = parent->GetChildAt(index);
            if (content->IsContentOfType(nsIContent::eELEMENT)) {
              data = new (prevdata->mPresContext)
                          RuleProcessorData(prevdata->mPresContext, content,
                                            prevdata->mRuleWalker,
                                            &prevdata->mCompatMode);
              prevdata->mPreviousSiblingData = data;    
              break;
            }
          }
        }
      }
    }
    // for descendant combinators and child combinators, the content
    // to test against is the parent
    else {
      data = prevdata->mParentData;
      if (!data) {
        nsIContent *content = prevdata->mContent->GetParent();
        if (content) {
          data = new (prevdata->mPresContext)
                      RuleProcessorData(prevdata->mPresContext, content,
                                        prevdata->mRuleWalker,
                                        &prevdata->mCompatMode);
          prevdata->mParentData = data;    
        }
      }
    }
    if (! data) {
      return PR_FALSE;
    }
    if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
      // to avoid greedy matching, we need to recur if this is a
      // descendant combinator and the next combinator is not
      if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
          (selector->mNext) &&
          (!NS_IS_GREEDY_OPERATOR(selector->mNext->mOperator))) {

        // pretend the selector didn't match, and step through content
        // while testing the same selector

        // This approach is slightly strange in that when it recurs
        // it tests from the top of the content tree, down.  This
        // doesn't matter much for performance since most selectors
        // don't match.  (If most did, it might be faster...)
        if (SelectorMatchesTree(*data, selector)) {
          return PR_TRUE;
        }
      }
      selector = selector->mNext;
    }
    else {
      // for adjacent sibling and child combinators, if we didn't find
      // a match, we're done
      if (!NS_IS_GREEDY_OPERATOR(selector->mOperator)) {
        return PR_FALSE;  // parent was required to match
      }
    }
    prevdata = data;
  }
  return PR_TRUE; // all the selectors matched.
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool SetStyleSheetReference ( nsISupports *  aElement,
void aSheet 
) [static]

Definition at line 1135 of file nsCSSStyleSheet.cpp.

{
  nsICSSRule*  rule = (nsICSSRule*)aElement;

  if (nsnull != rule) {
    rule->SetStyleSheet((nsICSSStyleSheet*)aSheet);
  }
  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool ValueIncludes ( const nsSubstring aValueList,
const nsSubstring aValue,
const nsStringComparator &  aComparator 
) [static]

Definition at line 2801 of file nsCSSStyleSheet.cpp.

{
  const PRUnichar *p = aValueList.BeginReading(),
              *p_end = aValueList.EndReading();

  while (p < p_end) {
    // skip leading space
    while (p != p_end && nsCRT::IsAsciiSpace(*p))
      ++p;

    const PRUnichar *val_start = p;

    // look for space or end
    while (p != p_end && !nsCRT::IsAsciiSpace(*p))
      ++p;

    const PRUnichar *val_end = p;

    if (val_start < val_end &&
        aValue.Equals(Substring(val_start, val_end), aComparator))
      return PR_TRUE;

    ++p; // we know the next character is not whitespace
  }
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 3864 of file nsCSSStyleSheet.cpp.

const PRUnichar kNullCh = PRUnichar('\0') [static]

Definition at line 2799 of file nsCSSStyleSheet.cpp.