Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "HTMLNames.h" | |
| 7 #include "core/dom/Element.h" | |
| 8 #include "core/dom/ElementTraversal.h" | |
| 9 #include "core/frame/FrameView.h" | |
| 10 #include "core/html/HTMLDocument.h" | |
| 11 #include "core/html/HTMLElement.h" | |
| 12 #include "core/testing/DummyPageHolder.h" | |
| 13 #include <gtest/gtest.h> | |
| 14 | |
| 15 using namespace WebCore; | |
| 16 using namespace HTMLNames; | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 class AffectedByFocusTest : public ::testing::Test { | |
|
eseidel
2014/01/31 06:25:19
Very cool that we're building up more unittest arc
| |
| 21 | |
| 22 protected: | |
| 23 | |
| 24 struct ElementResult { | |
| 25 const WebCore::QualifiedName tag; | |
| 26 bool affectedBy; | |
| 27 bool childrenAffectedBy; | |
| 28 }; | |
| 29 | |
| 30 virtual void SetUp() OVERRIDE; | |
| 31 | |
| 32 HTMLDocument& document() const { return *m_document; } | |
| 33 | |
| 34 void setHtmlInnerHTML(const char* htmlContent); | |
| 35 | |
| 36 void checkElements(ElementResult expected[], unsigned expectedCount) const; | |
| 37 | |
| 38 private: | |
| 39 OwnPtr<DummyPageHolder> m_dummyPageHolder; | |
| 40 | |
| 41 HTMLDocument* m_document; | |
| 42 }; | |
| 43 | |
| 44 void AffectedByFocusTest::SetUp() | |
| 45 { | |
| 46 m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); | |
| 47 m_document = toHTMLDocument(&m_dummyPageHolder->document()); | |
| 48 ASSERT(m_document); | |
| 49 } | |
| 50 | |
| 51 void AffectedByFocusTest::setHtmlInnerHTML(const char* htmlContent) | |
| 52 { | |
| 53 document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), AS SERT_NO_EXCEPTION); | |
| 54 document().view()->updateLayoutAndStyleIfNeededRecursive(); | |
| 55 } | |
| 56 | |
| 57 void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expec tedCount) const | |
| 58 { | |
| 59 unsigned i = 0; | |
| 60 Element* elm = document().body(); | |
| 61 | |
| 62 for (; elm && i < 5; elm = ElementTraversal::next(*elm), ++i) { | |
| 63 ASSERT_TRUE(elm->hasTagName(expected[i].tag)); | |
| 64 ASSERT(elm->renderStyle()); | |
| 65 ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus()) ; | |
| 66 ASSERT_EQ(expected[i].childrenAffectedBy, elm->childrenAffectedByFocus() ); | |
| 67 } | |
| 68 | |
| 69 ASSERT(!elm && i == size); | |
| 70 } | |
| 71 | |
| 72 // A global :focus rule in html.css currently causes every single element to be | |
|
eseidel
2014/01/31 06:25:19
We have a bug open with the w3c about this: https
| |
| 73 // affectedByFocus. Check that all elements in a document with no :focus rules | |
| 74 // gets the affectedByFocus set on RenderStyle and not childrenAffectedByFocus. | |
| 75 TEST_F(AffectedByFocusTest, UAUniversalFocusRule) | |
| 76 { | |
| 77 ElementResult expected[] = { | |
| 78 { bodyTag, true, false }, | |
| 79 { divTag, true, false }, | |
| 80 { divTag, true, false }, | |
| 81 { divTag, true, false }, | |
| 82 { spanTag, true, false } | |
| 83 }; | |
| 84 | |
| 85 setHtmlInnerHTML("<body>" | |
| 86 "<div><div></div></div>" | |
| 87 "<div><span></span></div>" | |
| 88 "</body>"); | |
| 89 | |
| 90 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | |
| 91 } | |
| 92 | |
| 93 // ":focus div" will mark ascendants of all divs with childrenAffectedByFocus. | |
| 94 TEST_F(AffectedByFocusTest, FocusedAscendant) | |
| 95 { | |
| 96 ElementResult expected[] = { | |
| 97 { bodyTag, true, true }, | |
| 98 { divTag, true, true }, | |
| 99 { divTag, true, false }, | |
| 100 { divTag, true, false }, | |
| 101 { spanTag, true, false } | |
| 102 }; | |
| 103 | |
| 104 setHtmlInnerHTML("<head>" | |
| 105 "<style>:focus div { background-color: pink }</style>" | |
| 106 "</head>" | |
| 107 "<body>" | |
| 108 "<div><div></div></div>" | |
| 109 "<div><span></span></div>" | |
| 110 "</body>"); | |
| 111 | |
| 112 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | |
| 113 } | |
| 114 | |
| 115 // "body:focus div" will mark the body element with childrenAffectedByFocus. | |
| 116 TEST_F(AffectedByFocusTest, FocusedAscendantWithType) | |
| 117 { | |
| 118 ElementResult expected[] = { | |
| 119 { bodyTag, true, true }, | |
| 120 { divTag, true, false }, | |
| 121 { divTag, true, false }, | |
| 122 { divTag, true, false }, | |
| 123 { spanTag, true, false } | |
| 124 }; | |
| 125 | |
| 126 setHtmlInnerHTML("<head>" | |
| 127 "<style>body:focus div { background-color: pink }</style>" | |
| 128 "</head>" | |
| 129 "<body>" | |
| 130 "<div><div></div></div>" | |
| 131 "<div><span></span></div>" | |
| 132 "</body>"); | |
| 133 | |
| 134 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | |
| 135 } | |
| 136 | |
| 137 // ":not(body):focus div" should not mark the body element with childrenAffected ByFocus. | |
| 138 // Note that currently ":focus:not(body)" does not do the same. Then the :focus is | |
| 139 // checked and the childrenAffectedByFocus flag set before the negated type sele ctor | |
| 140 // is found. | |
| 141 TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType) | |
| 142 { | |
| 143 ElementResult expected[] = { | |
| 144 { bodyTag, true, false }, | |
| 145 { divTag, true, true }, | |
| 146 { divTag, true, false }, | |
| 147 { divTag, true, false }, | |
| 148 { spanTag, true, false } | |
| 149 }; | |
| 150 | |
| 151 setHtmlInnerHTML("<head>" | |
| 152 "<style>:not(body):focus div { background-color: pink }</style>" | |
| 153 "</head>" | |
| 154 "<body>" | |
| 155 "<div><div></div></div>" | |
| 156 "<div><span></span></div>" | |
| 157 "</body>"); | |
| 158 | |
| 159 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | |
| 160 } | |
| 161 | |
| 162 // Checking current behavior for ":focus + div", but this is a BUG or at best | |
| 163 // sub-optimal. The focused element will also in this case get childrenAffectedB yFocus | |
| 164 // even if it's really a sibling. Effectively, the whole sub-tree of the focused | |
| 165 // element will have styles recalculated even though none of the children are | |
| 166 // affected. There are other mechanisms that makes sure the sibling also gets it s | |
| 167 // styles recalculated. | |
| 168 TEST_F(AffectedByFocusTest, FocusedSibling) | |
| 169 { | |
| 170 ElementResult expected[] = { | |
| 171 { bodyTag, true, false }, | |
| 172 { divTag, true, true }, | |
| 173 { spanTag, true, false }, | |
| 174 { divTag, true, false } | |
| 175 }; | |
| 176 | |
| 177 setHtmlInnerHTML("<head>" | |
| 178 "<style>:focus + div { background-color: pink }</style>" | |
| 179 "</head>" | |
| 180 "<body>" | |
| 181 "<div>" | |
| 182 " <span></span>" | |
| 183 "</div>" | |
| 184 "<div></div>" | |
| 185 "</body>"); | |
| 186 | |
| 187 checkElements(expected, sizeof(expected) / sizeof(ElementResult)); | |
| 188 } | |
| 189 | |
| 190 TEST_F(AffectedByFocusTest, AffectedByFocusUpdate) | |
| 191 { | |
| 192 // Check that when focussing the outer div in the document below, you only | |
| 193 // get a single element style recalc. | |
| 194 | |
| 195 setHtmlInnerHTML("<style>:focus { border: 1px solid lime; }</style>" | |
| 196 "<div id=d tabIndex=1>" | |
| 197 "<div></div>" | |
| 198 "<div></div>" | |
| 199 "<div></div>" | |
| 200 "<div></div>" | |
| 201 "<div></div>" | |
| 202 "<div></div>" | |
| 203 "<div></div>" | |
| 204 "<div></div>" | |
| 205 "<div></div>" | |
| 206 "<div></div>" | |
| 207 "</div>"); | |
| 208 | |
| 209 document().view()->updateLayoutAndStyleIfNeededRecursive(); | |
| 210 | |
| 211 unsigned startCount = document().styleEngine()->resolverAccessCount(); | |
| 212 | |
| 213 document().getElementById("d")->focus(); | |
| 214 document().view()->updateLayoutAndStyleIfNeededRecursive(); | |
| 215 | |
| 216 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount; | |
| 217 | |
| 218 ASSERT_EQ(1U, accessCount); | |
| 219 } | |
| 220 | |
| 221 TEST_F(AffectedByFocusTest, ChildrenAffectedByFocusUpdate) | |
| 222 { | |
| 223 // Check that when focussing the outer div in the document below, you get a | |
| 224 // style recalc for the whole subtree. | |
| 225 | |
| 226 setHtmlInnerHTML("<style>:focus div { border: 1px solid lime; }</style>" | |
| 227 "<div id=d tabIndex=1>" | |
| 228 "<div></div>" | |
| 229 "<div></div>" | |
| 230 "<div></div>" | |
| 231 "<div></div>" | |
| 232 "<div></div>" | |
| 233 "<div></div>" | |
| 234 "<div></div>" | |
| 235 "<div></div>" | |
| 236 "<div></div>" | |
| 237 "<div></div>" | |
| 238 "</div>"); | |
| 239 | |
| 240 document().view()->updateLayoutAndStyleIfNeededRecursive(); | |
| 241 | |
| 242 unsigned startCount = document().styleEngine()->resolverAccessCount(); | |
| 243 | |
| 244 document().getElementById("d")->focus(); | |
| 245 document().view()->updateLayoutAndStyleIfNeededRecursive(); | |
| 246 | |
| 247 unsigned accessCount = document().styleEngine()->resolverAccessCount() - sta rtCount; | |
| 248 | |
| 249 ASSERT_EQ(11U, accessCount); | |
| 250 } | |
| 251 | |
| 252 } // namespace | |
| OLD | NEW |