/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
 * All rights reserved.
 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
 * (http://www.torchmobile.com/)
 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "core/css/ElementRuleCollector.h"

#include "core/css/CSSImportRule.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/css/CSSMediaRule.h"
#include "core/css/CSSPropertyValueSet.h"
#include "core/css/CSSRuleList.h"
#include "core/css/CSSSelector.h"
#include "core/css/CSSStyleRule.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/CSSSupportsRule.h"
#include "core/css/StyleEngine.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/StyleResolverStats.h"
#include "core/css/resolver/StyleRuleUsageTracker.h"
#include "core/dom/ShadowRoot.h"
#include "core/style/ComputedStyle.h"

namespace blink {

ElementRuleCollector::ElementRuleCollector(const ElementResolveContext& context,
                                           const SelectorFilter& filter,
                                           ComputedStyle* style)
    : context_(context),
      selector_filter_(filter),
      style_(style),
      pseudo_style_request_(kPseudoIdNone),
      mode_(SelectorChecker::kResolvingStyle),
      can_use_fast_reject_(
          selector_filter_.ParentStackIsConsistent(context.ParentNode())),
      same_origin_only_(false),
      matching_ua_rules_(false),
      include_empty_rules_(false) {}

ElementRuleCollector::~ElementRuleCollector() = default;

const MatchResult& ElementRuleCollector::MatchedResult() const {
  return result_;
}

StyleRuleList* ElementRuleCollector::MatchedStyleRuleList() {
  DCHECK_EQ(mode_, SelectorChecker::kCollectingStyleRules);
  return style_rule_list_.Release();
}

CSSRuleList* ElementRuleCollector::MatchedCSSRuleList() {
  DCHECK_EQ(mode_, SelectorChecker::kCollectingCSSRules);
  return css_rule_list_.Release();
}

void ElementRuleCollector::ClearMatchedRules() {
  matched_rules_.clear();
}

inline StyleRuleList* ElementRuleCollector::EnsureStyleRuleList() {
  if (!style_rule_list_)
    style_rule_list_ = new StyleRuleList();
  return style_rule_list_;
}

inline StaticCSSRuleList* ElementRuleCollector::EnsureRuleList() {
  if (!css_rule_list_)
    css_rule_list_ = StaticCSSRuleList::Create();
  return css_rule_list_.Get();
}

void ElementRuleCollector::AddElementStyleProperties(
    const CSSPropertyValueSet* property_set,
    bool is_cacheable) {
  if (!property_set)
    return;
  result_.AddMatchedProperties(property_set);
  if (!is_cacheable)
    result_.SetIsCacheable(false);
}

static bool RulesApplicableInCurrentTreeScope(
    const Element* element,
    const ContainerNode* scoping_node) {
  // Check if the rules come from a shadow style sheet in the same tree scope.
  return !scoping_node ||
         element->ContainingTreeScope() == scoping_node->ContainingTreeScope();
}

template <typename RuleDataListType>
void ElementRuleCollector::CollectMatchingRulesForList(
    const RuleDataListType* rules,
    CascadeOrder cascade_order,
    const MatchRequest& match_request) {
  if (!rules)
    return;

  SelectorChecker::Init init;
  init.mode = mode_;
  init.is_ua_rule = matching_ua_rules_;
  init.element_style = style_.get();
  init.scrollbar = pseudo_style_request_.scrollbar;
  init.scrollbar_part = pseudo_style_request_.scrollbar_part;
  SelectorChecker checker(init);
  SelectorChecker::SelectorCheckingContext context(
      context_.GetElement(), SelectorChecker::kVisitedMatchEnabled);
  context.scope = match_request.scope;
  context.pseudo_id = pseudo_style_request_.pseudo_id;

  unsigned rejected = 0;
  unsigned fast_rejected = 0;
  unsigned matched = 0;

  for (const auto& rule_data : *rules) {
    if (can_use_fast_reject_ &&
        selector_filter_.FastRejectSelector<RuleData::kMaximumIdentifierCount>(
            rule_data.DescendantSelectorIdentifierHashes())) {
      fast_rejected++;
      continue;
    }

    // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the
    // only reason this is needed.
    if (same_origin_only_ && !rule_data.HasDocumentSecurityOrigin())
      continue;

    StyleRule* rule = rule_data.Rule();

    // If the rule has no properties to apply, then ignore it in the non-debug
    // mode.
    if (!rule->ShouldConsiderForMatchingRules(include_empty_rules_))
      continue;

    SelectorChecker::MatchResult result;
    context.selector = &rule_data.Selector();
    if (!checker.Match(context, result)) {
      rejected++;
      continue;
    }
    if (pseudo_style_request_.pseudo_id != kPseudoIdNone &&
        pseudo_style_request_.pseudo_id != result.dynamic_pseudo) {
      rejected++;
      continue;
    }

    matched++;
    DidMatchRule(rule_data, result, cascade_order, match_request);
  }

  StyleEngine& style_engine =
      context_.GetElement()->GetDocument().GetStyleEngine();
  if (!style_engine.Stats())
    return;

  INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_rejected, rejected);
  INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_fast_rejected,
                                fast_rejected);
  INCREMENT_STYLE_STATS_COUNTER(style_engine, rules_matched, matched);
}

