Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another take on implementing CSS variables (custom properties) #3314

Merged
merged 15 commits into from
Feb 17, 2024

Conversation

Neograph734
Copy link
Contributor

I have always thought this would be difficult because of the time #1872 is already open, but thanks tmolitor-stud-tu for showing how easy it actually is in #3255.

The approach there was a great start, but it was missing the possibility to use fallback values as a second parameter of var(). Furthermore I have shuffled some assignments around and wrote tests. Please share your thoughts.

@Neograph734
Copy link
Contributor Author

Funny how the tests do pass on my local machine :/

@bsweeney bsweeney added this to the 2.1.1 milestone Nov 3, 2023
@Mellthas
Copy link
Member

Mellthas commented Nov 5, 2023

Funny how the tests do pass on my local machine :/

CI failed with undefined index notices on PHP 7.3, here’s the output:

There were 6 errors
1) Dompdf\Tests\Css\StyleTest::testVar with data set "invalid_value" ('Helvetica', 'var(--undefined)', 'Helvetica')
Undefined index: --undefined

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1244
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1661
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1083
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

2) Dompdf\Tests\Css\StyleTest::testInheritedVar with data set "green" (0, '#00ff00FF')
Undefined index: --fallback-propert

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1250
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1283
/home/runner/work/dompdf/dompdf/src/Css/Stylesheet.php:1069
/home/runner/work/dompdf/dompdf/src/Dompdf.php:731
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1164
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

3) Dompdf\Tests\Css\StyleTest::testInheritedVar with data set "red" (1, '#ff0000FF')
Undefined index: --fallback-propert

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1250
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1283
/home/runner/work/dompdf/dompdf/src/Css/Stylesheet.php:1069
/home/runner/work/dompdf/dompdf/src/Dompdf.php:731
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1164
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

4) Dompdf\Tests\Css\StyleTest::testInheritedVar with data set "yellow" (2, '#ffff00FF')
Undefined index: --fallback-propert

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1250
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1283
/home/runner/work/dompdf/dompdf/src/Css/Stylesheet.php:1069
/home/runner/work/dompdf/dompdf/src/Dompdf.php:731
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1164
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

5) Dompdf\Tests\Css\StyleTest::testInheritedVar with data set "blue" (3, '#0000ffFF')
Undefined index: --fallback-propert

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1250
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1283
/home/runner/work/dompdf/dompdf/src/Css/Stylesheet.php:1069
/home/runner/work/dompdf/dompdf/src/Dompdf.php:731
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1164
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

6) Dompdf\Tests\Css\StyleTest::testInheritedVar with data set "purple" (4, '#ff00ffFF')
Undefined index: --fallback-propert

/home/runner/work/dompdf/dompdf/src/Css/Style.php:1235
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1250
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1694
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1723
/home/runner/work/dompdf/dompdf/src/Css/Style.php:1283
/home/runner/work/dompdf/dompdf/src/Css/Stylesheet.php:1069
/home/runner/work/dompdf/dompdf/src/Dompdf.php:731
/home/runner/work/dompdf/dompdf/tests/Css/StyleTest.php:1164
phpvfscomposer:///home/runner/work/dompdf/dompdf/vendor/phpunit/phpunit/phpunit:106

When running locally on PHP 8.2, I get several deprecation notices (need to pass --display-deprecations when using PHPUnit 10).

@bsweeney
Copy link
Member

bsweeney commented Nov 5, 2023

Approved running the tests so you can see any failures as you make updates.

@bsweeney bsweeney mentioned this pull request Nov 5, 2023
Copy link
Member

@bsweeney bsweeney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some initial thoughts for discussion. I haven't thoroughly evaluated this in relation to the spec nor in relation to how we generally parse CSS properties.

src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Stylesheet.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
@Neograph734
Copy link
Contributor Author

Awsome, those 3 tests fail locally as well because the border shorthand property is never running compute_prop(). That's enough for today.

src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
@Neograph734
Copy link
Contributor Author

Neograph734 commented Nov 8, 2023

Thanks for all the reviews, but I am getting the feeling that the different conversations are getting mixed (and duplicated). So I am struggling to keep up...

I'm happy to push the adjustments I tried locally that appear to resolve current issues.

Feel free to commit what you have, I believe you have the required permissions. I don't want to break anything of your work in an attempt to close some of the above threads.

@bsweeney
Copy link
Member

bsweeney commented Nov 8, 2023

Thanks for all the reviews, but I am getting the feeling that the different conversations are getting mixed (and duplicated). So I am struggling to keep up...

Yes, I noticed that. My apologies. I dunno what happened I think I somehow started a new review when I was commenting on another thread. And then I made a similar comment twice. 😞

I'm happy to push the adjustments I tried locally that appear to resolve current issues.

Feel free to commit what you have, I believe you have the required permissions. I don't want to break anything of your work in an attempt to close some of the above threads.

I'll make those changes and resolve a few conversations.

@bsweeney
Copy link
Member

bsweeney commented Nov 17, 2023

OK I've added changes that handle recursion plus improve variable resolution dependency. @Neograph734 you'll want to re-clone or hard reset your local repo since I rewrote the history to avoid potential complications with merging (after I royally flubbed it earlier).

The dependency logic is kinda kludgey, but I was having trouble finding a better way to handle it. I have a vague idea about how to improve the dependency handling in set_prop but I don't think I'm able to sufficiently articulate it right now. Plus the direction I'm thinking would require a change to the internal structure of the Style class related to specified properties.

I added some test cases to cover some scenarios that weren't working previously. The document I was using to test things follows.

sample document
<style>
    :root {
        --color: orange;
    }
</style>


<style>
    .border {
        font-size: var(--color);
        border: 2px solid var(--color);
        --color: green;
    }
    .inherit {
        border: inherit;
    }
