Closed Bug 1784022 Opened 2 years ago Closed 2 years ago

Convert text-emphasis-position #defines to enum classes.

Categories

(Core :: CSS Parsing and Computation, task)

task

Tracking

()

RESOLVED FIXED
107 Branch
Tracking Status
firefox107 --- fixed

People

(Reporter: anurag.kalia, Assigned: anurag.kalia)

References

Details

Attachments

(1 file, 1 obsolete file)

+++ This bug was initially created as a clone of Bug #1625745 +++

Depends on: 1277133
Blocks: 1277133
No longer depends on: 1277133

@emilio: I would like to work on this bug, but I am not sure how to assign it to myself. Once this goes through, I will work on similar tasks.

Hi Anurag! The bug should be auto-assigned to you when you submit a patch. Let me know if you need any help with that.

Sure! I have taken a deep dive into the code. Before I dive further and implement this, I wanted to run my approach by you once.

First of all, I see a bug in the current implementation. According to the spec (https://drafts.csswg.org/css-text-decor/#text-emphasis-position-property), Valid rule is [ over | under ] && [ right | left ]? but in the current implementation right | left is a required param. I intend to fix it in the same patch.

Now, over to the implementation:

  1. Because there are two groups (over | under) and (right | left), I intend to use bitflags! macro for the same and intend to derive it using #css(bitflags(...)) ala servo/components/style/values/specified/box.rs#ScrollbarGutter.
  2. Moreover, the current use case is not well-supported by #css(bitflags(...)). Specifically, we do not have any single flag and we need to supply right|left automatically in their absence. Hence, I intend to modify bitflags derivation too by adding a new flag_groups attribute that specifies various groups of mixed flags (2 groups - left|right and over|under in this case), specifies whether each group is required, and specifies whether each group has a default flag in case it is optional.
Flags: needinfo?(emilio)

Let me also know if the explanation is confusing and how to format it to make it more readable.

(In reply to Anurag Kalia from comment #3)

Sure! I have taken a deep dive into the code. Before I dive further and implement this, I wanted to run my approach by you once.

First of all, I see a bug in the current implementation. According to the spec (https://drafts.csswg.org/css-text-decor/#text-emphasis-position-property), Valid rule is [ over | under ] && [ right | left ]? but in the current implementation right | left is a required param. I intend to fix it in the same patch.

So, that's worth fixing (and other browsers do accept the optional param, see https://wpt.fyi/results/css/css-text-decor/parsing/text-emphasis-position-computed.html). However it might be worth doing it in a follow-up bug instead (just to focus on the refactoring on this one, and then changing behavior on another bug, wdyt?).

Now, over to the implementation:

  1. Because there are two groups (over | under) and (right | left), I intend to use bitflags! macro for the same and intend to derive it using #css(bitflags(...)) ala servo/components/style/values/specified/box.rs#ScrollbarGutter.

That sounds good.

  1. Moreover, the current use case is not well-supported by #css(bitflags(...)). Specifically, we do not have any single flag and we need to supply right|left automatically in their absence. Hence, I intend to modify bitflags derivation too by adding a new flag_groups attribute that specifies various groups of mixed flags (2 groups - left|right and over|under in this case), specifies whether each group is required, and specifies whether each group has a default flag in case it is optional.

Is this needed? I'd rather avoid complicating the derive code unless we have multiple use cases for it. At a glance, it seems we can avoid such complications with the existing infrastructure, with a small tweak:

We'd mark all the flags as mixed flags, and then validate_mixed can take care of rejecting invalid groups:

impl TextEmphasisPosition {
    fn has_exactly_one_of(&self, left: Self, right: Self) {
        self.intersects(left | right) && !self.contains(left | right)
    }
    fn validate(&self) -> bool {
        self.has_exactly_one_of(Self::OVER, Self::UNDER) && self.has_exactly_one_of(Self::LEFT, Self::RIGHT)
    }
}

That should be enough for our refactoring purposes.

Then in the bug where we make left | right optional, we can change the derive code to pass a mutable reference, and instead do:

fn validate(&mut self) -> bool {
    if !self.has_exactly_one_of(Self::OVER, Self::UNDER) {
        return false;
    }
    if self.intersects(Self::LEFT) {
        return !self.intersects(Self::RIGHT);
    }
    self.remove(Self::RIGHT); // Right is optional and shouldn't be serialized.
    true
}

What do you think? That should be simpler, at a glance, and avoids over-generalizing. If we end up with more flags that need this infrastructure and it becomes complicated to maintain we can add support to the derive code, but till then I think this is more preferable.

Flags: needinfo?(emilio) → needinfo?(anurag.kalia)

It makes sense to me and thank you for the wpt dashboard. Did not know something like this existed! I will only do refactoring in this ticket.

Just a small question for the followup validate function. The only valid states afterwards will be: OVER, UNDER, OVER LEFT and UNDER LEFT, if I understand correctly. Can we tweak it to the following?

fn validate(&mut self) -> bool {
    if !self.has_exactly_one_of(Self::OVER, Self::UNDER) {
        return false;
    }
    if self.intersects(Self::LEFT) {
        return !self.intersects(Self::RIGHT);
    }
    self.set(Self::RIGHT); // Right is optional and should be serialized if LEFT does not exist.
    true
}

This will help avoid surprises in usages like this:

(mTextEmphasisPosition & StyleTextEmphasisPosition::RIGHT
? eSideRight
: eSideLeft)

Devs will have to constantly keep remembering RIGHT is optional when the struct does not lend that information readily. But it is possible I am overthinking this and the codebase may have many other examples for the same without problems. 

Anyway, this is a very minor point and I agree with your general approach for now. I will start with it. Thank you for the patience!
Flags: needinfo?(anurag.kalia) → needinfo?(emilio)

Yeah, I think what we should do is probably just not generate StyleTextEmphasisPosition::RIGHT in C++, or add a convenient mozilla::Side Side() const; function or something. The reason why we can't add RIGHT unconditionally if not present is that we should serialize to the shortest form, so if you write over right, we should serialize back just over.

Flags: needinfo?(emilio)
Assignee: nobody → anurag.kalia
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Attachment #9291219 - Attachment is obsolete: true

They already have some bugs on file. They seem intermittent and totally unrelated to your changes, so patch looks good to land. Thanks!

Flags: needinfo?(emilio)

Hi! Just one very last question on this. The lando link says "There has been no attempt to land revisions in this stack. " I am under the impression I don't have access to it. What happens now to get this merged in the main code repo?

Flags: needinfo?(emilio)

Err, d'oh, I just forgot to click the land button for you. You should consider applying for L1 commit access (that would give you try access, see https://www.mozilla.org/en-US/about/governance/policies/commit/access-policy/). I'd be happy to vouch for you. You can get L3 access after a while, and then you can land your own patches. Till then, asking me or someone else to land it is totally fine :)

Flags: needinfo?(emilio)
Pushed by ealvarez@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/edeb8da0c39b
[refactor] Convert text-emphasis-position #defines to enum classes r=emilio
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 107 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: