2016-02-24 10:01:12 +03:00
|
|
|
/* -*- 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/ServoRestyleManager.h"
|
2016-07-08 10:08:46 +03:00
|
|
|
#include "mozilla/ServoStyleSet.h"
|
2016-08-12 05:01:52 +03:00
|
|
|
#include "mozilla/dom/ChildIterator.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsStyleChangeList.h"
|
2016-02-24 10:01:12 +03:00
|
|
|
|
|
|
|
using namespace mozilla::dom;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
ServoRestyleManager::ServoRestyleManager(nsPresContext* aPresContext)
|
|
|
|
: RestyleManagerBase(aPresContext)
|
2016-05-05 07:01:37 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-02-24 10:01:12 +03:00
|
|
|
void
|
|
|
|
ServoRestyleManager::PostRestyleEvent(Element* aElement,
|
|
|
|
nsRestyleHint aRestyleHint,
|
|
|
|
nsChangeHint aMinChangeHint)
|
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
if (MOZ_UNLIKELY(IsDisconnected()) ||
|
|
|
|
MOZ_UNLIKELY(PresContext()->PresShell()->IsDestroying())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-19 04:02:55 +03:00
|
|
|
if (aRestyleHint == 0 && !aMinChangeHint && !HasPendingRestyles()) {
|
|
|
|
return; // Nothing to do.
|
2016-07-13 23:42:47 +03:00
|
|
|
}
|
|
|
|
|
2016-07-19 04:02:55 +03:00
|
|
|
// Note that unlike in Servo, we don't mark elements as dirty until we process
|
|
|
|
// the restyle hints in ProcessPendingRestyles.
|
|
|
|
if (aRestyleHint || aMinChangeHint) {
|
|
|
|
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
|
|
|
|
snapshot->AddExplicitRestyleHint(aRestyleHint);
|
|
|
|
snapshot->AddExplicitChangeHint(aMinChangeHint);
|
2016-07-08 10:08:46 +03:00
|
|
|
}
|
|
|
|
|
2016-08-04 04:58:06 +03:00
|
|
|
PostRestyleEventInternal(false);
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ServoRestyleManager::PostRestyleEventForLazyConstruction()
|
|
|
|
{
|
2016-08-04 04:58:06 +03:00
|
|
|
PostRestyleEventInternal(true);
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ServoRestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint)
|
|
|
|
{
|
2016-07-29 01:22:54 +03:00
|
|
|
NS_WARNING("stylo: ServoRestyleManager::RebuildAllStyleData not implemented");
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ServoRestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
|
|
|
nsRestyleHint aRestyleHint)
|
|
|
|
{
|
2016-08-03 20:35:59 +03:00
|
|
|
NS_WARNING("stylo: ServoRestyleManager::PostRebuildAllStyleDataEvent not implemented");
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
2016-07-29 05:20:45 +03:00
|
|
|
void
|
2016-07-13 23:42:47 +03:00
|
|
|
ServoRestyleManager::RecreateStyleContexts(nsIContent* aContent,
|
|
|
|
nsStyleContext* aParentContext,
|
2016-07-29 05:20:45 +03:00
|
|
|
ServoStyleSet* aStyleSet,
|
|
|
|
nsStyleChangeList& aChangeListToProcess)
|
2016-07-13 23:42:47 +03:00
|
|
|
{
|
|
|
|
nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
|
2016-07-29 05:20:45 +03:00
|
|
|
if (!primaryFrame && !aContent->IsDirtyForServo()) {
|
2016-08-06 23:39:04 +03:00
|
|
|
// This happens when, for example, a display: none child of a
|
|
|
|
// HAS_DIRTY_DESCENDANTS content is reached as part of the traversal.
|
2016-07-13 23:42:47 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-15 21:48:45 +03:00
|
|
|
if (aContent->IsDirtyForServo()) {
|
2016-08-07 00:18:12 +03:00
|
|
|
RefPtr<ServoComputedValues> computedValues =
|
2016-08-23 06:14:27 +03:00
|
|
|
Servo_ComputedValues_Get(aContent).Consume();
|
2016-08-07 00:18:12 +03:00
|
|
|
MOZ_ASSERT(computedValues);
|
|
|
|
|
2016-08-12 05:01:52 +03:00
|
|
|
nsChangeHint changeHint = nsChangeHint(0);
|
2016-08-07 00:18:12 +03:00
|
|
|
// NB: Change hint processing only applies to elements, at least until we
|
|
|
|
// support display: contents.
|
|
|
|
if (aContent->IsElement()) {
|
|
|
|
Element* element = aContent->AsElement();
|
|
|
|
|
|
|
|
// Add an explicit change hint if appropriate.
|
|
|
|
ServoElementSnapshot* snapshot;
|
|
|
|
if (mModifiedElements.Get(element, &snapshot)) {
|
|
|
|
changeHint |= snapshot->ExplicitChangeHint();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the stored change hint if there's a frame. If there isn't a frame,
|
|
|
|
// generate a ReconstructFrame change hint if the new display value
|
|
|
|
// (which we can get from the ComputedValues stored on the node) is not
|
|
|
|
// none.
|
|
|
|
if (primaryFrame) {
|
|
|
|
changeHint |= primaryFrame->StyleContext()->ConsumeStoredChangeHint();
|
|
|
|
} else {
|
|
|
|
const nsStyleDisplay* currentDisplay =
|
|
|
|
Servo_GetStyleDisplay(computedValues);
|
|
|
|
if (currentDisplay->mDisplay != NS_STYLE_DISPLAY_NONE) {
|
|
|
|
changeHint |= nsChangeHint_ReconstructFrame;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the new change hint to the list of elements to process if
|
|
|
|
// we need to do any work.
|
|
|
|
if (changeHint) {
|
|
|
|
aChangeListToProcess.AppendChange(primaryFrame, element, changeHint);
|
|
|
|
}
|
2016-07-29 05:20:45 +03:00
|
|
|
}
|
|
|
|
|
2016-08-07 00:18:12 +03:00
|
|
|
// The frame reconstruction step (if needed) will ask for the descendants'
|
|
|
|
// style correctly. If not needed, we're done too.
|
2016-07-29 05:20:45 +03:00
|
|
|
if (!primaryFrame) {
|
2016-08-25 01:39:55 +03:00
|
|
|
aContent->UnsetIsDirtyForServo();
|
2016-07-29 05:20:45 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-08-07 00:18:12 +03:00
|
|
|
// Hold the old style context alive, because it could become a dangling
|
|
|
|
// pointer during the replacement. In practice it's not a huge deal (on
|
|
|
|
// GetNextContinuationWithSameStyle the pointer is not dereferenced, only
|
|
|
|
// compared), but better not playing with dangling pointers if not needed.
|
|
|
|
RefPtr<nsStyleContext> oldStyleContext = primaryFrame->StyleContext();
|
|
|
|
MOZ_ASSERT(oldStyleContext);
|
2016-07-15 21:48:45 +03:00
|
|
|
|
|
|
|
// TODO: Figure out what pseudos does this content have, and do the proper
|
|
|
|
// thing with them.
|
2016-07-29 05:20:45 +03:00
|
|
|
RefPtr<nsStyleContext> newContext =
|
2016-08-07 00:18:12 +03:00
|
|
|
aStyleSet->GetContext(computedValues.forget(), aParentContext, nullptr,
|
2016-07-15 21:48:45 +03:00
|
|
|
CSSPseudoElementType::NotPseudo);
|
|
|
|
|
2016-08-07 00:18:12 +03:00
|
|
|
// XXX This could not always work as expected: there are kinds of content
|
2016-07-29 05:20:45 +03:00
|
|
|
// with the first split and the last sharing style, but others not. We
|
|
|
|
// should handle those properly.
|
|
|
|
for (nsIFrame* f = primaryFrame; f;
|
|
|
|
f = GetNextContinuationWithSameStyle(f, oldStyleContext)) {
|
|
|
|
f->SetStyleContext(newContext);
|
|
|
|
}
|
|
|
|
|
2016-08-12 05:01:52 +03:00
|
|
|
// Update pseudo-elements state if appropriate.
|
|
|
|
if (aContent->IsElement()) {
|
|
|
|
Element* aElement = aContent->AsElement();
|
|
|
|
const static CSSPseudoElementType pseudosToRestyle[] = {
|
|
|
|
CSSPseudoElementType::before, CSSPseudoElementType::after,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (CSSPseudoElementType pseudoType : pseudosToRestyle) {
|
|
|
|
nsIAtom* pseudoTag =
|
|
|
|
nsCSSPseudoElements::GetPseudoAtom(pseudoType);
|
|
|
|
if (nsIFrame* pseudoFrame =
|
|
|
|
FrameForPseudoElement(aElement, pseudoTag)) {
|
|
|
|
// TODO: we could maybe make this more performant via calling into
|
|
|
|
// Servo just once to know which pseudo-elements we've got to restyle?
|
|
|
|
RefPtr<nsStyleContext> pseudoContext =
|
|
|
|
aStyleSet->ProbePseudoElementStyle(aElement, pseudoType,
|
|
|
|
newContext);
|
|
|
|
|
|
|
|
// If pseudoContext is null here, it means the frame is going away, so
|
|
|
|
// our change hint computation should have already indicated we need
|
|
|
|
// to reframe.
|
|
|
|
MOZ_ASSERT_IF(!pseudoContext,
|
|
|
|
changeHint & nsChangeHint_ReconstructFrame);
|
|
|
|
if (pseudoContext) {
|
|
|
|
pseudoFrame->SetStyleContext(pseudoContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 05:20:45 +03:00
|
|
|
// TODO: There are other continuations we still haven't restyled, mostly
|
|
|
|
// pseudo-elements. We have to deal with those, and with anonymous boxes.
|
2016-08-25 01:39:55 +03:00
|
|
|
aContent->UnsetIsDirtyForServo();
|
2016-07-15 21:48:45 +03:00
|
|
|
}
|
2016-07-13 23:42:47 +03:00
|
|
|
|
2016-07-15 21:48:45 +03:00
|
|
|
if (aContent->HasDirtyDescendantsForServo()) {
|
2016-07-29 05:20:45 +03:00
|
|
|
MOZ_ASSERT(primaryFrame,
|
|
|
|
"Frame construction should be scheduled, and it takes the "
|
2016-08-07 00:18:12 +03:00
|
|
|
"correct style for the children, so no need to be here.");
|
2016-08-17 03:24:37 +03:00
|
|
|
StyleChildrenIterator it(aContent);
|
2016-07-15 21:48:45 +03:00
|
|
|
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
|
2016-07-29 05:20:45 +03:00
|
|
|
RecreateStyleContexts(n, primaryFrame->StyleContext(),
|
|
|
|
aStyleSet, aChangeListToProcess);
|
2016-07-15 21:48:45 +03:00
|
|
|
}
|
2016-08-25 01:39:55 +03:00
|
|
|
aContent->UnsetHasDirtyDescendantsForServo();
|
2016-07-13 23:42:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-23 01:19:30 +03:00
|
|
|
static void
|
|
|
|
MarkChildrenAsDirtyForServo(nsIContent* aContent)
|
|
|
|
{
|
2016-08-17 03:24:37 +03:00
|
|
|
StyleChildrenIterator it(aContent);
|
2016-07-23 01:19:30 +03:00
|
|
|
|
|
|
|
nsIContent* n = it.GetNextChild();
|
|
|
|
bool hadChildren = bool(n);
|
|
|
|
for (; n; n = it.GetNextChild()) {
|
|
|
|
n->SetIsDirtyForServo();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hadChildren) {
|
|
|
|
aContent->SetHasDirtyDescendantsForServo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 05:01:52 +03:00
|
|
|
/* static */ nsIFrame*
|
|
|
|
ServoRestyleManager::FrameForPseudoElement(nsIContent* aContent,
|
|
|
|
nsIAtom* aPseudoTagOrNull)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
|
|
|
|
nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
|
|
|
|
|
|
|
|
if (!aPseudoTagOrNull) {
|
|
|
|
return primaryFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!primaryFrame) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: we probably need to special-case display: contents here. Gecko's
|
|
|
|
// RestyleManager passes the primary frame of the parent instead.
|
|
|
|
if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
|
|
|
|
return nsLayoutUtils::GetBeforeFrameForContent(primaryFrame, aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
|
|
|
|
return nsLayoutUtils::GetAfterFrameForContent(primaryFrame, aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_CRASH("Unkown pseudo-element given to "
|
|
|
|
"ServoRestyleManager::FrameForPseudoElement");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
2016-07-19 04:02:55 +03:00
|
|
|
ServoRestyleManager::NoteRestyleHint(Element* aElement, nsRestyleHint aHint)
|
|
|
|
{
|
2016-07-29 05:20:45 +03:00
|
|
|
const nsRestyleHint HANDLED_RESTYLE_HINTS = eRestyle_Self |
|
|
|
|
eRestyle_Subtree |
|
|
|
|
eRestyle_LaterSiblings |
|
|
|
|
eRestyle_SomeDescendants;
|
|
|
|
// NB: For Servo, at least for now, restyling and running selector-matching
|
|
|
|
// against the subtree is necessary as part of restyling the element, so
|
|
|
|
// processing eRestyle_Self will perform at least as much work as
|
|
|
|
// eRestyle_Subtree.
|
|
|
|
if (aHint & (eRestyle_Self | eRestyle_Subtree)) {
|
2016-07-19 04:02:55 +03:00
|
|
|
aElement->SetIsDirtyForServo();
|
2016-08-19 23:07:52 +03:00
|
|
|
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
|
2016-07-29 05:20:45 +03:00
|
|
|
// NB: Servo gives us a eRestyle_SomeDescendants when it expects us to run
|
|
|
|
// selector matching on all the descendants. There's a bug on Servo to align
|
|
|
|
// meanings here (#12710) to avoid this potential source of confusion.
|
|
|
|
} else if (aHint & eRestyle_SomeDescendants) {
|
2016-07-23 01:19:30 +03:00
|
|
|
MarkChildrenAsDirtyForServo(aElement);
|
2016-08-19 23:07:52 +03:00
|
|
|
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
|
2016-07-19 04:02:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aHint & eRestyle_LaterSiblings) {
|
2016-08-19 23:07:52 +03:00
|
|
|
aElement->MarkAncestorsAsHavingDirtyDescendantsForServo();
|
2016-08-05 21:55:19 +03:00
|
|
|
for (nsIContent* cur = aElement->GetNextSibling(); cur;
|
2016-07-19 04:02:55 +03:00
|
|
|
cur = cur->GetNextSibling()) {
|
2016-07-29 05:20:45 +03:00
|
|
|
cur->SetIsDirtyForServo();
|
2016-07-19 04:02:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Handle all other nsRestyleHint values.
|
2016-07-29 05:20:45 +03:00
|
|
|
if (aHint & ~HANDLED_RESTYLE_HINTS) {
|
2016-07-29 01:22:54 +03:00
|
|
|
NS_WARNING(nsPrintfCString("stylo: Unhandled restyle hint %s",
|
2016-07-29 05:20:45 +03:00
|
|
|
RestyleManagerBase::RestyleHintToString(aHint).get()).get());
|
2016-07-19 04:02:55 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-24 10:01:12 +03:00
|
|
|
void
|
|
|
|
ServoRestyleManager::ProcessPendingRestyles()
|
|
|
|
{
|
2016-07-29 05:20:45 +03:00
|
|
|
MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!");
|
|
|
|
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
|
2016-07-18 21:28:27 +03:00
|
|
|
if (!HasPendingRestyles()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-07-13 23:42:47 +03:00
|
|
|
|
2016-07-29 05:20:45 +03:00
|
|
|
ServoStyleSet* styleSet = StyleSet();
|
2016-07-27 03:06:25 +03:00
|
|
|
if (!styleSet->StylingStarted()) {
|
|
|
|
// If something caused us to restyle, and we haven't started styling yet,
|
|
|
|
// do nothing. Everything is dirty, and we'll style it all later.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-07-13 23:42:47 +03:00
|
|
|
nsIDocument* doc = PresContext()->Document();
|
2016-07-18 21:28:27 +03:00
|
|
|
Element* root = doc->GetRootElement();
|
2016-07-13 23:42:47 +03:00
|
|
|
if (root) {
|
2016-07-19 04:02:55 +03:00
|
|
|
for (auto iter = mModifiedElements.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
ServoElementSnapshot* snapshot = iter.UserData();
|
|
|
|
Element* element = iter.Key();
|
|
|
|
|
|
|
|
// TODO: avoid the ComputeRestyleHint call if we already have the highest
|
|
|
|
// explicit restyle hint?
|
|
|
|
nsRestyleHint hint = styleSet->ComputeRestyleHint(element, snapshot);
|
|
|
|
hint |= snapshot->ExplicitRestyleHint();
|
|
|
|
|
|
|
|
if (hint) {
|
|
|
|
NoteRestyleHint(element, hint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-28 00:00:29 +03:00
|
|
|
if (root->IsDirtyForServo() || root->HasDirtyDescendantsForServo()) {
|
2016-08-04 04:58:06 +03:00
|
|
|
mInStyleRefresh = true;
|
2016-08-12 00:12:49 +03:00
|
|
|
styleSet->StyleDocument(/* aLeaveDirtyBits = */ true);
|
2016-07-29 05:20:45 +03:00
|
|
|
|
|
|
|
// First do any queued-up frame creation. (see bugs 827239 and 997506).
|
|
|
|
//
|
|
|
|
// XXXEmilio I'm calling this to avoid random behavior changes, since we
|
|
|
|
// delay frame construction after styling we should re-check once our
|
|
|
|
// model is more stable whether we can skip this call.
|
|
|
|
//
|
|
|
|
// Note this has to be *after* restyling, because otherwise frame
|
|
|
|
// construction will find unstyled nodes, and that's not funny.
|
|
|
|
PresContext()->FrameConstructor()->CreateNeededFrames();
|
|
|
|
|
|
|
|
nsStyleChangeList changeList;
|
|
|
|
RecreateStyleContexts(root, nullptr, styleSet, changeList);
|
|
|
|
ProcessRestyledFrames(changeList);
|
2016-08-04 04:58:06 +03:00
|
|
|
|
|
|
|
mInStyleRefresh = false;
|
2016-07-28 00:00:29 +03:00
|
|
|
}
|
2016-07-13 23:42:47 +03:00
|
|
|
}
|
|
|
|
|
2016-07-18 21:28:27 +03:00
|
|
|
MOZ_ASSERT(!doc->IsDirtyForServo());
|
2016-08-12 00:12:49 +03:00
|
|
|
MOZ_ASSERT(!doc->HasDirtyDescendantsForServo());
|
|
|
|
|
|
|
|
mModifiedElements.Clear();
|
2016-07-18 21:28:27 +03:00
|
|
|
|
2016-07-08 10:08:46 +03:00
|
|
|
IncrementRestyleGeneration();
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
|
2016-02-24 10:01:12 +03:00
|
|
|
nsIContent* aChild)
|
|
|
|
{
|
2016-08-11 21:48:27 +03:00
|
|
|
//
|
|
|
|
// XXXbholley: We need the Gecko logic here to correctly restyle for things
|
|
|
|
// like :empty and positional selectors (though we may not need to post
|
|
|
|
// restyle events as agressively as the Gecko path does).
|
|
|
|
//
|
|
|
|
// Bug 1297899 tracks this work.
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
ServoRestyleManager::ContentInserted(nsINode* aContainer, nsIContent* aChild)
|
2016-08-11 21:48:27 +03:00
|
|
|
{
|
|
|
|
if (!aContainer->ServoData().get()) {
|
|
|
|
// This can happen with display:none. Bug 1297249 tracks more investigation
|
|
|
|
// and assertions here.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Style the new subtree because we will most likely need it during subsequent
|
|
|
|
// frame construction. Bug 1298281 tracks deferring this work in the lazy
|
|
|
|
// frame construction case.
|
|
|
|
StyleSet()->StyleNewSubtree(aChild);
|
|
|
|
|
|
|
|
RestyleForInsertOrChange(aContainer, aChild);
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
ServoRestyleManager::RestyleForAppend(nsIContent* aContainer,
|
2016-02-24 10:01:12 +03:00
|
|
|
nsIContent* aFirstNewContent)
|
|
|
|
{
|
2016-08-11 21:48:27 +03:00
|
|
|
//
|
|
|
|
// XXXbholley: We need the Gecko logic here to correctly restyle for things
|
|
|
|
// like :empty and positional selectors (though we may not need to post
|
|
|
|
// restyle events as agressively as the Gecko path does).
|
|
|
|
//
|
|
|
|
// Bug 1297899 tracks this work.
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
ServoRestyleManager::ContentAppended(nsIContent* aContainer,
|
2016-08-11 21:48:27 +03:00
|
|
|
nsIContent* aFirstNewContent)
|
|
|
|
{
|
|
|
|
if (!aContainer->ServoData().get()) {
|
|
|
|
// This can happen with display:none. Bug 1297249 tracks more investigation
|
|
|
|
// and assertions here.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Style the new subtree because we will most likely need it during subsequent
|
|
|
|
// frame construction. Bug 1298281 tracks deferring this work in the lazy
|
|
|
|
// frame construction case.
|
|
|
|
if (aFirstNewContent->GetNextSibling()) {
|
|
|
|
aContainer->SetHasDirtyDescendantsForServo();
|
|
|
|
StyleSet()->StyleNewChildren(aContainer);
|
|
|
|
} else {
|
|
|
|
StyleSet()->StyleNewSubtree(aFirstNewContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
RestyleForAppend(aContainer, aFirstNewContent);
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-16 21:33:30 +03:00
|
|
|
ServoRestyleManager::ContentRemoved(nsINode* aContainer,
|
2016-08-11 21:48:27 +03:00
|
|
|
nsIContent* aOldChild,
|
|
|
|
nsIContent* aFollowingSibling)
|
2016-02-24 10:01:12 +03:00
|
|
|
{
|
2016-08-11 21:48:27 +03:00
|
|
|
NS_WARNING("stylo: ServoRestyleManager::ContentRemoved not implemented");
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
|
2016-07-19 04:02:55 +03:00
|
|
|
EventStates aChangedBits)
|
2016-02-24 10:01:12 +03:00
|
|
|
{
|
2016-07-08 10:08:46 +03:00
|
|
|
if (!aContent->IsElement()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
Element* aElement = aContent->AsElement();
|
|
|
|
nsChangeHint changeHint;
|
|
|
|
nsRestyleHint restyleHint;
|
2016-07-19 04:02:55 +03:00
|
|
|
|
|
|
|
// NOTE: restyleHint here is effectively always 0, since that's what
|
|
|
|
// ServoStyleSet::HasStateDependentStyle returns. Servo computes on
|
|
|
|
// ProcessPendingRestyles using the ElementSnapshot, but in theory could
|
|
|
|
// compute it sequentially easily.
|
|
|
|
//
|
|
|
|
// Determine what's the best way to do it, and how much work do we save
|
|
|
|
// processing the restyle hint early (i.e., computing the style hint here
|
|
|
|
// sequentially, potentially saving the snapshot), vs lazily (snapshot
|
|
|
|
// approach).
|
|
|
|
//
|
|
|
|
// If we take the sequential approach we need to specialize Servo's restyle
|
|
|
|
// hints system a bit more, and mesure whether we save something storing the
|
|
|
|
// restyle hint in the table and deferring the dirtiness setting until
|
|
|
|
// ProcessPendingRestyles (that's a requirement if we store snapshots though),
|
|
|
|
// vs processing the restyle hint in-place, dirtying the nodes on
|
|
|
|
// PostRestyleEvent.
|
|
|
|
//
|
|
|
|
// If we definitely take the snapshot approach, we should take rid of
|
|
|
|
// HasStateDependentStyle, etc (though right now they're no-ops).
|
|
|
|
ContentStateChangedInternal(aElement, aChangedBits, &changeHint,
|
|
|
|
&restyleHint);
|
|
|
|
|
|
|
|
EventStates previousState = aElement->StyleState() ^ aChangedBits;
|
|
|
|
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
|
|
|
|
snapshot->AddState(previousState);
|
2016-07-08 10:08:46 +03:00
|
|
|
|
2016-07-18 21:28:57 +03:00
|
|
|
PostRestyleEvent(aElement, restyleHint, changeHint);
|
2016-05-05 07:01:37 +03:00
|
|
|
return NS_OK;
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ServoRestyleManager::AttributeWillChange(Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
2016-07-19 04:02:55 +03:00
|
|
|
nsIAtom* aAttribute, int32_t aModType,
|
2016-02-24 10:01:12 +03:00
|
|
|
const nsAttrValue* aNewValue)
|
|
|
|
{
|
2016-07-20 00:35:37 +03:00
|
|
|
ServoElementSnapshot* snapshot = SnapshotForElement(aElement);
|
|
|
|
snapshot->AddAttrs(aElement);
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
ServoRestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
|
|
|
{
|
2016-07-29 01:22:54 +03:00
|
|
|
NS_WARNING("stylo: ServoRestyleManager::ReparentStyleContext not implemented");
|
2016-06-10 10:07:17 +03:00
|
|
|
return NS_OK;
|
2016-02-24 10:01:12 +03:00
|
|
|
}
|
|
|
|
|
2016-07-19 04:02:55 +03:00
|
|
|
ServoElementSnapshot*
|
|
|
|
ServoRestyleManager::SnapshotForElement(Element* aElement)
|
|
|
|
{
|
2016-07-29 20:50:26 +03:00
|
|
|
// NB: aElement is the argument for the construction of the snapshot in the
|
|
|
|
// not found case.
|
|
|
|
return mModifiedElements.LookupOrAdd(aElement, aElement);
|
2016-07-19 04:02:55 +03:00
|
|
|
}
|
|
|
|
|
2016-02-24 10:01:12 +03:00
|
|
|
} // namespace mozilla
|