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

Porting TextBlock, Inlines, Flow Layout from WPF #5461

Closed
wants to merge 11 commits into from

Conversation

shartte
Copy link
Contributor

@shartte shartte commented Feb 10, 2021

As requested by @Gillibald, a branch for discussing work on porting the inline work from WPF.

/// <summary>
/// Defines the <see cref="FontFamily"/> property.
/// </summary>
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
Copy link
Contributor

Choose a reason for hiding this comment

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

These are defined on TextElement so we should inherit them from there

@@ -548,5 +602,13 @@ public bool MoveNext()
return !(Current is TextEndOfLine);
}
}

private static LineBreakEnumerator GetLineBreakEnumerator(TextRun run)
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the reason behind this change?

@shartte shartte changed the base branch from master to inlinesTheThird February 10, 2021 12:28
@Gillibald
Copy link
Contributor

There is something about those synthetic characters. When I add a LineBreak to the TextBlock it always uses TextSourceLength=2 for the LineBreak. I think we need to treat LineBreak etc. as actual text.

@shartte
Copy link
Contributor Author

shartte commented Feb 11, 2021

Yes, that is extremely weird. In this branch, my current hack was to actually define Text for EndOfLine/EndOfParagraph and make it contain actual text (\n and the paragraph separator unicode character, respectively).
However. Is my understanding correct that the text source positions are completely separated from the text that actually gets shaped in the end? Hence the differentiation between TextSourceLength and actual Length? We currently wildly mix the two concepts.

@Gillibald
Copy link
Contributor

TextSourceLength is just meant for querying runs from the text source

@Gillibald
Copy link
Contributor

I think WPF treats TextEndOfLine as part of the TextLine and therefore the TextSourceLength contributes to the final length of the line. This is why they subtract the synthetic character count from TextLine.Length

@Gillibald
Copy link
Contributor

We probably want to fire up a WPF application and test TextFormatter.FormatLine in combination with TextEndOfLine to find out the expected results.

@Gillibald
Copy link
Contributor

Gillibald commented Feb 11, 2021

I have run something under WPF. So the full length of a TextEndOfLine run adds to the total length of the TextLine. TextEndOfLine is always added to the list of runs.
Screenshot 2021-02-11 135223
Screenshot 2021-02-11 135239

A regular line break that is part of the text isn't added as a TextEndOfLine run.

The next step will be to implement that behavior.

Currently, TextLine.TextRange only includes acutal text and does not add synthetic length of TextEndOfLine runs.

@Gillibald
Copy link
Contributor

This can be used to investigate WPF's behavior
WpfApp1.zip

@Gillibald
Copy link
Contributor

I think we don't have to process a synthetic LineBreak like WPF does. We can just introduce a flat EOT and use that instead. Adding TextEndOfLine to the list of runs just makes the code more complicated but isn't any useful in the end.

@shartte
Copy link
Contributor Author

shartte commented Feb 20, 2021

@Gillibald Do you mean EndOfParagraph? I think the hickup in TextBlock was not about end of line, rather EndOfParagraph.
It's hard to judge at this point, how this will interact with the FlowDocument later, since TextBlock only displays a single paragraph at a time, apparently. Although I also thought that potentially just indicating EndOfText/EndOfLine via a boolean Property might be sufficient.

@Gillibald
Copy link
Contributor

TextEndOfParagraph is a TextEndOfLine. For TextBlock LineBreak is transformed into TextEndOfLine on top of that when the TextSource reaches its end a TextEndOfParagraph is produced. Both are processed in the same way by the standard TextFormatter. FlowDocument most likely processes TextEndOfParagraph differently.

@shartte
Copy link
Contributor Author

shartte commented Feb 20, 2021

@Gillibald
Copy link
Contributor

Y that implicitly looks at the last run in the line. If it is a TextEndOfParagraph this is true. I don't think that synthetic runs should contribute to the text metrics.

@shartte
Copy link
Contributor Author

shartte commented Feb 20, 2021

