Attachment #802689: Implement RestyleUndisplayedDescendants that restyles diplay:none children and display:contents descendants. for bug #907396

View | Details | Raw Unified | Return to bug 907396
Collapse All | Expand All

(-)a/layout/base/RestyleManager.cpp (-66 / +94 lines)
Line     Link Here 
 Lines 2072-2088   ElementRestyler::Restyle(nsRestyleHint a Link Here 
2072
  nsRestyleHint childRestyleHint = aRestyleHint;
2072
  nsRestyleHint childRestyleHint = aRestyleHint;
2073
2073
2074
  if (childRestyleHint == eRestyle_Self) {
2074
  if (childRestyleHint == eRestyle_Self) {
2075
    childRestyleHint = nsRestyleHint(0);
2075
    childRestyleHint = nsRestyleHint(0);
2076
  }
2076
  }
2077
2077
2078
  RestyleSelf(aRestyleHint);
2078
  RestyleSelf(aRestyleHint);
2079
2079
2080
  RestyleChildren(childRestyleHint);
2080
  // No need to do this if we're planning to reframe already.
2081
  // It's also important to check mHintsHandled since we use
2082
  // mFrame->StyleContext(), which is out of date if mHintsHandled
2083
  // has a ReconstructFrame hint.  Using an out of date style
2084
  // context could trigger assertions about mismatched rule trees.
2085
  if (!(mHintsHandled & nsChangeHint_ReconstructFrame)) {
2086
    RestyleChildren(childRestyleHint);
2087
  }
2081
}
2088
}
2082
2089
2083
void
2090
void
2084
ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint)
2091
ElementRestyler::RestyleSelf(nsRestyleHint aRestyleHint)
2085
{
2092
{
2086
  // XXXldb get new context from prev-in-flow if possible, to avoid
2093
  // XXXldb get new context from prev-in-flow if possible, to avoid
2087
  // duplication.  (Or should we just let |GetContext| handle that?)
2094
  // duplication.  (Or should we just let |GetContext| handle that?)
2088
  // Getting the hint would be nice too, but that's harder.
2095
  // Getting the hint would be nice too, but that's harder.
 Lines 2346-2362   ElementRestyler::RestyleSelf(nsRestyleHi Link Here 
2346
      }
2353
      }
2347
    }
2354
    }
2348
  }
2355
  }