DISABLE_CFI_PERF
void ElementRuleCollector::CollectMatchingRules(
    const MatchRequest& match_request,
    CascadeOrder cascade_order,
    bool matching_tree_boundary_rules) {
  DCHECK(match_request.rule_set);
  DCHECK(context_.GetElement());

  Element& element = *context_.GetElement();
  const AtomicString& pseudo_id = element.ShadowPseudoId();
  if (!pseudo_id.IsEmpty()) {
    DCHECK(element.IsStyledElement());
    CollectMatchingRulesForList(
        match_request.rule_set->ShadowPseudoElementRules(pseudo_id),
        cascade_order, match_request);
  }

  if (element.IsVTTElement())
    CollectMatchingRulesForList(match_request.rule_set->CuePseudoRules(),
                                cascade_order, match_request);
  // Check whether other types of rules are applicable in the current tree
  // scope. Criteria for this:
  // a) the rules are UA rules.
  // b) matching tree boundary crossing rules.
  // c) the rules come from a shadow style sheet in the same tree scope as the
  //    given element.
  // c) is checked in rulesApplicableInCurrentTreeScope.
  if (!matching_ua_rules_ && !matching_tree_boundary_rules &&
      !RulesApplicableInCurrentTreeScope(&element, match_request.scope))
    return;

  // We need to collect the rules for id, class, tag, and everything else into a
  // buffer and then sort the buffer.
  if (element.HasID())
    CollectMatchingRulesForList(
        match_request.rule_set->IdRules(element.IdForStyleResolution()),
        cascade_order, match_request);
  if (element.IsStyledElement() && element.HasClass()) {
    for (size_t i = 0; i < element.ClassNames().size(); ++i)
      CollectMatchingRulesForList(
          match_request.rule_set->ClassRules(element.ClassNames()[i]),
          cascade_order, match_request);
  }

  if (element.IsLink())
    CollectMatchingRulesForList(match_request.rule_set->LinkPseudoClassRules(),
                                cascade_order, match_request);
  if (SelectorChecker::MatchesFocusPseudoClass(element))
    CollectMatchingRulesForList(match_request.rule_set->FocusPseudoClassRules(),
                                cascade_order, match_request);
  CollectMatchingRulesForList(
      match_request.rule_set->TagRules(element.LocalNameForSelectorMatching()),
      cascade_order, match_request);
  CollectMatchingRulesForList(match_request.rule_set->UniversalRules(),
                              cascade_order, match_request);
}

void ElementRuleCollector::CollectMatchingShadowHostRules(
    const MatchRequest& match_request,
    CascadeOrder cascade_order) {
  CollectMatchingRulesForList(match_request.rule_set->ShadowHostRules(),
                              cascade_order, match_request);
}

void ElementRuleCollector::CollectMatchingPartPseudoRules(
    const MatchRequest& match_request,
    CascadeOrder cascade_order) {
  if (!RuntimeEnabledFeatures::CSSPartPseudoElementEnabled())
    return;
  CollectMatchingRulesForList(match_request.rule_set->PartPseudoRules(),
                              cascade_order, match_request);
}

template <class CSSRuleCollection>
CSSRule* ElementRuleCollector::FindStyleRule(CSSRuleCollection* css_rules,
                                             StyleRule* style_rule) {
  if (!css_rules)
    return nullptr;
  CSSRule* result = nullptr;
  for (unsigned i = 0; i < css_rules->length() && !result; ++i) {
    CSSRule* css_rule = css_rules->item(i);
    CSSRule::Type css_rule_type = css_rule->type();
    if (css_rule_type == CSSRule::kStyleRule) {
      CSSStyleRule* css_style_rule = ToCSSStyleRule(css_rule);
      if (css_style_rule->GetStyleRule() == style_rule)
        result = css_rule;
    } else if (css_rule_type == CSSRule::kImportRule) {
      CSSImportRule* css_import_rule = ToCSSImportRule(css_rule);
      result = FindStyleRule(css_import_rule->styleSheet(), style_rule);
    } else {
      result = FindStyleRule(css_rule->cssRules(), style_rule);
    }
  }
  return result;
}

