Commit 4e41dd51 authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

[cascade] Provide HashTraits for CSSPropertyName.

This is needed for the Cascade Project, which will use CSSPropertyName
as the HashMap key.

HashTraits requires the key object to support "empty" and "deleted"
values. This is implemented by storing kEmptyValue and kDeletedValue
in an integer which is shared with the CSSPropertyID.

Constructing empty or deleted CSSPropertyNames is not advisable outside of
HashTraits, hence the relevant constructor is exposed via friendship.
(Inspired by PropertyHandle).

BUG=947004
R=futhark@chromium.org

Change-Id: I48bfb3707f73f0cadd7696075fce622352f9dee0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1553555Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649069}
parent e1e8c390
......@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
namespace blink {
......@@ -22,9 +23,9 @@ static_assert(sizeof(CSSPropertyName) == sizeof(SameSizeAsCSSPropertyName),
} // namespace
bool CSSPropertyName::operator==(const CSSPropertyName& other) const {
if (property_id_ != other.property_id_)
if (value_ != other.value_)
return false;
if (property_id_ != CSSPropertyID::kVariable)
if (value_ != static_cast<int>(CSSPropertyID::kVariable))
return true;
return custom_property_name_ == other.custom_property_name_;
}
......@@ -32,7 +33,13 @@ bool CSSPropertyName::operator==(const CSSPropertyName& other) const {
AtomicString CSSPropertyName::ToAtomicString() const {
if (IsCustomProperty())
return custom_property_name_;
return CSSProperty::Get(property_id_).GetPropertyNameAtomicString();
return CSSProperty::Get(Id()).GetPropertyNameAtomicString();
}
unsigned CSSPropertyName::GetHash() const {
if (IsCustomProperty())
return AtomicStringHash::GetHash(custom_property_name_);
return value_;
}
} // namespace blink
......@@ -16,16 +16,15 @@ namespace blink {
// including custom properties.
class CORE_EXPORT CSSPropertyName {
DISALLOW_NEW();
public:
explicit CSSPropertyName(CSSPropertyID property_id)
: property_id_(property_id) {
DCHECK_NE(property_id, CSSPropertyID::kInvalid);
DCHECK_NE(property_id, CSSPropertyID::kVariable);
: value_(static_cast<int>(property_id)) {
DCHECK_NE(Id(), CSSPropertyID::kInvalid);
DCHECK_NE(Id(), CSSPropertyID::kVariable);
}
explicit CSSPropertyName(const AtomicString& custom_property_name)
: property_id_(CSSPropertyID::kVariable),
: value_(static_cast<int>(CSSPropertyID::kVariable)),
custom_property_name_(custom_property_name) {
DCHECK(!custom_property_name.IsNull());
}
......@@ -44,21 +43,79 @@ class CORE_EXPORT CSSPropertyName {
return !(*this == other);
}
CSSPropertyID Id() const { return property_id_; }
bool IsCustomProperty() const {
return property_id_ == CSSPropertyID::kVariable;
CSSPropertyID Id() const {
DCHECK(!IsEmptyValue() && !IsDeletedValue());
return static_cast<CSSPropertyID>(value_);
}
bool IsCustomProperty() const { return Id() == CSSPropertyID::kVariable; }
AtomicString ToAtomicString() const;
private:
CSSPropertyID property_id_;
// For HashTraits::EmptyValue().
static constexpr int kEmptyValue = -1;
// For HashTraits::ConstructDeletedValue(...).
static constexpr int kDeletedValue = -2;
explicit CSSPropertyName(int value) : value_(value) {
DCHECK(value == kEmptyValue || value == kDeletedValue);
}
unsigned GetHash() const;
bool IsEmptyValue() const { return value_ == kEmptyValue; }
bool IsDeletedValue() const { return value_ == kDeletedValue; }
// The value_ field is either a CSSPropertyID, kEmptyValue, or
// kDeletedValue.
int value_;
AtomicString custom_property_name_;
friend class CSSPropertyNameTest;
friend struct ::WTF::DefaultHash<blink::CSSPropertyName>;
friend struct ::WTF::HashTraits<blink::CSSPropertyName>;
};
} // namespace blink
namespace WTF {
template <>
struct DefaultHash<blink::CSSPropertyName> {
struct Hash {
STATIC_ONLY(Hash);
static unsigned GetHash(const blink::CSSPropertyName& name) {
return name.GetHash();
}
static bool Equal(const blink::CSSPropertyName& a,
const blink::CSSPropertyName& b) {
return a == b;
}
static const bool safe_to_compare_to_empty_or_deleted = true;
};
};
template <>
struct HashTraits<blink::CSSPropertyName>
: SimpleClassHashTraits<blink::CSSPropertyName> {
using CSSPropertyName = blink::CSSPropertyName;
static const bool kEmptyValueIsZero = false;
static const bool kNeedsDestruction = true;
static void ConstructDeletedValue(CSSPropertyName& slot, bool) {
new (NotNull, &slot) CSSPropertyName(CSSPropertyName::kDeletedValue);
}
static bool IsDeletedValue(CSSPropertyName value) {
return value.IsDeletedValue();
}
static blink::CSSPropertyName EmptyValue() {
return blink::CSSPropertyName(CSSPropertyName::kEmptyValue);
}
};
} // namespace WTF
WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::CSSPropertyName)
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PROPERTY_NAME_H_
......@@ -5,31 +5,53 @@
#include "third_party/blink/renderer/core/css/css_property_name.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
TEST(CSSPropertyNameTest, IdStandardProperty) {
class CSSPropertyNameTest : public testing::Test {
public:
CSSPropertyName Empty() const {
return CSSPropertyName(CSSPropertyName::kEmptyValue);
}
CSSPropertyName Deleted() const {
return CSSPropertyName(CSSPropertyName::kDeletedValue);
}
bool IsDeleted(const CSSPropertyName& name) const {
return name.IsDeletedValue();
}
bool IsEmpty(const CSSPropertyName& name) const {
return name.IsEmptyValue();
}
unsigned GetHash(const CSSPropertyName& name) const { return name.GetHash(); }
};
TEST_F(CSSPropertyNameTest, IdStandardProperty) {
CSSPropertyName name(CSSPropertyID::kFontSize);
EXPECT_EQ(CSSPropertyID::kFontSize, name.Id());
}
TEST(CSSPropertyNameTest, IdCustomProperty) {
TEST_F(CSSPropertyNameTest, IdCustomProperty) {
CSSPropertyName name(AtomicString("--x"));
EXPECT_EQ(CSSPropertyID::kVariable, name.Id());
EXPECT_TRUE(name.IsCustomProperty());
}
TEST(CSSPropertyNameTest, GetNameStandardProperty) {
TEST_F(CSSPropertyNameTest, GetNameStandardProperty) {
CSSPropertyName name(CSSPropertyID::kFontSize);
EXPECT_EQ(AtomicString("font-size"), name.ToAtomicString());
}
TEST(CSSPropertyNameTest, GetNameCustomProperty) {
TEST_F(CSSPropertyNameTest, GetNameCustomProperty) {
CSSPropertyName name(AtomicString("--x"));
EXPECT_EQ(AtomicString("--x"), name.ToAtomicString());
}
TEST(CSSPropertyNameTest, OperatorEquals) {
TEST_F(CSSPropertyNameTest, OperatorEquals) {
EXPECT_EQ(CSSPropertyName("--x"), CSSPropertyName("--x"));
EXPECT_EQ(CSSPropertyName(CSSPropertyID::kColor),
CSSPropertyName(CSSPropertyID::kColor));
......@@ -38,7 +60,7 @@ TEST(CSSPropertyNameTest, OperatorEquals) {
CSSPropertyName(CSSPropertyID::kBackgroundColor));
}
TEST(CSSPropertyNameTest, From) {
TEST_F(CSSPropertyNameTest, From) {
EXPECT_TRUE(CSSPropertyName::From("color"));
EXPECT_TRUE(CSSPropertyName::From("--x"));
EXPECT_FALSE(CSSPropertyName::From("notaproperty"));
......@@ -49,9 +71,82 @@ TEST(CSSPropertyNameTest, From) {
EXPECT_EQ(*CSSPropertyName::From("--x"), CSSPropertyName("--x"));
}
TEST(CSSPropertyNameTest, FromNativeCSSProperty) {
TEST_F(CSSPropertyNameTest, FromNativeCSSProperty) {
CSSPropertyName name = GetCSSPropertyFontSize().GetCSSPropertyName();
EXPECT_EQ(CSSPropertyName(CSSPropertyID::kFontSize), name);
}
TEST_F(CSSPropertyNameTest, IsEmptyValue) {
CSSPropertyName empty = Empty();
CSSPropertyName deleted = Deleted();
CSSPropertyName normal = GetCSSPropertyFontSize().GetCSSPropertyName();
CSSPropertyName custom("--x");
EXPECT_TRUE(IsEmpty(empty));
EXPECT_FALSE(IsEmpty(deleted));
EXPECT_FALSE(IsEmpty(normal));
EXPECT_FALSE(IsEmpty(custom));
}
TEST_F(CSSPropertyNameTest, IsDeletedValue) {
CSSPropertyName empty = Empty();
CSSPropertyName deleted = Deleted();
CSSPropertyName normal = GetCSSPropertyFontSize().GetCSSPropertyName();
CSSPropertyName custom("--x");
EXPECT_FALSE(IsDeleted(empty));
EXPECT_TRUE(IsDeleted(deleted));
EXPECT_FALSE(IsDeleted(normal));
EXPECT_FALSE(IsDeleted(custom));
}
TEST_F(CSSPropertyNameTest, GetHash) {
CSSPropertyName normal = GetCSSPropertyFontSize().GetCSSPropertyName();
CSSPropertyName custom("--x");
// Don't crash.
GetHash(normal);
GetHash(custom);
}
TEST_F(CSSPropertyNameTest, CompareEmptyDeleted) {
CSSPropertyName normal = GetCSSPropertyFontSize().GetCSSPropertyName();
CSSPropertyName custom("--x");
EXPECT_EQ(Empty(), Empty());
EXPECT_EQ(Deleted(), Deleted());
EXPECT_NE(Empty(), Deleted());
EXPECT_NE(Deleted(), Empty());
EXPECT_NE(Empty(), normal);
EXPECT_NE(Empty(), custom);
EXPECT_NE(Deleted(), normal);
EXPECT_NE(Deleted(), custom);
EXPECT_NE(normal, Empty());
EXPECT_NE(custom, Empty());
EXPECT_NE(normal, Deleted());
EXPECT_NE(custom, Deleted());
}
TEST_F(CSSPropertyNameTest, HashMapBasic) {
HashMap<CSSPropertyName, AtomicString> map;
map.Set(CSSPropertyName("--x"), "foo");
map.Set(CSSPropertyName("--y"), "foo");
map.Set(CSSPropertyName("--z"), "foo");
map.Set(CSSPropertyName("--x"), "bar");
map.erase(CSSPropertyName("--z"));
EXPECT_EQ("bar", map.Take(CSSPropertyName("--x")));
EXPECT_EQ("foo", map.Take(CSSPropertyName("--y")));
EXPECT_EQ(map.end(), map.find(CSSPropertyName("--z")));
map.Set(GetCSSPropertyFontSize().GetCSSPropertyName(), "foo");
map.Set(GetCSSPropertyFontSize().GetCSSPropertyName(), "bar");
EXPECT_EQ("bar", map.Take(GetCSSPropertyFontSize().GetCSSPropertyName()));
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment