Fix readonly and type attribute selector incorrect style sharing

RuleSet has a special case in isCommonAttributeSelectorAttribute for
allowing style sharing on elements that match "type" or "readonly"
attribute selectors as long as they have the same value. This was
added long ago in r96393 and worked based on the assumption that
there was logic in canShareStyleWithElement that actually checked
the value of the type and readonly attributes on the style sharing
candidates.

Later in r123730 the type attribute handling was regressed when it
was moved to only check the value for <input>. The readonly attribute
was later regressed in the same way in r134984.

This patch restores the checks those two patches moved but retains the
switch from getAttribute to fastGetAttribute for HTML which was likely
most of the performance improvement and fixes the bug where elements
would incorrectly share style even if one of them matched an attribute
selector.

Unfortunately this does mean that we need to call the slow geAttribute
in SVG documents which may be a minor regression. We can work to
improve the performance of SVG in the future once we get the
correctness back.

BUG=307170
R=leviw@chromium.org

Review URL: https://codereview.chromium.org/27033011

git-svn-id: svn://svn.chromium.org/blink/trunk@159699 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/fast/css/style-sharing-type-and-readonly-expected.txt b/LayoutTests/fast/css/style-sharing-type-and-readonly-expected.txt
new file mode 100644
index 0000000..b04370a
--- /dev/null
+++ b/LayoutTests/fast/css/style-sharing-type-and-readonly-expected.txt
@@ -0,0 +1,14 @@
+Make sure special case style sharing for readonly and type attributes works
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS getComputedStyle(document.querySelector("[black]")).color is "rgb(0, 0, 0)"
+PASS getComputedStyle(document.querySelector("[readonly]")).color is "rgb(255, 0, 0)"
+PASS getComputedStyle(document.querySelector("[type]")).color is "rgb(0, 0, 255)"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Black
+Red
+Blue
diff --git a/LayoutTests/fast/css/style-sharing-type-and-readonly.html b/LayoutTests/fast/css/style-sharing-type-and-readonly.html
new file mode 100644
index 0000000..3b95b0e
--- /dev/null
+++ b/LayoutTests/fast/css/style-sharing-type-and-readonly.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+
+<script src="../js/resources/js-test-pre.js"></script>
+
+<style>
+  div[readonly="red"] {
+    color: red;
+  }
+  div[type="blue"] {
+    color: blue;
+  }
+</style>
+
+<div black>Black</div>
+<div readonly="red">Red</div>
+<div type="blue">Blue</div>
+
+<script>
+description("Make sure special case style sharing for readonly and type attributes works");
+
+shouldBe('getComputedStyle(document.querySelector("[black]")).color','"rgb(0, 0, 0)"');
+shouldBe('getComputedStyle(document.querySelector("[readonly]")).color','"rgb(255, 0, 0)"');
+shouldBe('getComputedStyle(document.querySelector("[type]")).color','"rgb(0, 0, 255)"');
+</script>
+
+<script src="../js/resources/js-test-post.js"></script>
\ No newline at end of file
diff --git a/Source/core/css/resolver/SharedStyleFinder.cpp b/Source/core/css/resolver/SharedStyleFinder.cpp
index 2a6dd7b..d76a433 100644
--- a/Source/core/css/resolver/SharedStyleFinder.cpp
+++ b/Source/core/css/resolver/SharedStyleFinder.cpp
@@ -68,12 +68,6 @@
 
     HTMLInputElement* thisInputElement = toHTMLInputElement(element);
     HTMLInputElement* otherInputElement = toHTMLInputElement(context.element());
-    if (thisInputElement->elementData() != otherInputElement->elementData()) {
-        if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->fastGetAttribute(typeAttr))
-            return false;
-        if (thisInputElement->fastGetAttribute(readonlyAttr) != otherInputElement->fastGetAttribute(readonlyAttr))
-            return false;
-    }
 
     if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled())
         return false;
@@ -124,6 +118,12 @@
     return element->isHTMLElement() && toHTMLElement(element)->hasDirectionAuto();
 }
 
+static inline const AtomicString& typeAttributeValue(const Element* element)
+{
+    // type is animatable in SVG so we need to go down the slow path here.
+    return element->isSVGElement() ? element->getAttribute(typeAttr) : element->fastGetAttribute(typeAttr);
+}
+
 bool SharedStyleFinder::sharingCandidateHasIdenticalStyleAffectingAttributes(const ElementResolveContext& context, Element* sharingCandidate) const
 {
     if (context.element()->elementData() == sharingCandidate->elementData())
@@ -133,6 +133,13 @@
     if (context.element()->fastGetAttribute(langAttr) != sharingCandidate->fastGetAttribute(langAttr))
         return false;
 
+    // These two checks must be here since RuleSet has a specail case to allow style sharing between elements
+    // with type and readonly attributes whereas other attribute selectors prevent sharing.
+    if (typeAttributeValue(context.element()) != typeAttributeValue(sharingCandidate))
+        return false;
+    if (context.element()->fastGetAttribute(readonlyAttr) != sharingCandidate->fastGetAttribute(readonlyAttr))
+        return false;
+
     if (!m_elementAffectedByClassRules) {
         if (sharingCandidate->hasClass() && classNamesAffectedByRules(sharingCandidate->classNames()))
             return false;