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

Add preliminary support for MathML #577

Merged
merged 9 commits into from
Mar 18, 2021
Merged

Conversation

tneotia
Copy link
Collaborator

@tneotia tneotia commented Mar 8, 2021

Fixes #219

I know we are trying to reduce the number of packages this library depends on, but I really think flutter_math is a good addition - I'm super pleased with how the implementation turned out!

image

I added support for a "custom" tag in the second commit. I know we are trying to adhere to HTML standard as close as possible, but I thought it would be a nice feature to directly add Tex support inside HTML if we are already using a package to render math using Tex strings. This is also useful for #207 as a temporary workaround until we decide to implement external CSS support (if that's even possible). If this doesn't seem like a good feature then I can revert the commit.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 10, 2021

Adding support for flutter_math will be very helpful in the long run. I needed support for some vertical-align in #556 which was only because I was converting tex to SVG images. This feature will render Math like a native widget which is much better than using SVGs.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 10, 2021

That's great @ngaurav! - since you use this feature, do you mind testing this PR against your tex strings and your Html implementation? If you find any issues please let me know.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 10, 2021

@tneotia Sure I will be happy to help.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 11, 2021

I was surprised to not find any issue till now in rendering. It truly delivers. One minor issue is that the tex part is always rendered in a new line. I hope this can be fixed, as shown here. Once that is done, then it remains to be seen if the alignment with the baseline is perfect on not.

Here is a sample code:
"<tex>10^5</tex> clones of Agent Smith are present in Matrix, a computer generated world. This number doubles in 25 hours. The doubled time increases by 5 hours for every subsequent double time. (Eg., the second double occurs in 30 hours, the third in 35 hours and so on.) If the number of clones of Agent Smith at time T is <tex>10^8</tex>, which of the following is the best approximation for T?"

Here is how it is rendered currently. It should ideally be inline.
WhatsApp Image 2021-03-12 at 1 32 13 AM

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 12, 2021

Simple fix, this was in place for mathML since the <math> tags don't render inline. However the baseline is not perfect:

image

It seems it is aligning slightly down:

image

It's very close though... I'll see if there's a way to improve it.

Edit: This is the result with 3.5 bottom padding:

image

This is pushed here, can you try it out again @ngaurav and see how it looks for more complex Tex?

image

I made it so that inline Tex is rendered with text style and height in mind so the baseline looks good, while tex by itself renders in the large display font. This is not pushed here yet so let me know your thoughts trying the implementation pushed right now compared to the above screenshot.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 12, 2021

We need to verify if vertical alignment is solved for all kinds of tex code. Try to render the following code. If it works, we can go ahead.
"What the value of <tex>\dfrac{a^3+b^3}{(a+b)(a^3+b^3)-(a-b)^2(a^2-ab+b^2)}</tex>?"

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 12, 2021

@ngaurav I don't know exactly how it should look but this is the result from the current implementation:

image

What do you think?

