Closed Bug 1368782 Opened 7 years ago Closed 7 years ago

CSS cascading order of @import-ed style sheets is broken (regression from bug 1352968)

Categories

(Core :: CSS Parsing and Computation, defect)

55 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla55
Tracking Status
firefox-esr52 --- unaffected
firefox53 --- unaffected
firefox54 --- unaffected
firefox55 + fixed

People

(Reporter: soeren.hentzschel, Assigned: xidorn)

References

Details

(Keywords: regression)

Attachments

(5 files)

Attached image screenshot.png
There are a lot of style issues on a lot of websites after landing of bug 1352968 (according to mozregression).

Please the the attached screenshot. It shows a phpbb forum with wrong link colors, missing borders around input fields, borders where no borders should be (around the input fields), …

Demo url: https://www.camp-firefox.de/forum/

There are more examples, for example the backend of Pimcore websites. I'll attach a screenshot in a few minutes.
Attached image screenshot2.png
Screenshot of Pimcore CMS, also a lot of obvious style bugs.
[Tracking Requested - why for this release]:
sounds like a regression with potentially big impact
Keywords: regression
OS: Unspecified → All
Hardware: Unspecified → All
Version: 52 Branch → 55 Branch
Attached file testcase.htm
Load this testcase.
Result: red background.
Expected: green background.
My guess is that the code actually depends on the order of child sheets which I changed in bug 1352968. Although the order had already been broken in some case before that, reversing it may make things even worse, I guess.
Assignee: nobody → xidorn+moz
Flags: needinfo?(xidorn+moz)
This is a pretty basic testcase to be broken.  Seems like this requires both (a) prompt fix or backout and (b) a test that actually tests that case.
Flags: needinfo?(xidorn+moz)
Summary: Bug 1352968 brokes the CSS of a lot of websites → CSS cascading order of @import-ed style sheets is broken (regression from bug 1352968)
Reversing the order is a violation of https://drafts.csswg.org/css-cascade-4/#cascade-order

