/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
 * All rights reserved.
 * Copyright (C) 2012 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#include "core/css/resolver/ScopedStyleResolver.h"

#include "core/HTMLNames.h"
#include "core/animation/DocumentTimeline.h"
#include "core/css/CSSFontSelector.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/FontFace.h"
#include "core/css/PageRuleCollector.h"
#include "core/css/RuleFeature.h"
#include "core/css/StyleRule.h"
#include "core/css/StyleSheetContents.h"
#include "core/css/resolver/MatchRequest.h"
#include "core/dom/Document.h"
#include "core/dom/StyleChangeReason.h"
#include "core/dom/StyleEngine.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLStyleElement.h"
#include "core/svg/SVGStyleElement.h"

namespace blink {

ScopedStyleResolver* ScopedStyleResolver::parent() const {
  for (TreeScope* scope = treeScope().parentTreeScope(); scope;
       scope = scope->parentTreeScope()) {
    if (ScopedStyleResolver* resolver = scope->scopedStyleResolver())
      return resolver;
  }
  return nullptr;
}

void ScopedStyleResolver::addKeyframeRules(const RuleSet& ruleSet) {
  const HeapVector<Member<StyleRuleKeyframes>> keyframesRules =
      ruleSet.keyframesRules();
  for (unsigned i = 0; i < keyframesRules.size(); ++i)
    addKeyframeStyle(keyframesRules[i]);
}

void ScopedStyleResolver::addFontFaceRules(const RuleSet& ruleSet) {
  // FIXME(BUG 72461): We don't add @font-face rules of scoped style sheets for
  // the moment.
  if (!treeScope().rootNode().isDocumentNode())
    return;

  Document& document = treeScope().document();
  CSSFontSelector* cssFontSelector = document.styleEngine().fontSelector();
  const HeapVector<Member<StyleRuleFontFace>> fontFaceRules =
      ruleSet.fontFaceRules();
  for (auto& fontFaceRule : fontFaceRules) {
    if (FontFace* fontFace = FontFace::create(&document, fontFaceRule))
      cssFontSelector->fontFaceCache()->add(cssFontSelector, fontFaceRule,
                                            fontFace);
  }
  if (fontFaceRules.size())
    document.styleResolver()->invalidateMatchedPropertiesCache();
}

void ScopedStyleResolver::appendCSSStyleSheet(CSSStyleSheet& cssSheet) {
  RuleSet* ruleSet =
      treeScope().document().styleEngine().ruleSetForSheet(cssSheet);

  m_viewportDependentMediaQueryResults.appendVector(
      cssSheet.viewportDependentMediaQueryResults());
  m_deviceDependentMediaQueryResults.appendVector(
      cssSheet.deviceDependentMediaQueryResults());
  if (!ruleSet)
    return;

  unsigned index = m_authorStyleSheets.size();
  m_authorStyleSheets.append(&cssSheet);
  addKeyframeRules(*ruleSet);
  addFontFaceRules(*ruleSet);
  addTreeBoundaryCrossingRules(*ruleSet, &cssSheet, index);
}

void ScopedStyleResolver::appendActiveStyleSheets(
    unsigned index,
    const ActiveStyleSheetVector& activeSheets) {
  for (auto activeIterator = activeSheets.begin() + index;
       activeIterator != activeSheets.end(); activeIterator++) {
    CSSStyleSheet* sheet = activeIterator->first;
    m_viewportDependentMediaQueryResults.appendVector(
        sheet->viewportDependentMediaQueryResults());
    m_deviceDependentMediaQueryResults.appendVector(
        sheet->deviceDependentMediaQueryResults());
    if (!activeIterator->second)
      continue;
    const RuleSet& ruleSet = *activeIterator->second;
    m_authorStyleSheets.append(sheet);
    addKeyframeRules(ruleSet);
    addFontFaceRules(ruleSet);
    addTreeBoundaryCrossingRules(ruleSet, sheet, index++);
  }
}

void ScopedStyleResolver::collectFeaturesTo(
    RuleFeatureSet& features,
    HeapHashSet<Member<const StyleSheetContents>>&
        visitedSharedStyleSheetContents) const {
  features.viewportDependentMediaQueryResults().appendVector(
      m_viewportDependentMediaQueryResults);
  features.deviceDependentMediaQueryResults().appendVector(
      m_deviceDependentMediaQueryResults);

  for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
    ASSERT(m_authorStyleSheets[i]->ownerNode());
    StyleSheetContents* contents = m_authorStyleSheets[i]->contents();
    if (contents->hasOneClient() ||
        visitedSharedStyleSheetContents.add(contents).isNewEntry)
      features.add(contents->ruleSet().features());
  }

  if (!m_treeBoundaryCrossingRuleSet)
    return;

  for (const auto& rules : *m_treeBoundaryCrossingRuleSet)
    features.add(rules->m_ruleSet->features());
}

void ScopedStyleResolver::resetAuthorStyle() {
  m_authorStyleSheets.clear();
  m_viewportDependentMediaQueryResults.clear();
  m_deviceDependentMediaQueryResults.clear();
  m_keyframesRuleMap.clear();
  m_treeBoundaryCrossingRuleSet = nullptr;
  m_hasDeepOrShadowSelector = false;
  m_needsAppendAllSheets = false;
}

StyleRuleKeyframes* ScopedStyleResolver::keyframeStylesForAnimation(
    const StringImpl* animationName) {
  if (m_keyframesRuleMap.isEmpty())
    return nullptr;

  KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(animationName);
  if (it == m_keyframesRuleMap.end())
    return nullptr;

  return it->value.get();
}

void ScopedStyleResolver::addKeyframeStyle(StyleRuleKeyframes* rule) {
  AtomicString s(rule->name());

  if (rule->isVendorPrefixed()) {
    KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(s.impl());
    if (it == m_keyframesRuleMap.end())
      m_keyframesRuleMap.set(s.impl(), rule);
    else if (it->value->isVendorPrefixed())
      m_keyframesRuleMap.set(s.impl(), rule);
  } else {
    m_keyframesRuleMap.set(s.impl(), rule);
  }
}

ContainerNode& ScopedStyleResolver::invalidationRootForTreeScope(
    const TreeScope& treeScope) {
  if (treeScope.rootNode() == treeScope.document())
    return treeScope.document();
  return toShadowRoot(treeScope.rootNode()).host();
}

void ScopedStyleResolver::keyframesRulesAdded(const TreeScope& treeScope) {
  // Called when @keyframes rules are about to be added/removed from a
  // TreeScope. @keyframes rules may apply to animations on elements in the
  // same TreeScope as the stylesheet, or the host element in the parent
  // TreeScope if the TreeScope is a shadow tree.

  ScopedStyleResolver* resolver = treeScope.scopedStyleResolver();
  ScopedStyleResolver* parentResolver =
      treeScope.parentTreeScope()
          ? treeScope.parentTreeScope()->scopedStyleResolver()
          : nullptr;

  bool hadUnresolvedKeyframes = false;
  if (resolver && resolver->m_hasUnresolvedKeyframesRule) {
    resolver->m_hasUnresolvedKeyframesRule = false;
    hadUnresolvedKeyframes = true;
  }
  if (parentResolver && parentResolver->m_hasUnresolvedKeyframesRule) {
    parentResolver->m_hasUnresolvedKeyframesRule = false;
    hadUnresolvedKeyframes = true;
  }

  if (hadUnresolvedKeyframes) {
    // If an animation ended up not being started because no @keyframes
    // rules were found for the animation-name, we need to recalculate style
    // for the elements in the scope, including its shadow host if
    // applicable.
    invalidationRootForTreeScope(treeScope).setNeedsStyleRecalc(
        SubtreeStyleChange, StyleChangeReasonForTracing::create(
                                StyleChangeReason::StyleSheetChange));
    return;
  }

  // If we have animations running, added/removed @keyframes may affect these.
  treeScope.document().timeline().invalidateKeyframeEffects(treeScope);
}

void ScopedStyleResolver::collectMatchingAuthorRules(
    ElementRuleCollector& collector,
    CascadeOrder cascadeOrder) {
  for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
    ASSERT(m_authorStyleSheets[i]->ownerNode());
    MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(),
                              &m_scope->rootNode(), m_authorStyleSheets[i], i);
    collector.collectMatchingRules(matchRequest, cascadeOrder);
  }
}