case "math":
return MathElement(
element: element,
texStr: r'',
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: wouldn't null make more sense than an empty string?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree, I changed it. The latest commit also has some extra changes for styling, if you'd like to review that.

pubspec.yaml Outdated
@@ -29,7 +29,10 @@ dependencies:
chewie_audio: ^1.2.0

# Plugins for rendering the <svg> tag.
flutter_svg: ^0.21.0-nullsafety.0
flutter_svg: ^0.20.0-nullsafety.3
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we need the downgrade here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

flutter_math was constrained to 0.20.0, I changed the dependency to flutter_math_fork because flutter_math hasn't been maintained for a bit. It's essentially the same but has a hotfix for an error occurring on Flutter 2.0.0+.

pubspec.yaml Outdated
flutter_svg: ^0.20.0-nullsafety.3

# Plugin for rendering MathML
flutter_math: ^0.3.0-nullsafety.1
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another external dependency... I should really start work on the modularization.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was watching flutter_widget_from_html and its just completed modularization... It uses widget factories (I still don't know what these are and how they work) and forks of each dependency as an "add-on" to the original lib.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

@tneotia I think the baseline rendering is fine when we use a bottom padding of 3.5. But I would like to test it myself. I am using /tneotia/flutter_html currently and the <tex> tags method is still not displaying content in inline mode.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 15, 2021

Hm did you pull the latest changes? It should display inline.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

Yes, I did clean my pub cache, and also did flutter clean. I still don't see tex in inline. Can you point me to simple fix (commit) which enabled inline.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 15, 2021

@ngaurav This one added it at first, then this one improved it.

Maybe it doesn't work for your HTML, if you have those changes if you can put your HTML here so I can fix it that would be great.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

Thanks, it helped. I just changed the condition element.localName == "math" || element.parent!.localName == "body" ? to element.localName == "math"

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

I just analyzed all my use cases. The flutter_math library is perfect as it covers all the major latex features. But, the issue of baseline alignment is still there. I removed the bottom padding of 3.5, to see what is the default rule of rendering latex in html. I found that latex widgets are center aligned with the rest of the text. So, if there is a script where we have few superscripts and no subscripts, then it will appear aligned with some bottom padding. But, if there is some text where there is only subscripts then it will appear above the baseline, and to make align it with baseline you need padding on the top. Here are some screenshots (without any padding).
Screenshot_20210316-004438
Screenshot_20210316-004338
Screenshot_20210316-004235

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

A generic fix for this alignment issue is to allow support for vertical-align css as mentioned in #556

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 15, 2021

I see... So would you say it's acceptable for now (and we do vertical align in a separate PR) or should any changes be made in this PR?

@ngaurav
Copy link
Contributor

ngaurav commented Mar 15, 2021

Technically this PR is sound but one change is necessary – Bottom padding of 3.5 should be removed. Also, there are two issues where discretion needs to be exercised:

  1. As seen in the screenshot, there was a right overflow. One option is to set max-width using media query. But it can also be left to the users of this library to ensure that their latex widgets are not too large.
  2. I was having issues in inline rendering which was fixed when I removed the code || element.parent!.localName == "body". Here is my flutter code which was causing issue Html(data:"Find the remainder when <tex>3^{3^3}+7^{7^7}</tex> is divided by 5"). I understand that my input to Html() didn't have any <body> tag or <p> tag. These tags are ideally present in an html. But I feel inline rendering should be allowed even the bare-minimum Html inputs without the <body> tag.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 15, 2021

For 2) that is strange as it should work even without the body tag, since that's how I tested. I'll investigate it and see what's going on, and remove the 3.5 padding.

I wonder what it will take for vertical-align, I saw you used Transform or something like that. Maybe I'll attack that next....

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 16, 2021

Actually @ngaurav the behavior for 2) is intentional. My reasoning is that if somebody is using HTML:

<body>
<tex>x^2</tex>
<tex>y^2</tex>
</body>

The tex should not render like x^2 y^2 but instead like

x^2
y^2

(basically display as block element). When inline, then it will display inline. A simple fix for the sample html Find the remainder when <tex>3^{3^3}+7^{7^7}</tex> is divided by 5 is to surround with <span>: <span>Find the remainder when <tex>3^{3^3}+7^{7^7}</tex> is divided by 5</span>.

If you disagree let me know, this was just my thought process. Other than that I removed the 3.5 padding.

Also I am debating, should I add a horizontally scrollable widget to Math.tex? Just in case the Tex overflows the right side? I'm in a dilemma about this. I figure I should just leave it, if someone needs this then they can use customRender to override.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 16, 2021