I think the problem was that it looks at the trailing whitespace field as a performance optimization to quickly test if there's any trailing whitespace (which includes EndOfLine runs apparently) in the line. And that field comes from the metrics.

It feels convoluted.

@Gillibald
Copy link
Contributor

Y we don't need to mimic that. Just hold a flag in the text line metric that indicates synthetic characters (TextEndOfLine). Adding synthetic characters to the NewLineLength is a hack.

@tofutim
Copy link

tofutim commented Oct 25, 2021

Hi @Gillibald and @shartte, curious how far this is away from working as I have some use of inlines in my old WPF project I would like to port. Esp inlines on TextBlock. Is it still active?

Are we close to being able to

    <TextBlock>
      <Run Text="A "></Run>
      <Run Classes="code">TextBlock</Run>
      <Run Text=" with "></Run>
      <Run FontWeight="Bold">differing</Run>
      <Run FontStyle="Italic" Text=" styles"></Run>
      <Run FontSize="24" Text=" and fonts"></Run>
      <Run>.</Run>
    </TextBlock>

Also, I'm curious why the Avalonia implementation of TextBlock is not just exactly a copy WPF's implementation? Did you guys write all the controls from scratch? I would have thought it would be the same.

@Gillibald
Copy link
Contributor

Our API surface is 95% but you can't just take WPF's code and it magically works. WPF is heavily reliant on DIrectWrite and isn't very portable. So the challenge here is to reimplement everything underneath WPF's API to make everything else portable.

This PR will be continued early next year

@grokys
Copy link
Member

grokys commented Oct 26, 2021

Also, I'm curious why the Avalonia implementation of TextBlock is not just exactly a copy WPF's implementation? Did you guys write all the controls from scratch? I would have thought it would be the same.

Yes, we rewrite all the controls from scratch. Avalonia started in late 2013 but WPF wasn't open sourced until late 2018 so for the first 5 years of the project we couldn't use WPF sources.

@Gillibald Gillibald mentioned this pull request Nov 16, 2021
3 tasks
@grokys
Copy link
Member

grokys commented Dec 6, 2021

@Gillibald this PR has a lot of conflicts by now. Is it worth keeping open?

@Gillibald
Copy link
Contributor

We can close it. I need to rework most of it.

@Gillibald Gillibald closed this Dec 6, 2021
@PeteMichaud
Copy link

Should I interpret this closure as meaning that AvaloniaEdit does not currently support rich text?

@Gillibald
Copy link
Contributor

This work was about porting WPF's text tree and in some extend bringing FlowDocument to Avalonia. It was an attempt of multiple and was closed because it wasn't in a state we could move further.

Avalonia now supports proper whitespace handling via XamlX and also has inlines support.

We will most likely port WPF's text tree and other parts of FlowDocument in the near future. This is highly reliant on demand and funding.

@mlsomers
Copy link

mlsomers commented Apr 9, 2022

Sorry for being off-topic but I'd just like to throw this idea in here.

It's going to be a huge task but if you ever get to it, please consider to keep an option open for some features that were lacking in the original WPF and finally rendered it unusable for my purpose:

<FlowDocument Language="nl" IsHyphenationEnabled="True">

IsHyphenationEnabled was restricted to only four languages: English, Spanish, French, and German. It is related to the spell-checking dictionaries which could be extended for extra jargon but did not allow adding any full dictionary.

If this feature would have been available at that time it would have entirely removed Adobe InDesign from my workflow.
The text could be rendered to XPS using a DocumentPaginator, from there to PDF.

It's probably far out of scope, but if you could ever get Avalonia to natively render PDF, your audience would instantly increase. This is a feature that some Winforms and WPF users have wanted for decades. There are many commercial solutions (most of them not native .Net). The best open source PDF in .Net that I am aware of is PdfSharp which is far from mature.

Bottom line: If you could bring typesetting and native PDF into scope I think there would be allot more demand and possibly funding from a wider audience outside the cross-platform-ui domain...

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.

6 participants