2349
}
2356
}
2350
2357
2351
void
2358
void
2352
ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
2359
ElementRestyler::RestyleChildren(nsRestyleHint aChildRestyleHint)
2353
{
2360
{
2354
  RestyleUndisplayedChildren(aChildRestyleHint);
2361
  MOZ_ASSERT(!(mHintsHandled & nsChangeHint_ReconstructFrame),
2362
             "No need to do this if we're planning to reframe already.");
2363
2364
  RestyleUndisplayedDescendants(aChildRestyleHint);
2355
2365
2356
  // Check whether we might need to create a new ::before frame.
2366
  // Check whether we might need to create a new ::before frame.
2357
  // There's no need to do this if we're planning to reframe already
2367
  // There's no need to do this if we're planning to reframe already
2358
  // or if we're not forcing restyles on kids.
2368
  // or if we're not forcing restyles on kids.
2359
  // It's also important to check mHintsHandled since we use
2369
  // It's also important to check mHintsHandled since we use
2360
  // mFrame->StyleContext(), which is out of date if mHintsHandled has a
2370
  // mFrame->StyleContext(), which is out of date if mHintsHandled has a
2361
  // ReconstructFrame hint.  Using an out of date style context could
2371
  // ReconstructFrame hint.  Using an out of date style context could
2362
  // trigger assertions about mismatched rule trees.
2372
  // trigger assertions about mismatched rule trees.
 Lines 2386-2480   ElementRestyler::RestyleChildren(nsResty Link Here 
2386
2396
2387
    RestyleContentChildren(aChildRestyleHint);
2397
    RestyleContentChildren(aChildRestyleHint);
2388
2398
2389
    SendAccessibilityNotifications();
2399
    SendAccessibilityNotifications();
2390
  }
2400
  }
2391
}
2401
}
2392
2402
2393
void
2403
void
2394
ElementRestyler::RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint)
2404
ElementRestyler::RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint)
2395
{
2405
{
2396
  // When the root element is display:none, we still construct *some*
2406
  // When the root element is display:none, we still construct *some*
2397
  // frames that have the root element as their mContent, down to the
2407
  // frames that have the root element as their mContent, down to the
2398
  // DocElementContainingBlock.
2408
  // DocElementContainingBlock.
2399
  bool checkUndisplayed;
2409
  bool checkUndisplayed;
2400
  nsIContent* undisplayedParent;
2410
  nsIContent* undisplayedParent;
2401
  nsCSSFrameConstructor* frameConstructor = mPresContext->FrameConstructor();
2402
  if (mFrame->StyleContext()->GetPseudo()) {
2411
  if (mFrame->StyleContext()->GetPseudo()) {
2403
    checkUndisplayed = mFrame == frameConstructor->
2412
    checkUndisplayed = mFrame == mPresContext->FrameConstructor()->
2404
                                   GetDocElementContainingBlock();
2413
                                   GetDocElementContainingBlock();
2405
    undisplayedParent = nullptr;
2414
    undisplayedParent = nullptr;
2406
  } else {
2415
  } else {
2407
    checkUndisplayed = !!mFrame->GetContent();
2416
    checkUndisplayed = !!mFrame->GetContent();
2408
    undisplayedParent = mFrame->GetContent();
2417
    undisplayedParent = mFrame->GetContent();
2409
  }
2418
  }
2410
  if (checkUndisplayed &&
2419
  if (checkUndisplayed) {
2411
      // No need to do this if we're planning to reframe already.
2420
    DoRestyleUndisplayedDescendants(aChildRestyleHint, undisplayedParent);
2412
      // It's also important to check mHintsHandled since we use
2421
  }
2413
      // mFrame->StyleContext(), which is out of date if mHintsHandled
2422
}
2414
      // has a ReconstructFrame hint.  Using an out of date style
2415
      // context could trigger assertions about mismatched rule trees.
2416
      !(mHintsHandled & nsChangeHint_ReconstructFrame)) {
2417
    UndisplayedNode* undisplayed =
2418
      frameConstructor->GetAllUndisplayedContentIn(undisplayedParent);
2419
    for (TreeMatchContext::AutoAncestorPusher
2420
           pushAncestor(undisplayed, mTreeMatchContext,
2421
                        undisplayedParent ? undisplayedParent->AsElement()
2422
                                          : nullptr);
2423
         undisplayed; undisplayed = undisplayed->mNext) {
2424
      NS_ASSERTION(undisplayedParent ||
2425
                   undisplayed->mContent ==
2426
                     mPresContext->Document()->GetRootElement(),
2427
                   "undisplayed node child of null must be root");
2428
      NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
2429
                   "Shouldn't have random pseudo style contexts in the "
2430
                   "undisplayed map");
2431
2423
2432
      // Get the parent of the undisplayed content and check if it is a XBL
2424
void
2433
      // children element. Push the children element as an ancestor here because it does
2425
ElementRestyler::DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
2434
      // not have a frame and would not otherwise be pushed as an ancestor.
2426
                                                 nsIContent* aParent)
2435
      nsIContent* parent = undisplayed->mContent->GetParent();
2427
{
2436
      bool pushInsertionPoint = parent && parent->IsActiveChildrenElement();
2428
  nsCSSFrameConstructor* fc = mPresContext->FrameConstructor();
2437
      TreeMatchContext::AutoAncestorPusher
2429
  UndisplayedNode* nodes = fc->GetAllUndisplayedContentIn(aParent);
2438
        insertionPointPusher(pushInsertionPoint,
2430
  RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
2439
                             mTreeMatchContext,
2431
                          NS_STYLE_DISPLAY_NONE);
2440
                             parent && parent->IsElement() ? parent->AsElement() : nullptr);
2432
  nodes = fc->GetAllDisplayContentsIn(aParent);
2433
  RestyleUndisplayedNodes(aChildRestyleHint, nodes, aParent,
2434
                          NS_STYLE_DISPLAY_CONTENTS);
2435
}
2441
2436
2442
      nsRestyleHint thisChildHint = aChildRestyleHint;
2437
void
2443
      RestyleTracker::RestyleData undisplayedRestyleData;
2438
ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint    aChildRestyleHint,
2444
      if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
2439
                                         UndisplayedNode* aUndisplayed,
2445
                                         &undisplayedRestyleData)) {
2440
                                         nsIContent*      aUndisplayedParent,
2446
        thisChildHint =
2441
                                         const uint8_t    aDisplay)
2447
          nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
2442
{
2448
      }