> The last declaration in document order wins. For this purpose:
> 
> - Declarations from imported style sheets are ordered as if their
>   style sheets were substituted in place of the @import rule.
Attached file another testcase
This is a testcase which was already broken before that change because of dependence of child sheet order.
(In reply to Oriol [:Oriol] from comment #6)
> Reversing the order is a violation of
> https://drafts.csswg.org/css-cascade-4/#cascade-order
> 
> > The last declaration in document order wins. For this purpose:
> > 
> > - Declarations from imported style sheets are ordered as if their
> >   style sheets were substituted in place of the @import rule.

Right. I didn't realize that cascading depends on the internal order of child sheet, because that order already didn't reflect the rule order when there are dynamic changes. Thus the testcase I just uploaded was broken before that change.

I think I have an idea about how to fix both cases.
Flags: needinfo?(xidorn+moz)
Comment on attachment 8872845 [details]
Bug 1368782 - Always use rule order for cascading child sheets.

Doesn't this defeat the de-duplication that the CSS loader does?  In other words, didn't we previously call CascadeSheet once if a child sheet was @import-ed twice, and we now do so twice?

Also, does it have any effect on @import loops?

(What broke the order of child sheets, and can it be reverted?)
Flags: needinfo?(xidorn+moz)
Also, does this restore all of the tests in https://www.hixie.ch/tests/evil/css/import/ (both parts) to their behavior prior to bug 1352968?
OK, so yeah, it doesn't work properly with @import loop. I need to think a bit about how to handle this.
(In reply to David Baron :dbaron: ⌚️UTC-7 from comment #11)
> Also, does this restore all of the tests in
> https://www.hixie.ch/tests/evil/css/import/ (both parts) to their behavior
> prior to bug 1352968?

I manually went through hixie's import test with my latest patch, and it seems to me the result is identical to that from the beta version.

(In reply to David Baron :dbaron: ⌚️UTC-7 from comment #10)
> Comment on attachment 8872845 [details]
> Bug 1368782 - Always use rule order for cascading child sheets.
> 
> Doesn't this defeat the de-duplication that the CSS loader does?  In other
> words, didn't we previously call CascadeSheet once if a child sheet was
> @import-ed twice, and we now do so twice?

This has been addressed in the new revision of the patch.

> Also, does it have any effect on @import loops?

An import rule would not have its stylesheet set if there is @import loop involves. See Loader::LoadChildSheet [1] that aGeckoParentRule would get its child sheet only after we finish the checks.

> (What broke the order of child sheets, and can it be reverted?)

Dynamic changes would break the order of child sheets in the linked list. See test 2 and test 3 added in the patch. Both of the two tests fail before bug 1352968.

If we want to keep the order correct in the child sheet linked list... It is doable, but I suspect whether it's worth.


[1] https://dxr.mozilla.org/mozilla-central/rev/39d5cc0fda5e16c49a59d29d4ca186a5534cc88b/layout/style/Loader.cpp#2270-2271
Flags: needinfo?(xidorn+moz)
Comment on attachment 8872845 [details]
Bug 1368782 - Always use rule order for cascading child sheets.

https://reviewboard.mozilla.org/r/144352/#review148190

::: layout/style/nsCSSRuleProcessor.cpp:3740
(Diff revision 2)
> +    auto& rules = aSheet->Inner()->mOrderedRules;
> +    uint32_t i = 0, len = rules.Length();
> +    for (; i < len; i++) {
> +      if (rules[i]->GetType() != css::Rule::IMPORT_RULE) {
> +        break;
> +      }
> +    }

This isn't going to work if there's an @charset rule before the @import rule.  It's also pretty fragile.

::: layout/style/nsCSSRuleProcessor.cpp:3759
(Diff revision 2)
> +        // 2. the sheet has been referenced by another import rule at a
> +        //    later position.

Doesn't this comment imply that the deduplication code isn't necessary at all, and the first patch would be fine?
Attachment #8872845 - Flags: review?(dbaron)
Comment on attachment 8872845 [details]
Bug 1368782 - Always use rule order for cascading child sheets.

https://reviewboard.mozilla.org/r/144352/#review148190

> This isn't going to work if there's an @charset rule before the @import rule.  It's also pretty fragile.

`@charset` doesn't have CSSOM object, so it is never the case. No other rules can be put before import rules, and that is required in the spec, so I don't think there could be any problem here. Also, this is the reason I added the assertion at the top of `CascadeRuleEnumFunc`.

> Doesn't this comment imply that the deduplication code isn't necessary at all, and the first patch would be fine?

I think it is necessary. This check is done explicitly via the hash set, not the check for whether style sheet returned is null.

If an import rule doesn't have stylesheet connected, this behavior itself would violates the spec, I believe. So I think the explicit extra check is necessary if we want to avoid cascading duplicate stylesheet.
Attachment #8872845 - Flags: review?(dbaron)
Comment on attachment 8872845 [details]
Bug 1368782 - Always use rule order for cascading child sheets.

https://reviewboard.mozilla.org/r/144352/#review148198

So two further thoughts:

 1. a hashtable is a rather inefficient structure to use here; it would be more efficient to use booleans on the sheets themselves, perhaps?

 2. this doesn't coalesce multiple sheets except when they're siblings of each other.  For example, a sheet C imported as A->C and A->B->C will still get included twice.

Solving both of them fully seems difficult, though, though switching to solve (1) would solve part of (2).

Hopefully the hashtable inefficiency won't be too big a deal, though.  So I guess r=dbaron.

::: layout/style/nsCSSRuleProcessor.cpp:3758
(Diff revision 2)
> +      for (uint32_t j = i; j > 0; j--) {
> +        auto importRule = static_cast<css::ImportRule*>(rules[j - 1]);
> +        StyleSheet* sheet = importRule->GetStyleSheet();
> +        // There are two cases we want to ignore an import rule:
> +        // 1. the import rule does not have stylesheet connected because
> +        //    it fails in security check or there is a loop involves.

loop involves -> loop involved
Attachment #8872845 - Flags: review?(dbaron) → review+
I wouldn't expect the hashtable to be inefficient here actually. Inefficiency of hashtables are generally from two sides, IIUC: 1. cache miss because of random access in a large memory area, 2. computation of hash key.

For pointer hash key, the computation should be pretty cheap, so the second one shouldn't be an issue. And if there aren't lots of import rules, the hashtable should be pretty small, probably wouldn't be much larger than the array (IIRC, our hash table is usually pretty dense), so I wouldn't expect cache miss to be a significant issue either.
(In reply to David Baron :dbaron: ⌚️UTC-7 from comment #17)
>  2. this doesn't coalesce multiple sheets except when they're siblings of
> each other.  For example, a sheet C imported as A->C and A->B->C will still
> get included twice.

And the previous method which iterates child sheet linked list doesn't do so either, as far as I can see.

It is not terribly hard to do this optimization, I mean, we just need to collect all import rules recursively. But it is not clear to me whether it's really worth.
If we want to avoid hash table, we can do O(n^2) check with the array as well. I don't expect any real website to have thousands of import rules listed in a single sheet, so that would probably be faster than a hash table check in normal cases... but let's don't worry too much about this until it shows up in some profile, I guess.
Pushed by xquan@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/b19afe698a9e
Always use rule order for cascading child sheets. r=dbaron
https://hg.mozilla.org/mozilla-central/rev/b19afe698a9e
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla55
Blocks: 1373559
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: