1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * a list of the recomputation that needs to be done in response to a
9  * style change
10  */
11 
12 #include "nsStyleChangeList.h"
13 
14 #include "nsCSSFrameConstructor.h"
15 #include "nsIContent.h"
16 #include "nsIFrame.h"
17 
AppendChange(nsIFrame * aFrame,nsIContent * aContent,nsChangeHint aHint)18 void nsStyleChangeList::AppendChange(nsIFrame* aFrame, nsIContent* aContent,
19                                      nsChangeHint aHint) {
20   MOZ_ASSERT(aFrame || (aHint & nsChangeHint_ReconstructFrame),
21              "must have frame");
22   MOZ_ASSERT(aHint, "No hint to process?");
23   MOZ_ASSERT(!(aHint & nsChangeHint_NeutralChange),
24              "Neutral changes do not need extra processing, "
25              "and should be stripped out");
26   MOZ_ASSERT(aContent || !(aHint & nsChangeHint_ReconstructFrame),
27              "must have content");
28   // XXXbz we should make this take Element instead of nsIContent
29   MOZ_ASSERT(
30       !aContent || aContent->IsElement() ||
31           // display:contents elements posts the changes for their children:
32           (aFrame && aContent->GetParent() &&
33            aFrame->PresContext()
34                ->FrameConstructor()
35                ->GetDisplayContentsStyleFor(aContent->GetParent())) ||
36           (aContent->IsNodeOfType(nsINode::eTEXT) &&
37            aContent->IsStyledByServo() && aContent->HasFlag(NODE_NEEDS_FRAME) &&
38            aHint & nsChangeHint_ReconstructFrame),
39       "Shouldn't be trying to restyle non-elements directly, "
40       "except if it's a display:contents child or a text node "
41       "doing lazy frame construction");
42   MOZ_ASSERT(!(aHint & nsChangeHint_AllReflowHints) ||
43                  (aHint & nsChangeHint_NeedReflow),
44              "Reflow hint bits set without actually asking for a reflow");
45 
46   if (aHint & nsChangeHint_ReconstructFrame) {
47     // If Servo fires reconstruct at a node, it is the only change hint fired at
48     // that node.
49     if (IsServo()) {
50     // Note: Because we check whether |aHint| is a reconstruct above (which is
51     // necessary to avoid debug test timeouts on certain crashtests), this check
52     // will not find bugs where we add a non-reconstruct hint for an element
53     // after adding a reconstruct. This is ok though, since
54     // ProcessRestyledFrames will handle that case via mDestroyedFrames.
55 #ifdef DEBUG
56       for (size_t i = 0; i < Length(); ++i) {
57         MOZ_ASSERT(aContent != (*this)[i].mContent ||
58                        !((*this)[i].mHint & nsChangeHint_ReconstructFrame),
59                    "Should not append a non-ReconstructFrame hint after \
60                    appending a ReconstructFrame hint for the same \
61                    content.");
62       }
63 #endif
64     } else {
65       // Filter out all other changes for same content for Gecko (Servo asserts
66       // against this case above). NOTE: This is captured by reference to please
67       // static analysis. Capturing it by value as a pointer should be fine in
68       // this case.
69       RemoveElementsBy([&](const nsStyleChangeData& aData) {
70         return aData.mContent == aContent;
71       });
72     }
73   }
74 
75   if (!IsEmpty() && aFrame && aFrame == LastElement().mFrame) {
76     LastElement().mHint |= aHint;
77     return;
78   }
79 
80   AppendElement(nsStyleChangeData{aFrame, aContent, aHint});
81 }
82