gecko-dev/layout/style/ServoElementSnapshot.cpp
Brian Birtles f6eddc29f3 Bug 1365472 - Use animated class names when doing selector matching in Servo; r=heycam
Using SVG SMIL it is possible to animate the class attribute of an element using
markup such as the following:

  <style>
    .red {
      fill: red;
    }
  </style>
  <svg>
    <circle cx="50" cy="50" r="30" fill="blue">
      <set attributeName="class" to="red" begin="1s"/>
    </circle>
  </svg>

In Gecko, Element::GetClasses handles this case by looking for an animated class
string when the element in question is an SVG element.

This patch causes our Servo bindings to use GetClasses when querying attribute
values for selector matching.

Note that animating the class attribute is *not* expected to affect attribute
selectors such as `circle[class="red"]`. It does in Chrome, but that is due to
a Blink bug where animating attributes using SMIL affects the result of
getAttribute:

  https://bugs.chromium.org/p/chromium/issues/detail?id=735820

This patch adjusts the behavior for both the GeckoElement case and the
ServoElementSnapshot case.

MozReview-Commit-ID: DAFWHSH1aYB

--HG--
extra : rebase_source : 292c4e2fb419818ea851aca12790ff7e70f2e1d4
2017-06-27 10:55:03 -07:00

96 lines
2.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/ServoElementSnapshot.h"
#include "mozilla/dom/Element.h"
#include "nsIContentInlines.h"
#include "nsContentUtils.h"
namespace mozilla {
ServoElementSnapshot::ServoElementSnapshot(const Element* aElement)
: mState(0)
, mContains(Flags(0))
, mIsTableBorderNonzero(false)
, mIsMozBrowserFrame(false)
, mClassAttributeChanged(false)
, mIdAttributeChanged(false)
, mOtherAttributeChanged(false)
{
MOZ_COUNT_CTOR(ServoElementSnapshot);
mIsHTMLElementInHTMLDocument =
aElement->IsHTMLElement() && aElement->IsInHTMLDocument();
mIsInChromeDocument = nsContentUtils::IsChromeDoc(aElement->OwnerDoc());
mSupportsLangAttr = aElement->SupportsLangAttr();
}
ServoElementSnapshot::~ServoElementSnapshot()
{
MOZ_COUNT_DTOR(ServoElementSnapshot);
}
void
ServoElementSnapshot::AddAttrs(Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute)
{
MOZ_ASSERT(aElement);
if (aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::_class) {
mClassAttributeChanged = true;
} else if (aAttribute == nsGkAtoms::id) {
mIdAttributeChanged = true;
} else {
mOtherAttributeChanged = true;
}
} else {
mOtherAttributeChanged = true;
}
if (HasAttrs()) {
return;
}
uint32_t attrCount = aElement->GetAttrCount();
const nsAttrName* attrName;
for (uint32_t i = 0; i < attrCount; ++i) {
attrName = aElement->GetAttrNameAt(i);
const nsAttrValue* attrValue =
aElement->GetParsedAttr(attrName->LocalName(), attrName->NamespaceID());
mAttrs.AppendElement(ServoAttrSnapshot(*attrName, *attrValue));
}
mContains |= Flags::Attributes;
if (aElement->HasID()) {
mContains |= Flags::Id;
}
if (const nsAttrValue* classValue = aElement->GetClasses()) {
mClass = *classValue;
mContains |= Flags::MaybeClass;
}
}
void
ServoElementSnapshot::AddOtherPseudoClassState(Element* aElement)
{
MOZ_ASSERT(aElement);
if (HasOtherPseudoClassState()) {
return;
}
mIsTableBorderNonzero =
*nsCSSPseudoClasses::MatchesElement(CSSPseudoClassType::mozTableBorderNonzero,
aElement);
mIsMozBrowserFrame =
*nsCSSPseudoClasses::MatchesElement(CSSPseudoClassType::mozBrowserFrame,
aElement);
mContains |= Flags::OtherPseudoClassState;
}
} // namespace mozilla