2443
  nsIContent* undisplayedParent = aUndisplayedParent;
2449
      nsRefPtr<nsStyleContext> undisplayedContext;
2444
  UndisplayedNode* undisplayed = aUndisplayed;
2450
      nsStyleSet* styleSet = mPresContext->StyleSet();
2445
  for (TreeMatchContext::AutoAncestorPusher
2451
      if (thisChildHint) {
2446
         pushAncestor(undisplayed, mTreeMatchContext,
2452
        undisplayedContext =
2447
                      undisplayedParent ? undisplayedParent->AsElement()
2453
          styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
2448
                                        : nullptr);
2454
                                    mFrame->StyleContext(),
2449
       undisplayed; undisplayed = undisplayed->mNext) {
2455
                                    mTreeMatchContext);
2450
    NS_ASSERTION(undisplayedParent ||
2456
      } else {
2451
                 undisplayed->mContent ==
2457
        undisplayedContext =
2452
                   mPresContext->Document()->GetRootElement(),
2458
          styleSet->ReparentStyleContext(undisplayed->mStyle,
2453
                 "undisplayed node child of null must be root");
2459
                                         mFrame->StyleContext(),
2454
    NS_ASSERTION(!undisplayed->mStyle->GetPseudo(),
2460
                                         undisplayed->mContent->AsElement());
2455
                 "Shouldn't have random pseudo style contexts in the "
2461
      }
2456
                 "undisplayed map");
2462
      const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
2457
2463
      if (display->mDisplay != NS_STYLE_DISPLAY_NONE) {
2458
    // Get the parent of the undisplayed content and check if it is a XBL
2464
        NS_ASSERTION(undisplayed->mContent,
2459
    // children element. Push the children element as an ancestor here because it does
2465
                     "Must have undisplayed content");
2460
    // not have a frame and would not otherwise be pushed as an ancestor.
2466
        mChangeList->AppendChange(nullptr, undisplayed->mContent,
2461
    nsIContent* parent = undisplayed->mContent->GetParent();
2467
                                  NS_STYLE_HINT_FRAMECHANGE);
2462
    bool pushInsertionPoint = parent && parent->IsActiveChildrenElement();
2468
        // The node should be removed from the undisplayed map when
2463
    TreeMatchContext::AutoAncestorPusher
2469
        // we reframe it.
2464
      insertionPointPusher(pushInsertionPoint,
2470
      } else {
2465
                           mTreeMatchContext,
2471
        // update the undisplayed node with the new context
2466
                           parent && parent->IsElement() ? parent->AsElement() : nullptr);
2472
        undisplayed->mStyle = undisplayedContext;
2467
2468
    nsRestyleHint thisChildHint = aChildRestyleHint;
2469
    RestyleTracker::RestyleData undisplayedRestyleData;
2470
    if (mRestyleTracker.GetRestyleData(undisplayed->mContent->AsElement(),
2471
                                       &undisplayedRestyleData)) {
2472
      thisChildHint =
2473
        nsRestyleHint(thisChildHint | undisplayedRestyleData.mRestyleHint);
2474
    }
2475
    nsRefPtr<nsStyleContext> undisplayedContext;
2476
    nsStyleSet* styleSet = mPresContext->StyleSet();
2477
    if (thisChildHint) {
2478
      undisplayedContext =
2479
        styleSet->ResolveStyleFor(undisplayed->mContent->AsElement(),
2480
                                  mFrame->StyleContext(),
2481
                                  mTreeMatchContext);
2482
    } else {
2483
      undisplayedContext =
2484
        styleSet->ReparentStyleContext(undisplayed->mStyle,
2485
                                       mFrame->StyleContext(),
2486
                                       undisplayed->mContent->AsElement());
2487
    }
2488
    const nsStyleDisplay* display = undisplayedContext->StyleDisplay();
2489
    if (display->mDisplay != aDisplay) {
2490
      NS_ASSERTION(undisplayed->mContent, "Must have undisplayed content");
2491
      mChangeList->AppendChange(nullptr, undisplayed->mContent,
2492
                                NS_STYLE_HINT_FRAMECHANGE);
2493
      // The node should be removed from the undisplayed map when
2494
      // we reframe it.
2495
    } else {
2496
      // update the undisplayed node with the new context
2497
      undisplayed->mStyle = undisplayedContext;
2498
2499
      if (aDisplay == NS_STYLE_DISPLAY_CONTENTS) {
2500
        DoRestyleUndisplayedDescendants(aChildRestyleHint, undisplayed->mContent);
2473
      }
2501
      }
2474
    }