void ElementRuleCollector::AppendCSSOMWrapperForRule(
    CSSStyleSheet* parent_style_sheet,
    StyleRule* rule) {
  // |parentStyleSheet| is 0 if and only if the |rule| is coming from User
  // Agent. In this case, it is safe to create CSSOM wrappers without
  // parentStyleSheets as they will be used only by inspector which will not try
  // to edit them.
  CSSRule* css_rule = nullptr;
  if (parent_style_sheet)
    css_rule = FindStyleRule(parent_style_sheet, rule);
  else
    css_rule = rule->CreateCSSOMWrapper();
  DCHECK(!parent_style_sheet || css_rule);
  EnsureRuleList()->Rules().push_back(css_rule);
}

void ElementRuleCollector::SortAndTransferMatchedRules() {
  if (matched_rules_.IsEmpty())
    return;

  SortMatchedRules();

  if (mode_ == SelectorChecker::kCollectingStyleRules) {
    for (unsigned i = 0; i < matched_rules_.size(); ++i)
      EnsureStyleRuleList()->push_back(matched_rules_[i].GetRuleData()->Rule());
    return;
  }

  if (mode_ == SelectorChecker::kCollectingCSSRules) {
    for (unsigned i = 0; i < matched_rules_.size(); ++i)
      AppendCSSOMWrapperForRule(
          const_cast<CSSStyleSheet*>(matched_rules_[i].ParentStyleSheet()),
          matched_rules_[i].GetRuleData()->Rule());
    return;
  }

  // Now transfer the set of matched rules over to our list of declarations.
  for (unsigned i = 0; i < matched_rules_.size(); i++) {
    const RuleData* rule_data = matched_rules_[i].GetRuleData();
    result_.AddMatchedProperties(
        &rule_data->Rule()->Properties(), rule_data->LinkMatchType(),
        rule_data->PropertyWhitelist(matching_ua_rules_));
  }
}

void ElementRuleCollector::DidMatchRule(
    const RuleData& rule_data,
    const SelectorChecker::MatchResult& result,
    CascadeOrder cascade_order,
    const MatchRequest& match_request) {
  PseudoId dynamic_pseudo = result.dynamic_pseudo;
  // If we're matching normal rules, set a pseudo bit if we really just matched
  // a pseudo-element.
  if (dynamic_pseudo != kPseudoIdNone &&
      pseudo_style_request_.pseudo_id == kPseudoIdNone) {
    if (mode_ == SelectorChecker::kCollectingCSSRules ||
        mode_ == SelectorChecker::kCollectingStyleRules)
      return;
    // FIXME: Matching should not modify the style directly.
    if (!style_ || dynamic_pseudo >= kFirstInternalPseudoId)
      return;
    if ((dynamic_pseudo == kPseudoIdBefore ||
         dynamic_pseudo == kPseudoIdAfter) &&
        !rule_data.Rule()->Properties().HasProperty(CSSPropertyContent))
      return;
    style_->SetHasPseudoStyle(dynamic_pseudo);
  } else {
    matched_rules_.push_back(MatchedRule(
        &rule_data, result.specificity, cascade_order,
        match_request.style_sheet_index, match_request.style_sheet));
  }
}

static inline bool CompareRules(const MatchedRule& matched_rule1,
                                const MatchedRule& matched_rule2) {
  unsigned specificity1 = matched_rule1.Specificity();
  unsigned specificity2 = matched_rule2.Specificity();
  if (specificity1 != specificity2)
    return specificity1 < specificity2;

  return matched_rule1.GetPosition() < matched_rule2.GetPosition();
}

void ElementRuleCollector::SortMatchedRules() {
  std::sort(matched_rules_.begin(), matched_rules_.end(), CompareRules);
}

void ElementRuleCollector::AddMatchedRulesToTracker(
    StyleRuleUsageTracker* tracker) const {
  for (auto matched_rule : matched_rules_) {
    tracker->Track(matched_rule.ParentStyleSheet(),
                   matched_rule.GetRuleData()->Rule());
  }
}

}  // namespace blink
