Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* the interface (to internal code) for retrieving computed style data */
7 :
8 : #include "nsStyleContext.h"
9 : #include "CSSVariableImageTable.h"
10 : #include "mozilla/DebugOnly.h"
11 : #include "mozilla/Maybe.h"
12 :
13 : #include "nsCSSAnonBoxes.h"
14 : #include "nsCSSPseudoElements.h"
15 : #include "nsFontMetrics.h"
16 : #include "nsStyleConsts.h"
17 : #include "nsStyleStruct.h"
18 : #include "nsStyleStructInlines.h"
19 : #include "nsString.h"
20 : #include "nsPresContext.h"
21 : #include "nsIStyleRule.h"
22 :
23 : #include "nsCOMPtr.h"
24 : #include "nsStyleSet.h"
25 : #include "nsIPresShell.h"
26 :
27 : #include "nsRuleNode.h"
28 : #include "GeckoProfiler.h"
29 : #include "nsIDocument.h"
30 : #include "nsPrintfCString.h"
31 : #include "RubyUtils.h"
32 : #include "mozilla/Preferences.h"
33 : #include "mozilla/ArenaObjectID.h"
34 : #include "mozilla/StyleSetHandle.h"
35 : #include "mozilla/StyleSetHandleInlines.h"
36 : #include "mozilla/GeckoStyleContext.h"
37 : #include "mozilla/ServoStyleContext.h"
38 : #include "nsStyleContextInlines.h"
39 :
40 : #include "mozilla/ReflowInput.h"
41 : #include "nsLayoutUtils.h"
42 : #include "nsCoord.h"
43 :
44 : // Ensure the binding function declarations in nsStyleContext.h matches
45 : // those in ServoBindings.h.
46 : #include "mozilla/ServoBindings.h"
47 :
48 : using namespace mozilla;
49 :
50 : //----------------------------------------------------------------------
51 :
52 : #ifdef DEBUG
53 :
54 : // Check that the style struct IDs are in the same order as they are
55 : // in nsStyleStructList.h, since when we set up the IDs, we include
56 : // the inherited and reset structs spearately from nsStyleStructList.h
57 : enum DebugStyleStruct {
58 : #define STYLE_STRUCT(name, checkdata_cb) eDebugStyleStruct_##name,
59 : #include "nsStyleStructList.h"
60 : #undef STYLE_STRUCT
61 : };
62 :
63 : #define STYLE_STRUCT(name, checkdata_cb) \
64 : static_assert(static_cast<int>(eDebugStyleStruct_##name) == \
65 : static_cast<int>(eStyleStruct_##name), \
66 : "Style struct IDs are not declared in order?");
67 : #include "nsStyleStructList.h"
68 : #undef STYLE_STRUCT
69 :
70 : const uint32_t nsStyleContext::sDependencyTable[] = {
71 : #define STYLE_STRUCT(name, checkdata_cb)
72 : #define STYLE_STRUCT_DEP(dep) NS_STYLE_INHERIT_BIT(dep) |
73 : #define STYLE_STRUCT_END() 0,
74 : #include "nsStyleStructList.h"
75 : #undef STYLE_STRUCT
76 : #undef STYLE_STRUCT_DEP
77 : #undef STYLE_STRUCT_END
78 : };
79 :
80 : // Whether to perform expensive assertions in the nsStyleContext destructor.
81 : static bool sExpensiveStyleStructAssertionsEnabled;
82 : #endif
83 :
84 2203 : nsStyleContext::nsStyleContext(nsStyleContext* aParent,
85 : nsIAtom* aPseudoTag,
86 2203 : CSSPseudoElementType aPseudoType)
87 : : mParent(aParent)
88 : , mPseudoTag(aPseudoTag)
89 2203 : , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
90 : , mRefCnt(0)
91 : #ifdef DEBUG
92 4406 : , mFrameRefCnt(0)
93 : #endif
94 2203 : {}
95 :
96 : void
97 2203 : nsStyleContext::FinishConstruction()
98 : {
99 : // This check has to be done "backward", because if it were written the
100 : // more natural way it wouldn't fail even when it needed to.
101 : static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
102 : static_cast<CSSPseudoElementTypeBase>(
103 : CSSPseudoElementType::MAX),
104 : "pseudo element bits no longer fit in a uint64_t");
105 :
106 : #ifdef DEBUG
107 2203 : if (auto servo = GetAsServo()) {
108 0 : MOZ_ASSERT(servo->ComputedValues());
109 : } else {
110 2203 : MOZ_ASSERT(RuleNode());
111 : }
112 :
113 : static_assert(MOZ_ARRAY_LENGTH(nsStyleContext::sDependencyTable)
114 : == nsStyleStructID_Length,
115 : "Number of items in dependency table doesn't match IDs");
116 : #endif
117 :
118 2203 : if (mParent) {
119 2016 : mParent->AddChild(this);
120 : }
121 :
122 2203 : SetStyleBits();
123 :
124 : #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
125 : static_assert(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
126 : "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
127 : #undef eStyleStruct_LastItem
128 2203 : }
129 :
130 : void
131 1618 : nsStyleContext::Destructor()
132 : {
133 1618 : GeckoStyleContext* gecko = GetAsGecko();
134 : #ifdef DEBUG
135 1618 : if (gecko) {
136 1618 : NS_ASSERTION(gecko->HasNoChildren(), "destructing context with children");
137 1618 : if (sExpensiveStyleStructAssertionsEnabled) {
138 : // Assert that the style structs we are about to destroy are not referenced
139 : // anywhere else in the style context tree. These checks are expensive,
140 : // which is why they are not enabled by default.
141 0 : GeckoStyleContext* root = gecko;
142 0 : while (root->GetParent()) {
143 0 : root = root->GetParent();
144 : }
145 0 : root->AssertStructsNotUsedElsewhere(gecko,
146 0 : std::numeric_limits<int32_t>::max());
147 : } else {
148 : // In DEBUG builds when the pref is not enabled, we perform a more limited
149 : // check just of the children of this style context.
150 1618 : gecko->AssertStructsNotUsedElsewhere(gecko, 2);
151 : }
152 : }
153 : #endif
154 :
155 1618 : nsPresContext *presContext = PresContext();
156 3236 : DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
157 1618 : NS_ASSERTION(!geckoStyleSet ||
158 : geckoStyleSet->GetRuleTree() == AsGecko()->RuleNode()->RuleTree() ||
159 : geckoStyleSet->IsInRuleTreeReconstruct(),
160 : "destroying style context from old rule tree too late");
161 :
162 1618 : if (mParent) {
163 1497 : mParent->RemoveChild(this);
164 : } else {
165 121 : presContext->StyleSet()->RootStyleContextRemoved();
166 : }
167 :
168 : // Free up our data structs.
169 1618 : if (gecko) {
170 1618 : gecko->DestroyCachedStructs(presContext);
171 : }
172 :
173 : // Free any ImageValues we were holding on to for CSS variable values.
174 1618 : CSSVariableImageTable::RemoveAll(this);
175 1618 : }
176 :
177 2053 : void nsStyleContext::AddChild(nsStyleContext* aChild)
178 : {
179 2053 : if (GeckoStyleContext* gecko = GetAsGecko()) {
180 2053 : gecko->AddChild(aChild->AsGecko());
181 : }
182 2053 : }
183 :
184 1534 : void nsStyleContext::RemoveChild(nsStyleContext* aChild)
185 : {
186 1534 : if (GeckoStyleContext* gecko = GetAsGecko()) {
187 1534 : gecko->RemoveChild(aChild->AsGecko());
188 : }
189 1534 : }
190 :
191 : void
192 37 : nsStyleContext::MoveTo(nsStyleContext* aNewParent)
193 : {
194 37 : MOZ_ASSERT(aNewParent != mParent);
195 :
196 : // This function shouldn't be getting called if the parents have different
197 : // values for some flags in mBits (unless the flag is also set on this style
198 : // context) because if that were the case we would need to recompute those
199 : // bits for |this|.
200 :
201 : #define CHECK_FLAG(bit_) \
202 : MOZ_ASSERT((mParent->mBits & (bit_)) == (aNewParent->mBits & (bit_)) || \
203 : (mBits & (bit_)), \
204 : "MoveTo cannot be called if " #bit_ " value on old and new " \
205 : "style context parents do not match, unless the flag is set " \
206 : "on this style context");
207 :
208 37 : CHECK_FLAG(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA)
209 37 : CHECK_FLAG(NS_STYLE_IN_DISPLAY_NONE_SUBTREE)
210 37 : CHECK_FLAG(NS_STYLE_HAS_TEXT_DECORATION_LINES)
211 37 : CHECK_FLAG(NS_STYLE_RELEVANT_LINK_VISITED)
212 :
213 : #undef CHECK_FLAG
214 :
215 : // Assertions checking for visited style are just to avoid some tricky
216 : // cases we can't be bothered handling at the moment.
217 37 : MOZ_ASSERT(!IsStyleIfVisited());
218 37 : MOZ_ASSERT(!mParent->IsStyleIfVisited());
219 37 : MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
220 37 : MOZ_ASSERT(!mStyleIfVisited || mStyleIfVisited->mParent == mParent);
221 :
222 37 : if (mParent->HasChildThatUsesResetStyle()) {
223 8 : aNewParent->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
224 : }
225 :
226 37 : mParent->RemoveChild(this);
227 37 : mParent = aNewParent;
228 37 : mParent->AddChild(this);
229 :
230 37 : if (mStyleIfVisited) {
231 0 : mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
232 0 : mStyleIfVisited->mParent = aNewParent;
233 0 : mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
234 : }
235 37 : }
236 :
237 : template<class StyleContextLike>
238 : nsChangeHint
239 726 : nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
240 : uint32_t* aEqualStructs,
241 : uint32_t* aSamePointerStructs)
242 : {
243 1452 : AUTO_PROFILER_LABEL("nsStyleContext::CalcStyleDifferenceInternal", CSS);
244 :
245 : static_assert(nsStyleStructID_Length <= 32,
246 : "aEqualStructs is not big enough");
247 :
248 726 : *aEqualStructs = 0;
249 :
250 726 : nsChangeHint hint = nsChangeHint(0);
251 726 : NS_ENSURE_TRUE(aNewContext, hint);
252 : // We must always ensure that we populate the structs on the new style
253 : // context that are filled in on the old context, so that if we get
254 : // two style changes in succession, the second of which causes a real
255 : // style change, the PeekStyleData doesn't return null (implying that
256 : // nobody ever looked at that struct's data). In other words, we
257 : // can't skip later structs if we get a big change up front, because
258 : // we could later get a small change in one of those structs that we
259 : // don't want to miss.
260 :
261 1452 : DebugOnly<uint32_t> structsFound = 0;
262 :
263 : // FIXME(heycam): We should just do the comparison in
264 : // nsStyleVariables::CalcDifference, returning NeutralChange if there are
265 : // any Variables differences.
266 726 : const nsStyleVariables* thisVariables = PeekStyleVariables();
267 726 : if (thisVariables) {
268 171 : structsFound |= NS_STYLE_INHERIT_BIT(Variables);
269 171 : const nsStyleVariables* otherVariables = aNewContext->StyleVariables();
270 171 : if (thisVariables->mVariables == otherVariables->mVariables) {
271 96 : *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
272 : }
273 : } else {
274 555 : *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
275 : }
276 :
277 1452 : DebugOnly<int> styleStructCount = 1; // count Variables already
278 :
279 : // Servo's optimization to stop the cascade when there are no style changes
280 : // that children need to be recascade for relies on comparing all of the
281 : // structs, not just those that are returned from PeekStyleData, although
282 : // if PeekStyleData does return null we still don't want to accumulate
283 : // any change hints for those structs.
284 726 : bool checkUnrequestedServoStructs = IsServo();
285 :
286 : #define EXPAND(...) __VA_ARGS__
287 : #define DO_STRUCT_DIFFERENCE_WITH_ARGS(struct_, extra_args_) \
288 : PR_BEGIN_MACRO \
289 : const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
290 : bool unrequestedStruct; \
291 : if (this##struct_) { \
292 : unrequestedStruct = false; \
293 : structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
294 : } else if (checkUnrequestedServoStructs) { \
295 : this##struct_ = \
296 : Servo_GetStyle##struct_(AsServo()->ComputedValues()); \
297 : unrequestedStruct = true; \
298 : } else { \
299 : unrequestedStruct = false; \
300 : } \
301 : if (this##struct_) { \
302 : const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
303 : if (this##struct_ == other##struct_) { \
304 : /* The very same struct, so we know that there will be no */ \
305 : /* differences. */ \
306 : *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
307 : } else { \
308 : nsChangeHint difference = \
309 : this##struct_->CalcDifference(*other##struct_ EXPAND extra_args_); \
310 : if (!unrequestedStruct) { \
311 : hint |= difference; \
312 : } \
313 : if (!difference) { \
314 : *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
315 : } \
316 : } \
317 : } else { \
318 : *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
319 : } \
320 : styleStructCount++; \
321 : PR_END_MACRO
322 : #define DO_STRUCT_DIFFERENCE(struct_) \
323 : DO_STRUCT_DIFFERENCE_WITH_ARGS(struct_, ())
324 :
325 : // FIXME: The order of these DO_STRUCT_DIFFERENCE calls is no longer
326 : // significant. With a small amount of effort, we could replace them with a
327 : // #include "nsStyleStructList.h".
328 726 : DO_STRUCT_DIFFERENCE(Display);
329 726 : DO_STRUCT_DIFFERENCE(XUL);
330 726 : DO_STRUCT_DIFFERENCE(Column);
331 726 : DO_STRUCT_DIFFERENCE(Content);
332 726 : DO_STRUCT_DIFFERENCE(UserInterface);
333 726 : DO_STRUCT_DIFFERENCE(Visibility);
334 726 : DO_STRUCT_DIFFERENCE(Outline);
335 726 : DO_STRUCT_DIFFERENCE(TableBorder);
336 726 : DO_STRUCT_DIFFERENCE(Table);
337 726 : DO_STRUCT_DIFFERENCE(UIReset);
338 726 : DO_STRUCT_DIFFERENCE(Text);
339 726 : DO_STRUCT_DIFFERENCE_WITH_ARGS(List, (, PeekStyleDisplay()));
340 726 : DO_STRUCT_DIFFERENCE(SVGReset);
341 726 : DO_STRUCT_DIFFERENCE(SVG);
342 726 : DO_STRUCT_DIFFERENCE_WITH_ARGS(Position, (, PeekStyleVisibility()));
343 726 : DO_STRUCT_DIFFERENCE(Font);
344 726 : DO_STRUCT_DIFFERENCE(Margin);
345 726 : DO_STRUCT_DIFFERENCE(Padding);
346 726 : DO_STRUCT_DIFFERENCE(Border);
347 726 : DO_STRUCT_DIFFERENCE(TextReset);
348 726 : DO_STRUCT_DIFFERENCE(Effects);
349 726 : DO_STRUCT_DIFFERENCE(Background);
350 726 : DO_STRUCT_DIFFERENCE(Color);
351 :
352 : #undef DO_STRUCT_DIFFERENCE
353 : #undef DO_STRUCT_DIFFERENCE_WITH_ARGS
354 : #undef EXPAND
355 :
356 726 : MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
357 : "missing a call to DO_STRUCT_DIFFERENCE");
358 :
359 : #ifdef DEBUG
360 : #define STYLE_STRUCT(name_, callback_) \
361 : MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) == \
362 : !!PeekStyle##name_(), \
363 : "PeekStyleData results must not change in the middle of " \
364 : "difference calculation.");
365 : #include "nsStyleStructList.h"
366 : #undef STYLE_STRUCT
367 : #endif
368 :
369 : // We check for struct pointer equality here rather than as part of the
370 : // DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
371 : // we previously examined and found to be null on this style context
372 : // getting computed by later DO_STRUCT_DIFFERENCE calls (which can
373 : // happen when the nsRuleNode::ComputeXXXData method looks up another
374 : // struct.) This is important for callers in RestyleManager that
375 : // need to know the equality or not of the final set of cached struct
376 : // pointers.
377 726 : *aSamePointerStructs = 0;
378 :
379 : #define STYLE_STRUCT(name_, callback_) \
380 : { \
381 : const nsStyle##name_* data = PeekStyle##name_(); \
382 : if (!data || data == aNewContext->Style##name_()) { \
383 : *aSamePointerStructs |= NS_STYLE_INHERIT_BIT(name_); \
384 : } \
385 : }
386 : #include "nsStyleStructList.h"
387 : #undef STYLE_STRUCT
388 :
389 : // Note that we do not check whether this->RelevantLinkVisited() !=
390 : // aNewContext->RelevantLinkVisited(); we don't need to since
391 : // nsCSSFrameConstructor::DoContentStateChanged always adds
392 : // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
393 : // needs to, since HasStateDependentStyle probably doesn't work right
394 : // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
395 : // expose whether links are visited to performance tests since all
396 : // link coloring happens asynchronously at a time when it's hard for
397 : // the page to measure.
398 : // However, we do need to compute the larger of the changes that can
399 : // happen depending on whether the link is visited or unvisited, since
400 : // doing only the one that's currently appropriate would expose which
401 : // links are in history to easy performance measurement. Therefore,
402 : // here, we add nsChangeHint_RepaintFrame hints (the maximum for
403 : // things that can depend on :visited) for the properties on which we
404 : // call GetVisitedDependentColor.
405 726 : nsStyleContext *thisVis = GetStyleIfVisited(),
406 726 : *otherVis = aNewContext->GetStyleIfVisited();
407 726 : if (!thisVis != !otherVis) {
408 : // One style context has a style-if-visited and the other doesn't.
409 : // Presume a difference.
410 0 : hint |= nsChangeHint_RepaintFrame;
411 726 : } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
412 : // Bug 1364484: Update comments here and potentially remove the assertion
413 : // below once we return a non-null visited context in CalcStyleDifference
414 : // using Servo values. The approach is becoming quite similar to Gecko.
415 : // We'll handle visited style differently in servo. Assert against being
416 : // in the parallel traversal to avoid static analysis hazards when calling
417 : // StyleFoo() below.
418 0 : MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
419 :
420 : // Both style contexts have a style-if-visited.
421 0 : bool change = false;
422 :
423 : // NB: Calling Peek on |this|, not |thisVis|, since callers may look
424 : // at a struct on |this| without looking at the same struct on
425 : // |thisVis| (including this function if we skip one of these checks
426 : // due to change being true already or due to the old style context
427 : // not having a style-if-visited), but not the other way around.
428 : #define STYLE_FIELD(name_) thisVisStruct->name_ != otherVisStruct->name_
429 : #define STYLE_STRUCT(name_, fields_) \
430 : if (!change && PeekStyle##name_()) { \
431 : const nsStyle##name_* thisVisStruct = thisVis->Style##name_(); \
432 : const nsStyle##name_* otherVisStruct = otherVis->Style##name_(); \
433 : if (MOZ_FOR_EACH_SEPARATED(STYLE_FIELD, (||), (), fields_)) { \
434 : change = true; \
435 : } \
436 : }
437 : #include "nsCSSVisitedDependentPropList.h"
438 : #undef STYLE_STRUCT
439 : #undef STYLE_FIELD
440 :
441 0 : if (change) {
442 0 : hint |= nsChangeHint_RepaintFrame;
443 : }
444 : }
445 :
446 726 : if (hint & nsChangeHint_UpdateContainingBlock) {
447 : // If a struct returned nsChangeHint_UpdateContainingBlock, that
448 : // means that one property's influence on whether we're a containing
449 : // block for abs-pos or fixed-pos elements has changed. However, we
450 : // only need to return the hint if the overall computation of
451 : // whether we establish a containing block has changed.
452 :
453 : // This depends on data in nsStyleDisplay, nsStyleEffects and
454 : // nsStyleSVGReset, so we do it here.
455 :
456 : // Note that it's perhaps good for this test to be last because it
457 : // doesn't use Peek* functions to get the structs on the old
458 : // context. But this isn't a big concern because these struct
459 : // getters should be called during frame construction anyway.
460 6 : if (ThreadsafeStyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
461 : aNewContext->ThreadsafeStyleDisplay()->
462 4 : IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
463 1 : ThreadsafeStyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
464 : aNewContext->ThreadsafeStyleDisplay()->
465 : IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
466 : // While some styles that cause the frame to be a containing block
467 : // has changed, the overall result hasn't.
468 1 : hint &= ~nsChangeHint_UpdateContainingBlock;
469 : }
470 : }
471 :
472 726 : MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
473 : "Added a new hint without bumping AllHints?");
474 726 : return hint & ~nsChangeHint_NeutralChange;
475 : }
476 :
477 : nsChangeHint
478 726 : nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
479 : uint32_t* aEqualStructs,
480 : uint32_t* aSamePointerStructs)
481 : {
482 : return CalcStyleDifferenceInternal(aNewContext,
483 : aEqualStructs,
484 726 : aSamePointerStructs);
485 : }
486 :
487 : class MOZ_STACK_CLASS FakeStyleContext
488 : {
489 : public:
490 0 : explicit FakeStyleContext(const ServoComputedValues* aComputedValues)
491 0 : : mComputedValues(aComputedValues) {}
492 :
493 0 : nsStyleContext* GetStyleIfVisited() {
494 : // Bug 1364484: Figure out what to do here for Stylo visited values. We can
495 : // get the visited computed values:
496 : // RefPtr<ServoComputedValues> visitedComputedValues =
497 : // Servo_ComputedValues_GetVisitedStyle(mComputedValues).Consume();
498 : // But what's the best way to create the nsStyleContext?
499 0 : return nullptr;
500 : }
501 :
502 : #define STYLE_STRUCT(name_, checkdata_cb_) \
503 : const nsStyle##name_ * Style##name_() { \
504 : return Servo_GetStyle##name_(mComputedValues); \
505 : } \
506 : const nsStyle##name_ * ThreadsafeStyle##name_() { \
507 : return Servo_GetStyle##name_(mComputedValues); \
508 : }
509 : #include "nsStyleStructList.h"
510 : #undef STYLE_STRUCT
511 :
512 : private:
513 : const ServoComputedValues* MOZ_NON_OWNING_REF mComputedValues;
514 : };
515 :
516 : nsChangeHint
517 0 : nsStyleContext::CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
518 : uint32_t* aEqualStructs,
519 : uint32_t* aSamePointerStructs)
520 : {
521 0 : FakeStyleContext newContext(aNewComputedValues);
522 : return CalcStyleDifferenceInternal(&newContext,
523 : aEqualStructs,
524 0 : aSamePointerStructs);
525 : }
526 :
527 : namespace mozilla {
528 :
529 : void
530 0 : GeckoStyleContext::EnsureSameStructsCached(nsStyleContext* aOldContext)
531 : {
532 : // NOTE(emilio): We could do better here for stylo, where we only call
533 : // Style##name_() because we need to run FinishStyle, but otherwise this
534 : // is only a bitwise or.
535 : //
536 : // We could reduce the FFI traffic we do only doing it for structs that have
537 : // non-trivial FinishStyle.
538 :
539 : #define STYLE_STRUCT(name_, checkdata_cb_) \
540 : if (aOldContext->PeekStyle##name_()) { \
541 : Style##name_(); \
542 : }
543 : #include "nsStyleStructList.h"
544 : #undef STYLE_STRUCT
545 0 : }
546 :
547 : } // namespace mozilla
548 :
549 : #ifdef DEBUG
550 0 : void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
551 : {
552 0 : nsAutoCString str;
553 : // Indent
554 : int32_t ix;
555 0 : for (ix = aIndent; --ix >= 0; ) {
556 0 : str.AppendLiteral(" ");
557 : }
558 0 : str.Append(nsPrintfCString("%p(%d) parent=%p ",
559 0 : (void*)this, mRefCnt, (void *)mParent));
560 0 : if (mPseudoTag) {
561 0 : nsAutoString buffer;
562 0 : mPseudoTag->ToString(buffer);
563 0 : AppendUTF16toUTF8(buffer, str);
564 0 : str.Append(' ');
565 : }
566 :
567 0 : if (IsServo()) {
568 0 : fprintf_stderr(out, "%s{ServoComputedValues}\n", str.get());
569 0 : } else if (nsRuleNode* ruleNode = AsGecko()->RuleNode()) {
570 0 : fprintf_stderr(out, "%s{\n", str.get());
571 0 : str.Truncate();
572 0 : while (ruleNode) {
573 0 : nsIStyleRule *styleRule = ruleNode->GetRule();
574 0 : if (styleRule) {
575 0 : styleRule->List(out, aIndent + 1);
576 : }
577 0 : ruleNode = ruleNode->GetParent();
578 : }
579 0 : for (ix = aIndent; --ix >= 0; ) {
580 0 : str.AppendLiteral(" ");
581 : }
582 0 : fprintf_stderr(out, "%s}\n", str.get());
583 : }
584 : else {
585 0 : fprintf_stderr(out, "%s{}\n", str.get());
586 : }
587 :
588 0 : if (aListDescendants) {
589 0 : if (GeckoStyleContext* gecko = GetAsGecko()) {
590 0 : gecko->ListDescendants(out, aIndent);
591 : }
592 : }
593 0 : }
594 : #endif
595 :
596 : // Overridden to prevent the global delete from being called, since the memory
597 : // came out of an nsIArena instead of the global delete operator's heap.
598 : void
599 1618 : nsStyleContext::Destroy()
600 : {
601 1618 : if (IsGecko()) {
602 : // Get the pres context.
603 3236 : RefPtr<nsPresContext> presContext = PresContext();
604 : // Call our destructor.
605 1618 : this->AsGecko()->~GeckoStyleContext();
606 : // Don't let the memory be freed, since it will be recycled
607 : // instead. Don't call the global operator delete.
608 : presContext->PresShell()->
609 1618 : FreeByObjectID(eArenaObjectID_GeckoStyleContext, this);
610 : } else {
611 0 : delete static_cast<ServoStyleContext*>(this);
612 : }
613 1618 : }
614 :
615 : already_AddRefed<nsStyleContext>
616 2203 : NS_NewStyleContext(nsStyleContext* aParentContext,
617 : nsIAtom* aPseudoTag,
618 : CSSPseudoElementType aPseudoType,
619 : nsRuleNode* aRuleNode,
620 : bool aSkipParentDisplayBasedStyleFixup)
621 : {
622 4406 : RefPtr<nsRuleNode> node = aRuleNode;
623 : RefPtr<nsStyleContext> context =
624 2203 : new (aRuleNode->PresContext())
625 4406 : GeckoStyleContext(aParentContext, aPseudoTag, aPseudoType, node.forget(),
626 6609 : aSkipParentDisplayBasedStyleFixup);
627 4406 : return context.forget();
628 : }
629 :
630 : namespace mozilla {
631 :
632 : already_AddRefed<ServoStyleContext>
633 0 : ServoStyleContext::Create(nsStyleContext* aParentContext,
634 : nsPresContext* aPresContext,
635 : nsIAtom* aPseudoTag,
636 : CSSPseudoElementType aPseudoType,
637 : already_AddRefed<ServoComputedValues> aComputedValues)
638 : {
639 : RefPtr<ServoStyleContext> context =
640 : new ServoStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
641 0 : Move(aComputedValues));
642 0 : return context.forget();
643 : }
644 :
645 : } // namespace mozilla
646 :
647 : nsIPresShell*
648 16 : nsStyleContext::Arena()
649 : {
650 16 : return PresContext()->PresShell();
651 : }
652 :
653 : template<typename Func>
654 : static nscolor
655 560 : GetVisitedDependentColorInternal(nsStyleContext* aSc, Func aColorFunc)
656 : {
657 : nscolor colors[2];
658 560 : colors[0] = aColorFunc(aSc);
659 560 : if (nsStyleContext* visitedStyle = aSc->GetStyleIfVisited()) {
660 0 : colors[1] = aColorFunc(visitedStyle);
661 : return nsStyleContext::
662 0 : CombineVisitedColors(colors, aSc->RelevantLinkVisited());
663 : }
664 560 : return colors[0];
665 : }
666 :
667 : static nscolor
668 0 : ExtractColor(nsStyleContext* aContext, const nscolor& aColor)
669 : {
670 0 : return aColor;
671 : }
672 :
673 : static nscolor
674 560 : ExtractColor(nsStyleContext* aContext, const StyleComplexColor& aColor)
675 : {
676 560 : return aContext->StyleColor()->CalcComplexColor(aColor);
677 : }
678 :
679 : static nscolor
680 0 : ExtractColor(nsStyleContext* aContext, const nsStyleSVGPaint& aPaintServer)
681 : {
682 0 : return aPaintServer.Type() == eStyleSVGPaintType_Color
683 0 : ? aPaintServer.GetColor() : NS_RGBA(0, 0, 0, 0);
684 : }
685 :
686 : #define STYLE_FIELD(struct_, field_) aField == &struct_::field_ ||
687 : #define STYLE_STRUCT(name_, fields_) \
688 : template<> nscolor \
689 : nsStyleContext::GetVisitedDependentColor( \
690 : decltype(nsStyle##name_::MOZ_ARG_1 fields_) nsStyle##name_::* aField) \
691 : { \
692 : MOZ_ASSERT(MOZ_FOR_EACH(STYLE_FIELD, (nsStyle##name_,), fields_) false, \
693 : "Getting visited-dependent color for a field in nsStyle"#name_ \
694 : " which is not listed in nsCSSVisitedDependentPropList.h"); \
695 : return GetVisitedDependentColorInternal(this, \
696 : [aField](nsStyleContext* sc) { \
697 : return ExtractColor(sc, sc->Style##name_()->*aField); \
698 : }); \
699 : }
700 : #include "nsCSSVisitedDependentPropList.h"
701 : #undef STYLE_STRUCT
702 : #undef STYLE_FIELD
703 :
704 : struct ColorIndexSet {
705 : uint8_t colorIndex, alphaIndex;
706 : };
707 :
708 : static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
709 :
710 : /* static */ nscolor
711 0 : nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
712 : {
713 0 : if (NS_GET_A(aColors[1]) == 0) {
714 : // If the style-if-visited is transparent, then just use the
715 : // unvisited style rather than using the (meaningless) color
716 : // components of the visited style along with a potentially
717 : // non-transparent alpha value.
718 0 : aLinkIsVisited = false;
719 : }
720 :
721 : // NOTE: We want this code to have as little timing dependence as
722 : // possible on whether this->RelevantLinkVisited() is true.
723 : const ColorIndexSet &set =
724 0 : gVisitedIndices[aLinkIsVisited ? 1 : 0];
725 :
726 0 : nscolor colorColor = aColors[set.colorIndex];
727 0 : nscolor alphaColor = aColors[set.alphaIndex];
728 0 : return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
729 : NS_GET_B(colorColor), NS_GET_A(alphaColor));
730 : }
731 :
732 : #ifdef DEBUG
733 : /* static */ const char*
734 0 : nsStyleContext::StructName(nsStyleStructID aSID)
735 : {
736 0 : switch (aSID) {
737 : #define STYLE_STRUCT(name_, checkdata_cb) \
738 : case eStyleStruct_##name_: \
739 : return #name_;
740 : #include "nsStyleStructList.h"
741 : #undef STYLE_STRUCT
742 : default:
743 0 : return "Unknown";
744 : }
745 : }
746 :
747 : /* static */ bool
748 0 : nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
749 : {
750 : if (false)
751 : ;
752 : #define STYLE_STRUCT(name_, checkdata_cb_) \
753 : else if (aName.EqualsLiteral(#name_)) \
754 : aResult = eStyleStruct_##name_;
755 : #include "nsStyleStructList.h"
756 : #undef STYLE_STRUCT
757 : else
758 0 : return false;
759 0 : return true;
760 : }
761 : #endif
762 :
763 : #ifdef DEBUG
764 : /* static */ void
765 3 : nsStyleContext::Initialize()
766 : {
767 : Preferences::AddBoolVarCache(
768 : &sExpensiveStyleStructAssertionsEnabled,
769 3 : "layout.css.expensive-style-struct-assertions.enabled");
770 3 : }
771 : #endif
|