The behaviour of "<tex>x^2</tex>\n<tex>x^2</tex>" should be similar to this string : "Hi\nHi"` It gets rendered as follows (the newline character results in a space):

Screenshot_20210316-112907

So, I think to get the two lines effect "<tex>x^2</tex></br>< tex >y^2</tex>" should be used and normally a tex tag should be displayed inline

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 17, 2021

@erickok this is ready to go now.

@ryan-berger
Copy link
Collaborator

I'm very late to the discussion, however, I wanted to get a really quick comment in.

We've been denying a lot of custom tags, or custom tag render-ers features and although I wholeheartedly support the <math> tag since it is an HTML standard tag, I'm just wondering what makes the <tex> tag any different than any other custom tag others have proposed in ithe past.

Don't get me wrong, we've wanted to support it for a long time, but I'm wondering if a custom element is the correct way, or if feature parity of the Tex libraries would be more correct via supporting more CSS properties would be the correct way.

I'm open to whatever though, as it is a community decision, not 100% my own.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 18, 2021

I would suggest using the <tex> tag as a temporary workaround until we provide full support for Tex in HTML.

As far as I can tell, it will be quite the effort to fully and correctly support Tex, as it requires us to be able to 1) parse external CSS and 2) support quite a few more inline styles to render the Tex correctly.

Adding this tag doesn't affect anyone using well-formed HTML, but it can be useful for the time-being for people like @ngaurav who need to display a combination of rich text and Tex with ease.

Another thing we could do is remove <tex> support in the library itself but then add a note in the README about how people can use customRender to enable this - it wouldn't be super difficult at all and the dependency is already present. If you like this idea I can update the PR.

@ngaurav
Copy link
Contributor

ngaurav commented Mar 18, 2021

I think the custom tex tag should be supported for two reasons:

  1. We need mathml support and tex tag implementation is very close to methml. No extra dependency.
  2. AFAIK, flutter_math convert mathml to raw tex first, and then renders it. So, having support for raw tex makes sense.

@erickok
Copy link
Collaborator

erickok commented Mar 18, 2021

I agree with @ryan-berger here. The moment we officially support a custom tag such as <tex> we basically say that we add tags beyond what html offers. So instead why not only officially support the math tag and add to the documentation an example custom render, which is extremely easy to write?

customRender: {
  "tex": (_, __, ___, element) => Math.tex(element.text),
}

@ngaurav
Copy link
Contributor

ngaurav commented Mar 18, 2021

@erickok Sounds great. It acts as a nice demo for using custom tags.

@ryan-berger
Copy link
Collaborator

I agree with @ryan-berger here. The moment we officially support a custom tag such as <tex> we basically say that we add tags beyond what html offers. So instead why not only officially support the math tag and add to the documentation an example custom render, which is extremely easy to write?

customRender: {
  "tex": (_, __, ___, element) => Math.tex(element.text),
}

@erickok Doesn't this still leave us open to the same issue but in a different form? We've talked about adding customRender for just any tag, but we've never done so. Currently we have a whitelist of tags that we check. I still wonder if we want to lean into that or not because it sets an interesting precedent

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 18, 2021

@erickok Doesn't this still leave us open to the same issue but in a different form? We've talked about adding customRender for just any tag, but we've never done so. Currently we have a whitelist of tags that we check. I still wonder if we want to lean into that or not because it sets an interesting precedent

If I remember correctly customRender supports custom tags, in the example html at one point we used customRender to render <bird> as the bird emoji.

@DFelten
Copy link
Contributor

DFelten commented Mar 18, 2021

Yes, it supports custom tags. We're working with a lot of custom tags like the workaround I've mentioned here.

@erickok
Copy link
Collaborator

erickok commented Mar 18, 2021

Custom tags have always been supported and we should support them. It's just official support for tags that don't exist in html that we should not bring into the library, in my opinion. Html spec has no tag.

@tneotia
Copy link
Collaborator Author

tneotia commented Mar 18, 2021

I removed the official support for tex and added a note in the README in the two most recent commits.

@erickok erickok merged commit ad237b6 into Sub6Resources:master Mar 18, 2021
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.

Support for MathML
5 participants