// Returns true if the pseudo-class requirement of a rule is met by a list of an element's pseudo-classes. bool ElementDefinition::IsPseudoClassRuleApplicable(const StringList& rule_pseudo_classes, const PseudoClassList& element_pseudo_classes) const { for (StringList::size_type i = 0; i < rule_pseudo_classes.size(); ++i) { if (element_pseudo_classes.find(rule_pseudo_classes[i]) == element_pseudo_classes.end()) return false; } return true; }
// Iterates over the properties in the definition. bool ElementDefinition::IterateProperties(int& index, const PseudoClassList& pseudo_classes, PseudoClassList& property_pseudo_classes, String& property_name, const Property*& property) const { if (index < properties.GetNumProperties()) { PropertyMap::const_iterator i = properties.GetProperties().begin(); for (int count = 0; count < index; ++count) ++i; property_pseudo_classes.clear(); property_name = (*i).first; property = &((*i).second); ++index; return true; } // Not in the base properties; check for pseudo-class overrides. int property_count = properties.GetNumProperties(); for (PseudoClassPropertyDictionary::const_iterator i = pseudo_class_properties.begin(); i != pseudo_class_properties.end(); ++i) { // Iterate over each pseudo-class set that has a definition for this property; if we find one that matches our // pseudo-class, increment our index counter and either return that property (if we hit the requested index) or // continue looking if we're still below it. for (size_t j = 0; j < (*i).second.size(); ++j) { if (IsPseudoClassRuleApplicable((*i).second[j].first, pseudo_classes)) { property_count++; if (property_count > index) { // Copy the list of pseudo-classes. property_pseudo_classes.clear(); for (size_t k = 0; k < (*i).second[j].first.size(); ++k) property_pseudo_classes.insert((*i).second[j].first[k]); property_name = (*i).first; property = &((*i).second[j].second); ++index; return true; } else { break; } } } } return false; }
// Returns the list of properties this element definition has explicit definitions for involving the given // pseudo-class. void ElementDefinition::GetDefinedProperties(PropertyNameList& property_names, const PseudoClassList& pseudo_classes, const String& pseudo_class) const { for (PseudoClassPropertyDictionary::const_iterator i = pseudo_class_properties.begin(); i != pseudo_class_properties.end(); ++i) { // If this property has already been found, don't bother checking for it again. if (property_names.find((*i).first) != property_names.end()) continue; const PseudoClassPropertyList& property_list = (*i).second; bool property_defined = false; for (size_t j = 0; j < property_list.size(); ++j) { bool rule_valid = true; bool found_toggled_pseudo_class = false; const StringList& rule_pseudo_classes = property_list[j].first; for (size_t j = 0; j < rule_pseudo_classes.size(); ++j) { if (rule_pseudo_classes[j] == pseudo_class) { found_toggled_pseudo_class = true; continue; } if (pseudo_classes.find(rule_pseudo_classes[j]) == pseudo_classes.end()) { rule_valid = false; break; } } if (rule_valid && found_toggled_pseudo_class) { property_defined = true; break; } } if (property_defined) property_names.insert((*i).first); } }
// Iterates over the properties defined on the element. bool ElementStyle::IterateProperties(int& index, PseudoClassList& property_pseudo_classes, String& name, const Property*& property) { // First check for locally defined properties. if (local_properties != NULL) { if (index < local_properties->GetNumProperties()) { PropertyMap::const_iterator i = local_properties->GetProperties().begin(); for (int count = 0; count < index; ++count) ++i; name = (*i).first; property = &((*i).second); property_pseudo_classes.clear(); ++index; return true; } } const ElementDefinition* definition = GetDefinition(); if (definition != NULL) { int index_offset = 0; if (local_properties != NULL) index_offset = local_properties->GetNumProperties(); // Offset the index to be relative to the definition before we start indexing. When we do get a property back, // check that it hasn't been overridden by the element's local properties; if so, continue on to the next one. index -= index_offset; while (definition->IterateProperties(index, pseudo_classes, property_pseudo_classes, name, property)) { if (local_properties == NULL || local_properties->GetProperty(name) == NULL) { index += index_offset; return true; } } return false; } return false; }
// Adds to a list the names of this node's pseudo-classes which are deemed volatile. bool StyleSheetNode::GetVolatilePseudoClasses(PseudoClassList& volatile_pseudo_classes) const { if (type == PSEUDO_CLASS) { bool self_volatile = !children[TAG].empty(); for (NodeMap::const_iterator i = children[PSEUDO_CLASS].begin(); i != children[PSEUDO_CLASS].end(); ++i) self_volatile = (*i).second->GetVolatilePseudoClasses(volatile_pseudo_classes) | self_volatile; if (self_volatile) volatile_pseudo_classes.insert(name); return self_volatile; } else { for (NodeMap::const_iterator i = children[PSEUDO_CLASS].begin(); i != children[PSEUDO_CLASS].end(); ++i) (*i).second->GetVolatilePseudoClasses(volatile_pseudo_classes); } return false; }
// Initialises the element definition from a list of style sheet nodes. void ElementDefinition::Initialise(const std::vector< const StyleSheetNode* >& style_sheet_nodes, const PseudoClassList& volatile_pseudo_classes, bool _structurally_volatile) { // Set the volatile structure flag. structurally_volatile = _structurally_volatile; // Mark all the volatile pseudo-classes as structurally volatile. for (PseudoClassList::const_iterator i = volatile_pseudo_classes.begin(); i != volatile_pseudo_classes.end(); ++i) pseudo_class_volatility[*i] = STRUCTURE_VOLATILE; // Merge the default (non-pseudo-class) properties. for (size_t i = 0; i < style_sheet_nodes.size(); ++i) properties.Merge(style_sheet_nodes[i]->GetProperties()); // Merge the pseudo-class properties. PseudoClassPropertyMap merged_pseudo_class_properties; for (size_t i = 0; i < style_sheet_nodes.size(); ++i) { // Merge all the pseudo-classes. PseudoClassPropertyMap node_properties; style_sheet_nodes[i]->GetPseudoClassProperties(node_properties); for (PseudoClassPropertyMap::iterator j = node_properties.begin(); j != node_properties.end(); ++j) { // Merge the property maps into one uber-map; for the decorators. PseudoClassPropertyMap::iterator k = merged_pseudo_class_properties.find((*j).first); if (k == merged_pseudo_class_properties.end()) merged_pseudo_class_properties[(*j).first] = (*j).second; else (*k).second.Merge((*j).second); // Search through all entries in this dictionary; we'll insert each one into our optimised list of // pseudo-class properties. for (PropertyMap::const_iterator k = (*j).second.GetProperties().begin(); k != (*j).second.GetProperties().end(); ++k) { const String& property_name = (*k).first; const Property& property = (*k).second; // Skip this property if its specificity is lower than the base property's, as in // this case it will never be used. const Property* default_property = properties.GetProperty(property_name); if (default_property != NULL && default_property->specificity >= property.specificity) continue; PseudoClassPropertyDictionary::iterator l = pseudo_class_properties.find(property_name); if (l == pseudo_class_properties.end()) pseudo_class_properties[property_name] = PseudoClassPropertyList(1, PseudoClassProperty((*j).first, property)); else { // Find the location to insert this entry in the map, based on property priorities. int index = 0; while (index < (int) (*l).second.size() && (*l).second[index].second.specificity > property.specificity) index++; (*l).second.insert((*l).second.begin() + index, PseudoClassProperty((*j).first, property)); } } } } InstanceDecorators(merged_pseudo_class_properties); InstanceFontEffects(merged_pseudo_class_properties); }