| Index: Source/core/css/AffectedByFocusTest.cpp
|
| diff --git a/Source/core/css/AffectedByFocusTest.cpp b/Source/core/css/AffectedByFocusTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..671a6bed401ddee24c39e835039f9e76f3c1018a
|
| --- /dev/null
|
| +++ b/Source/core/css/AffectedByFocusTest.cpp
|
| @@ -0,0 +1,215 @@
|
| +/*
|
| + * Copyright (c) 2014, Opera Software ASA. 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.
|
| + * 3. Neither the name of Opera Software ASA nor the names of its
|
| + * contributors may be used to endorse or promote products derived
|
| + * from this software without specific prior written permission.
|
| + *
|
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE
|
| + * COPYRIGHT HOLDER OR 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 "config.h"
|
| +#include "HTMLNames.h"
|
| +#include "core/dom/Element.h"
|
| +#include "core/dom/ElementTraversal.h"
|
| +#include "core/frame/FrameView.h"
|
| +#include "core/html/HTMLDocument.h"
|
| +#include "core/html/HTMLElement.h"
|
| +#include "core/testing/DummyPageHolder.h"
|
| +#include <gtest/gtest.h>
|
| +
|
| +using namespace WebCore;
|
| +using namespace HTMLNames;
|
| +
|
| +namespace {
|
| +
|
| +class AffectedByFocusTest : public ::testing::Test {
|
| +
|
| +protected:
|
| +
|
| + struct ElementResult {
|
| + const WebCore::QualifiedName tag;
|
| + bool affectedBy;
|
| + bool childrenAffectedBy;
|
| + };
|
| +
|
| + virtual void SetUp() OVERRIDE;
|
| +
|
| + HTMLDocument& document() const { return *m_document; }
|
| +
|
| + void setHtmlInnerHTML(const char* htmlContent);
|
| +
|
| + void checkElements(ElementResult expected[], unsigned expectedCount) const;
|
| +
|
| +private:
|
| + OwnPtr<DummyPageHolder> m_dummyPageHolder;
|
| +
|
| + HTMLDocument* m_document;
|
| +};
|
| +
|
| +void AffectedByFocusTest::SetUp()
|
| +{
|
| + m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
|
| + m_document = toHTMLDocument(&m_dummyPageHolder->document());
|
| + ASSERT(m_document);
|
| +}
|
| +
|
| +void AffectedByFocusTest::setHtmlInnerHTML(const char* htmlContent)
|
| +{
|
| + document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent), ASSERT_NO_EXCEPTION);
|
| + document().view()->updateLayoutAndStyleIfNeededRecursive();
|
| +}
|
| +
|
| +void AffectedByFocusTest::checkElements(ElementResult expected[], unsigned expectedCount) const
|
| +{
|
| + unsigned i = 0;
|
| + Element* elm = document().body();
|
| +
|
| + for (; elm && i < 5; elm = ElementTraversal::next(*elm), ++i) {
|
| + ASSERT_TRUE(elm->hasTagName(expected[i].tag));
|
| + ASSERT(elm->renderStyle());
|
| + ASSERT_EQ(expected[i].affectedBy, elm->renderStyle()->affectedByFocus());
|
| + ASSERT_EQ(expected[i].childrenAffectedBy, elm->childrenAffectedByFocus());
|
| + }
|
| +
|
| + ASSERT(!elm && i == size);
|
| +}
|
| +
|
| +// A global :focus rule in html.css currently causes every single element to be
|
| +// affectedByFocus. Check that all elements in a document with no :focus rules
|
| +// gets the affectedByFocus set on RenderStyle and not childrenAffectedByFocus.
|
| +TEST_F(AffectedByFocusTest, UAUniversalFocusRule)
|
| +{
|
| + ElementResult expected[] = {
|
| + { bodyTag, true, false },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { spanTag, true, false }
|
| + };
|
| +
|
| + setHtmlInnerHTML("<body>"
|
| + "<div><div></div></div>"
|
| + "<div><span></span></div>"
|
| + "</body>");
|
| +
|
| + checkElements(expected, sizeof(expected) / sizeof(ElementResult));
|
| +}
|
| +
|
| +// ":focus div" will mark ascendants of all divs with childrenAffectedByFocus.
|
| +TEST_F(AffectedByFocusTest, FocusedAscendant)
|
| +{
|
| + ElementResult expected[] = {
|
| + { bodyTag, true, true },
|
| + { divTag, true, true },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { spanTag, true, false }
|
| + };
|
| +
|
| + setHtmlInnerHTML("<head>"
|
| + "<style>:focus div { background-color: pink }</style>"
|
| + "</head>"
|
| + "<body>"
|
| + "<div><div></div></div>"
|
| + "<div><span></span></div>"
|
| + "</body>");
|
| +
|
| + checkElements(expected, sizeof(expected) / sizeof(ElementResult));
|
| +}
|
| +
|
| +// "body:focus div" will mark the body element with childrenAffectedByFocus.
|
| +TEST_F(AffectedByFocusTest, FocusedAscendantWithType)
|
| +{
|
| + ElementResult expected[] = {
|
| + { bodyTag, true, true },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { spanTag, true, false }
|
| + };
|
| +
|
| + setHtmlInnerHTML("<head>"
|
| + "<style>body:focus div { background-color: pink }</style>"
|
| + "</head>"
|
| + "<body>"
|
| + "<div><div></div></div>"
|
| + "<div><span></span></div>"
|
| + "</body>");
|
| +
|
| + checkElements(expected, sizeof(expected) / sizeof(ElementResult));
|
| +}
|
| +
|
| +// ":not(body):focus div" should not mark the body element with childrenAffectedByFocus.
|
| +// Note that currently ":focus:not(body)" does not do the same. Then the :focus is
|
| +// checked and the childrenAffectedByFocus flag set before the negated type selector
|
| +// is found.
|
| +TEST_F(AffectedByFocusTest, FocusedAscendantWithNegatedType)
|
| +{
|
| + ElementResult expected[] = {
|
| + { bodyTag, true, false },
|
| + { divTag, true, true },
|
| + { divTag, true, false },
|
| + { divTag, true, false },
|
| + { spanTag, true, false }
|
| + };
|
| +
|
| + setHtmlInnerHTML("<head>"
|
| + "<style>:not(body):focus div { background-color: pink }</style>"
|
| + "</head>"
|
| + "<body>"
|
| + "<div><div></div></div>"
|
| + "<div><span></span></div>"
|
| + "</body>");
|
| +
|
| + checkElements(expected, sizeof(expected) / sizeof(ElementResult));
|
| +}
|
| +
|
| +// Checking current behavior for ":focus + div", but this is a BUG or at best
|
| +// sub-optimal. The focused element will also in this case get childrenAffectedByFocus
|
| +// even if it's really a sibling. Effectively, the whole sub-tree of the focused
|
| +// element will have styles recalculated even though none of the children are
|
| +// affected. There are other mechanisms that makes sure the sibling also gets its
|
| +// styles recalculated.
|
| +TEST_F(AffectedByFocusTest, FocusedSibling)
|
| +{
|
| + ElementResult expected[] = {
|
| + { bodyTag, true, false },
|
| + { divTag, true, true },
|
| + { spanTag, true, false },
|
| + { divTag, true, false }
|
| + };
|
| +
|
| + setHtmlInnerHTML("<head>"
|
| + "<style>:focus + div { background-color: pink }</style>"
|
| + "</head>"
|
| + "<body>"
|
| + "<div>"
|
| + " <span></span>"
|
| + "</div>"
|
| + "<div></div>"
|
| + "</body>");
|
| +
|
| + checkElements(expected, sizeof(expected) / sizeof(ElementResult));
|
| +}
|
| +
|
| +} // namespace
|
|
|