</style>
<p class="border"><span class="inherit">inherit (green)</span></p>

<style>
    .merge {
        border: 2px solid var(--color);
        --color: green;
    }
    p.merge {
        --color: blue;
    }
</style>
<p class="merge">merge (blue)</p>

<style>
    .specific {
        border: 2px solid var(--color);
        border-color: red;
        --color: blue;
    }
</style>
<p class="specific">specific (red)</p>

<style>
    .specific2 {
        border: 2px solid var(--color);
        border-top-color: red;
        --color: blue;
    }
</style>
<p class="specific2">specific2 (blue, red top)</p>

<style>
    .specific3 {
        border-top-color: red;
        border: 2px solid var(--color);
        --color: blue;
    }
</style>
<p class="specific3">specific3 (blue)</p>

<style>
    .twice {
        border: 2px solid var(--color);
        --color: red;
        --color: purple;
    }
</style>
<p class="twice">twice (purple)</p>

<style>
    .multiple {
        border: 2px var(--style) var(--color);
        --style: dashed;
    }
</style>
<p class="multiple">multiple (orange dashed)</p>

<style>
    .nested {
        border: var(--border-specification);
        --border-specification: 2px solid var(--bg);
        --bg: #ff0000FF;
    }
</style>
<p class="nested">nested (red)</p>

<style>
    .important-prop {
        --color: red;
        border: 2px solid var(--color) !important;
    }
    p.important-prop {
        border-color: green;
    }
</style>
<p class="important-prop">important prop (red)</p>

<style>
    .important-var {
        --color: blue !important;
    }
    p.important-var {
        border: 2px solid var(--color);
        --color: green;
    }
</style>
<p class="important-var">important var (blue)</p>

<style>
    .undef {
        font-size: var(--undef);
    }
</style>
<p class="bad">bad (none)</p>

<style>
    .unset {
        --color: unset;
        border: 2px solid var(--color);
    }
</style>
<p class="unset">unset (orange)</p>

<style>
    .initial {
        --color: initial;
        border: 2px solid var(--color);
    }
</style>
<p class="initial">initial (none)</p>

<style>
    .recurse {
        --one: var(--two);
        --two: var(--one);
    }
</style>

<style>
    .recurse-with-fallback {
        --one: var(--two);
        --two: var(--one, black);
    }
</style>

<style>
    .recurse-with-recursive-fallback {
        --one: var(--two, var(--two));
        --two: var(--one, var(--one));
    }
</style>

<style>
    .recurse-self {
        --one: var(--one, black);
    }
</style>

<style>
    .recurse-self-with-fallback {
        --one: var(--one, black);
    }
</style>

<style>
    .recurse-self-with-recursive-self-fallback {
        --one: var(--one, var(--one));
    }
</style>

<style>
    .recurse-self-with-recursive-self-fallback-with-fallback {
        --one: var(--one, var(--one, black));
    }
</style>

src/Css/Stylesheet.php Outdated Show resolved Hide resolved
@Neograph734
Copy link
Contributor Author

I have just implemented this in my development environment. This obviously contains much more CSS than the test cases, but I must say that it appears to work quite good. My color variables all neatly resolve. Thanks for giving this the last push Brian!

By the way, I cannot find that last requested change that github is complaining about...

@bsweeney
Copy link
Member

Glad it's working well for you as well.

I think that change request is just because I haven't updated my review so it's still reporting that I have requested changes. I added an approval review to make that go away. I have some other things I need to work on so I'll let this incubate a little longer in case anybody else has suggestions.

@bsweeney bsweeney modified the milestones: 2.1.1, 2.1.0 Nov 27, 2023
Copy link
Member

@Mellthas Mellthas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don’t have the time for a full review currently, so just some minor review comments for now.

src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
src/Css/Style.php Outdated Show resolved Hide resolved
- fixes important property check
- improves handling of important properties with regard to variable resolution
- improves unset and initial keyword handling for variables
@Neograph734
Copy link
Contributor Author

Neograph734 commented Dec 18, 2023

I was wondering, we have introduced a lot of different variants of:

substr($prop, 0, 2) === "--"
substr($prop, 0, 2) !== "--")
!substr($prop, 0, 2) == "--"

I am tempted to create a regex pattern for it, to bring it more in line with the rest of the code. At the same time I always learned that regex is slow. I am not sure if performance or code readbility is more important here. A small is_custom_property() function to wrap substr might also work?

Similarly, on line 1559 of Style.php we might want to use the self::CSS_VAR pattern instead of strpos($val, 'var(') !== false)?

@bsweeney
Copy link
Member

bsweeney commented Jan 8, 2024

I am tempted to create a regex pattern for it, to bring it more in line with the rest of the code. At the same time I always learned that regex is slow. I am not sure if performance or code readbility is more important here. A small is_custom_property() function to wrap substr might also work?

Performance is always top of mind, but I think we're safe adding a wrapper function to improve maintainability. I would expect that would be a compiler optimizable call.

Similarly, on line 1559 of Style.php we might want to use the self::CSS_VAR pattern instead of strpos($val, 'var(') !== false)?

Yes, that makes sense. We should use consistent logic to ensure that the code is more maintainable.

src/Css/Style.php Outdated Show resolved Hide resolved
@bsweeney
Copy link
Member

bsweeney commented Feb 2, 2024

I think we're brought this far enough, though I'm sure we could continue to optimize. I'll merge next week if no further updates or feedback are forthcoming.

@Neograph734
Copy link
Contributor Author

Great news, much appreciated!
I have nothing to add anymore.

@bsweeney bsweeney linked an issue Feb 17, 2024 that may be closed by this pull request
@bsweeney bsweeney merged commit e1d262b into dompdf:master Feb 17, 2024
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CSS variables
3 participants