blob: bef63b8bf392e9f4a5f129ff575ee63369a3c274 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_FILTER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_FILTER_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
namespace blink {
// Reject properties with the given flags set or unset.
//
// For example, the following applies only inherited properties that don't apply
// to ::first-letter:
//
// CascadeFilter filter;
// filter = filter.Add(CSSProperty::kInherited, false);
// filter = filter.Add(CSSProperty::kValidForFirstLetter, true);
// filter.Reject(GetCSSPropertyColor()); // -> false
// filter.Reject(GetCSSPropertyDirection()); // -> true
// filter.Reject(GetCSSPropertyTop()); // -> true
//
class CORE_EXPORT CascadeFilter {
public:
// Empty filter. Rejects nothing.
CascadeFilter() = default;
// Creates a filter with a single rule.
//
// This is equivalent to:
//
// CascadeFilter filter;
// filter.Add(flag, v);
//
CascadeFilter(CSSProperty::Flag flag, bool v)
: mask_(flag), flags_(v ? flag : 0) {}
bool operator==(const CascadeFilter& o) const {
return mask_ == o.mask_ && flags_ == o.flags_;
}
bool operator!=(const CascadeFilter& o) const {
return mask_ != o.mask_ || flags_ != o.flags_;
}
// Add a given rule to the filter.
//
// A flag can be rejected when it's either set or unset. For example
//
// CascadeFilter f1(CSSProperty::kInherited, true); // Rejects inherited
// CascadeFilter f2(CSSProperty::kInherited, false); // Rejects non-inherited
//
// Note that it's not possible to reject both set and unset flags in the same
// filter. However, if you wish to reject all properties, you can do so by
// using the CSSProperty::kProperty flag.
//
// Add() will have no effect if there already is a rule for the given flag:
//
// CascadeFilter filter;
// CascadeFilter f1 = filter.Add(CSSProperty::kInherited, true);
// CascadeFilter f2 = f1.Add(CSSProperty::kInherited, false);
// bool equal = f1 == f2; // true. Second call to Add had to effect.
//
// If you want to overwrite a previous rule, use Set().
CascadeFilter Add(CSSProperty::Flag flag, bool v) const {
const CSSProperty::Flags mask = mask_ | flag;
const CSSProperty::Flags flags =
v ? (flags_ | (flag & ~mask_)) : (flags_ & ~(flag & ~mask_));
return CascadeFilter(mask, flags);
}
// Like Add, except overwrites a previous rule for the same flag.
CascadeFilter Set(CSSProperty::Flag flag, bool v) const {
const CSSProperty::Flags mask = mask_ | flag;
const CSSProperty::Flags flags = v ? (flags_ | flag) : (flags_ & ~flag);
return CascadeFilter(mask, flags);
}
bool Rejects(const CSSProperty& property) const {
return ~(property.GetFlags() ^ flags_) & mask_;
}
bool Rejects(CSSProperty::Flag flag, bool v) const {
return ~((v ? flag : 0) ^ flags_) & (mask_ & flag);
}
private:
CascadeFilter(CSSProperty::Flags mask, CSSProperty::Flags flags)
: mask_(mask), flags_(flags) {}
// Specifies which bits are significant in flags_. In other words, mask_
// contains a '1' at the corresponding position for each flag seen by
// Add().
CSSProperty::Flags mask_ = 0;
// Contains the flags to exclude. Only bits set in mask_ matter.
CSSProperty::Flags flags_ = 0;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_RESOLVER_CASCADE_FILTER_H_