2502
    }
2475
  }
2503
  }
2476
}
2504
}
2477
2505
2478
void
2506
void
2479
ElementRestyler::RestyleBeforePseudo()
2507
ElementRestyler::RestyleBeforePseudo()
2480
{
2508
{
(-)a/layout/base/RestyleManager.h (-1 / +9 lines)
Line     Link Here 
 Lines 17-32    Link Here 
17
#include "nsPresContext.h"
17
#include "nsPresContext.h"
18
18
19
class nsRefreshDriver;
19
class nsRefreshDriver;
20
class nsIFrame;
20
class nsIFrame;
21
struct TreeMatchContext;
21
struct TreeMatchContext;
22
22
23
namespace mozilla {
23
namespace mozilla {
24
24
25
struct UndisplayedNode;
26
25
namespace dom {
27
namespace dom {
26
  class Element;
28
  class Element;
27
} // namespace dom
29
} // namespace dom
28
30
29
class RestyleManager MOZ_FINAL
31
class RestyleManager MOZ_FINAL
30
{
32
{
31
public:
33
public:
32
  friend class ::nsRefreshDriver;
34
  friend class ::nsRefreshDriver;
 Lines 338-354   private: Link Here 
338
   */
340
   */
339
  void CaptureChange(nsStyleContext* aOldContext,
341
  void CaptureChange(nsStyleContext* aOldContext,
340
                     nsStyleContext* aNewContext,
342
                     nsStyleContext* aNewContext,
341
                     nsChangeHint aChangeToAssume);
343
                     nsChangeHint aChangeToAssume);
342
344
343
  /**
345
  /**
344
   * Helpers for RestyleChildren().
346
   * Helpers for RestyleChildren().
345
   */
347
   */
346
  void RestyleUndisplayedChildren(nsRestyleHint aChildRestyleHint);
348
  void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint);
349
  void DoRestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint,
350
                                       nsIContent* aParent);
351
  void RestyleUndisplayedNodes(nsRestyleHint    aChildRestyleHint,
352
                               UndisplayedNode* aUndisplayed,
353
                               nsIContent*      aUndisplayedParent,
354
                               const uint8_t    aDisplay);
347
  void RestyleBeforePseudo();
355
  void RestyleBeforePseudo();
348
  void RestyleAfterPseudo();
356
  void RestyleAfterPseudo();
349
  void RestyleContentChildren(nsRestyleHint aChildRestyleHint);
357
  void RestyleContentChildren(nsRestyleHint aChildRestyleHint);
350
  void InitializeAccessibilityNotifications();
358
  void InitializeAccessibilityNotifications();
351
  void SendAccessibilityNotifications();
359
  void SendAccessibilityNotifications();
352
360
353
  enum DesiredA11yNotifications {
361
  enum DesiredA11yNotifications {
354
    eSkipNotifications,
362
    eSkipNotifications,
(-)a/layout/base/nsCSSFrameConstructor.cpp (+3 lines)
Line     Link Here 
 Lines 8284-8299   static bool EqualURIs(mozilla::css::URLV Link Here 
8284
         (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
8284
         (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
8285
}
8285
}
8286
8286
8287
nsresult
8287
nsresult
8288
nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
8288
nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
8289
{
8289
{
8290
  nsRefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement);
8290
  nsRefPtr<nsStyleContext> oldContext = GetUndisplayedContent(aElement);
8291
  if (!oldContext) {
8291
  if (!oldContext) {
8292
    if ((oldContext = GetDisplayContents(aElement))) {
8293
        NS_ERROR("MaybeRecreateFramesForElement GetDisplayContents");
8294
    }
8292
    return NS_OK;
8295
    return NS_OK;
8293
  }
8296
  }
8294
8297
8295
  // The parent has a frame, so try resolving a new context.
8298
  // The parent has a frame, so try resolving a new context.
8296
  nsRefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
8299
  nsRefPtr<nsStyleContext> newContext = mPresShell->StyleSet()->
8297
    ResolveStyleFor(aElement, oldContext->GetParent());
8300
    ResolveStyleFor(aElement, oldContext->GetParent());
8298
8301
8299
  ChangeUndisplayedContent(aElement, newContext);
8302
  ChangeUndisplayedContent(aElement, newContext);

Return to bug 907396