WICG / canvas-formatted-text

Other
80 stars 17 forks source link

Consider data model immutability (and one-step construction) #23

Closed travisleithead closed 2 years ago

travisleithead commented 2 years ago

I think it would be much easier to use the API if we can pass the whole model to the FormattedText constructor as an array instead of setting each run stylemap on separate statements. Is there also potential perf gain with that idea?

@nhelfman

travisleithead commented 2 years ago

@nhelfman could you provide a bit of example code that demonstrates this?

nhelfman commented 2 years ago

For example, instead of:

let text = new FormattedText();
text.textruns.push (new FormattedTextRun({ text: "hello" });
text.textruns.push (new FormattedTextRun(" world");

text.textruns[1].tstyleMap.set("text-decoration", "underline");

It could be declared as:

let text = new FormattedText([
    { text: "hello" },
    { text: " world", style: { "text-decoration": "underline" }
  ]
);

Then, if we define FormattedText to be immutable it can make code using it much safer. Obviously, the downside here is increased GC in case it has to be recreated frequently with minor changes, but we should first identify such use cases.

travisleithead commented 2 years ago

Your second example is almost fully supported by the current data model (see the 3rd constructor overload in the WebIDL):

  constructor(sequence<FormattedTextRunInit> textRunInit);

however, it expects a single string with the style declarations--there is some internal discussion about whether that should be used (e.g., requires the CSS parser to run on the string). Your approach with a record type of <css name string/ css value string> seems better.

The comment about making the data model immutable is more interesting. I'd been always thinking about FormattedText as a mutable data structure (like DOM nodes) that produces an immutable metrics--however if both the data model and associated metrics are immutable, then cross-referencing between them is no problem.

Mutability seems convenient if you use the FormattedText as the source data model. If you don't, and the formatted text is only the output of some other processing code (which seems very likely), then perhaps just re-creating it each time makes sense. I'd like to continue to explore this idea. If other folks have use cases where this makes sense, please share!

travisleithead commented 2 years ago

Closing this as PR https://github.com/WICG/canvas-formatted-text/pull/39 does away with the intermediary "data model" and now depends on application logic to host their own data model, which must be arranged correctly to a call to format to engage the API.