void ScopedStyleResolver::collectMatchingShadowHostRules(
    ElementRuleCollector& collector,
    CascadeOrder cascadeOrder) {
  for (size_t i = 0; i < m_authorStyleSheets.size(); ++i) {
    ASSERT(m_authorStyleSheets[i]->ownerNode());
    MatchRequest matchRequest(&m_authorStyleSheets[i]->contents()->ruleSet(),
                              &m_scope->rootNode(), m_authorStyleSheets[i], i);
    collector.collectMatchingShadowHostRules(matchRequest, cascadeOrder);
  }
}

void ScopedStyleResolver::collectMatchingTreeBoundaryCrossingRules(
    ElementRuleCollector& collector,
    CascadeOrder cascadeOrder) {
  if (!m_treeBoundaryCrossingRuleSet)
    return;

  for (const auto& rules : *m_treeBoundaryCrossingRuleSet) {
    MatchRequest request(rules->m_ruleSet.get(), &treeScope().rootNode(),
                         rules->m_parentStyleSheet, rules->m_parentIndex);
    collector.collectMatchingRules(request, cascadeOrder, true);
  }
}

void ScopedStyleResolver::matchPageRules(PageRuleCollector& collector) {
  // Only consider the global author RuleSet for @page rules, as per the HTML5
  // spec.
  ASSERT(m_scope->rootNode().isDocumentNode());
  for (size_t i = 0; i < m_authorStyleSheets.size(); ++i)
    collector.matchPageRules(&m_authorStyleSheets[i]->contents()->ruleSet());
}

DEFINE_TRACE(ScopedStyleResolver) {
  visitor->trace(m_scope);
  visitor->trace(m_authorStyleSheets);
  visitor->trace(m_viewportDependentMediaQueryResults);
  visitor->trace(m_deviceDependentMediaQueryResults);
  visitor->trace(m_keyframesRuleMap);
  visitor->trace(m_treeBoundaryCrossingRuleSet);
}

static void addRules(RuleSet* ruleSet,
                     const HeapVector<MinimalRuleData>& rules) {
  for (unsigned i = 0; i < rules.size(); ++i) {
    const MinimalRuleData& info = rules[i];
    ruleSet->addRule(info.m_rule, info.m_selectorIndex, info.m_flags);
  }
}

void ScopedStyleResolver::addTreeBoundaryCrossingRules(
    const RuleSet& authorRules,
    CSSStyleSheet* parentStyleSheet,
    unsigned sheetIndex) {
  bool isDocumentScope = treeScope().rootNode().isDocumentNode();
  if (authorRules.deepCombinatorOrShadowPseudoRules().isEmpty() &&
      (isDocumentScope || (authorRules.contentPseudoElementRules().isEmpty() &&
                           authorRules.slottedPseudoElementRules().isEmpty())))
    return;

  if (!authorRules.deepCombinatorOrShadowPseudoRules().isEmpty())
    m_hasDeepOrShadowSelector = true;

  RuleSet* ruleSetForScope = RuleSet::create();
  addRules(ruleSetForScope, authorRules.deepCombinatorOrShadowPseudoRules());

  if (!isDocumentScope) {
    addRules(ruleSetForScope, authorRules.contentPseudoElementRules());
    addRules(ruleSetForScope, authorRules.slottedPseudoElementRules());
  }

  if (!m_treeBoundaryCrossingRuleSet) {
    m_treeBoundaryCrossingRuleSet = new CSSStyleSheetRuleSubSet();
    treeScope().document().styleEngine().addTreeBoundaryCrossingScope(
        treeScope());
  }

  m_treeBoundaryCrossingRuleSet->append(
      RuleSubSet::create(parentStyleSheet, sheetIndex, ruleSetForScope));
}

DEFINE_TRACE(ScopedStyleResolver::RuleSubSet) {
  visitor->trace(m_parentStyleSheet);
  visitor->trace(m_ruleSet);
}

}  // namespace blink
