- From: Dael Jackson <daelcss@gmail.com>
- Date: Sun, 5 Mar 2017 11:00:23 -0500
- To: public-houdini@w3.org
- Cc: www-style@w3.org
================================================= These are the official Houdini Task Force minutes. Unless you're correcting the minutes, please respond by starting a new thread with an appropriate subject line. ================================================= Typed OM -------- - RESOLVED: CSSFooValue objects are mutable - RESOLVED: Move DOMMatrixReadOnly out of CSSTransformComponent to CSSMatrixComponent (and make mutable) - RESOLVED: Add an update() method to styleMap - TabAtkins will write a mail about if updateAll() is also necessary. - RESOLVED: Canonicalize by representing all values, and serialize to the most-backwards-compatible minimal representation to be mostly compatible with old CSSOM (minus some idiosyncrasies), and to gradually bring old CSSOM in line with new consistent serialization rules. Custom Properties ----------------- - RESOLVED: When you register a property that makes existing value invalid, we throw out the invalid value. - RESOLVED: Typed custom properties do not trigger fallback. - RESOLVED: Registering types for a property therefore does not force reparse. - RESOLVED: When typed custom properties fail, they fall back to their initial value not to invalid. - RESOLVED: Invalid argument for paint function produces an invalid image, does not trigger fallback or anything like that. - The previous four resolutions need author feedback. ===== FULL MINUTES BELOW ====== Agenda: https://github.com/w3c/css-houdini-drafts/wiki/Seattle-F2F-Jan-10-2017 Scribe: fantasai Typed OM ======== Mutability ---------- shane: First topic is revisiting mutability. shane: We resolved in the last meeting that all of the objects in the typed OM would be immutable. shane: I've since have implementation feedback from engineers in Chrome who are building this that that's not great for performance shane: Specific example of where it's really bad. shane: Specific ex is, you've built up a complex transform. Just want to modify a small part of that frame by frame: shane writes: new CSSTransformValue( [new CSSTranslationComponent(...), ... new CSSRotationComponent(new CSSAngleValue(5, 'deg')), ...., ]); fantasai: wow, that is so much writing.... shane: The problem here is that if you do this on every frame, you're constructing a whole bunch of objects that you then throw away, repeat, repeat, repeat shane: Doing a lot of object creation and cleanup on every frame, which is excessive work. shane: If this was mutable, though, you could then just modify the rotation value like: t[3].angle.value +=5; shane: You just mutate the one piece you're changing. shane: Given the whole point of this API is high performance, it seems important that we actually make it high performance =) Rossen: Why did we make it immutable? esprehn: For confusion reasons. esprehn: Today you do element.style.color = ... esprehn: Concern that people would do element.style.styleMap.transform and then call a method on it esprehn: And then authors would be confused because that's a copy, not the actual thing esprehn: But that was maybe preemptive, maybe not really a problem. shane: We weren't sure coming into the meeting. shane: We tossed it around, there weren't strong reasons on either side. We ended up on immutable. shane: I think this is a strong reason to flip back to mutable. smfr: Can you write down the mistake that elliot brought up? <esprehn> ex. element.styleMap.get("transform").rotate(32, 'deg') <esprehn> nothing happens to the element there <esprehn> you can alternate mutating the object and setting it <esprehn> ex. to place objects you could create a transform, and adjust it on the Y axis as you assign the style of each item in the list TabAtkins: The mistake is that you have to set the object back. smfr: Can replace the whole object, have to get it , modify it, and then set it? shane: We want to make an upgrade method to make this easier as well. <iank> document.body.styleMap.update('width', w => w.value += 5) surma: So want to make it mutable but not live. shane: Right. plinss: My only concern is that we see all three patterns all over the platform, and you never know what you're going to get. Would be nice if we could be consistent with ourselves. Rossen: Do we have a definition of what we need to be consistent with? plinss: No Rossen: That's another topic for the TAG then. smfr: Is this proposal to make all the CSSFooValue things mutable? shane: Yes. smfr: Would CSSTransformValue have a matrix? shane: DOMMAtrix is a view of the transform that you've set. smfr: You'd have to set a whole new matrix if you want to change it. smfr: Oh, you're assigning angle there. smfr: You can set a matrix Component, and then alter that. But DOMMatrix is the matrix of the whole thing. smfr: It inherits matrix from the base class? shane: We'll have DOMMatrix and then... will need to work out. shane: I think we need to remove the matrix component from the matrix superclass shane: I don't think I'm hearing strong disagreement... Rossen: So first question is whether or not to roll back decision to make this immutable. Rossen: Any objections? RESOLVED: CSSFooValue objects are mutable Rossen: Next issue is moving the DOMMatrixReadOnly out of CSSTransformComponent Rossen: to CSSMatrixComponent. shane: And making it mutable. RESOLVED: Move DOMMatrixReadOnly out of CSSTransformComponent to CSSMatrixComponent (and make mutable) Rossen: Do we need any other changes? fremy: Adding update()? RESOLVED: Add an update() method to styleMap shane: We might need update() and updateAll() Rossen: How is set() different from update()? shane: set() takes a value whereas update() takes a function. TabAtkins: This is supposed to look like a map. If you're mysteriously missing standard map methods, that's not good. iank: What if you try to update a thing that doesn't exist? shane: If you call update on a custom property that hasn't been set, then the input the update function is whatever the representation of a custom property's undefined value esprehn: ES map needs update function esprehn: In C++ you get entry in map and you can do one hash lookup instead of two. In JS you have to get and set, so it's two hash lookups. esprehn: It's supported by underlying platforms everywhere. slightlyoff: send mail? ACTION TabAtkins Send mail Rossen: There's bunch of open issues, but nothing happening. shane: I have to apologize, I was supposed to get some stuff done by now, but had some exceptional circumstances in Sydney shane: This year I started back up on this, been working on canonicalization. Rossen: Just wanted to see if we could help with these issues. shane: They're fairly mechanical afaict. Canonicalization ---------------- shane: Do want to go over the canonicalization, though. <nainar> Canonicalization is https://github.com/w3c/css-houdini-drafts/issues/268 shane: I made a spreadsheet of all the different CSS properties. shane: Trying to classify them all into different canonicalization approaches. shane: We talked about how the properties in the typed OM are serialized. shane: Complication of having values not going through string representation. shane: We decided we needed a canonical serialization for every property. fantasai: Didn't we decide we needed that a long time ago, added a field to the propdef table? dbaron: The CSSOM spec refers to canonical order a few times, but only for shorthands. shane: Also need to address e.g. colors are canonicalized into rgb. shane: Going through property by property shane: Looking at syntaxes and classifying into groups. shane: For the ones I've done, there's a small set of groups. shane: Some things are just a choice of keywords, no need to canonicalize shane: things which are set of keywords, e.g. flex-flow. shane: Need to fill in missing productions shane: e.g. flex-flow, you need a flex direction and a flex wrap. shane: But if you have a background, you don't want to necessarily fill in the missing pieces for bits of background that exist. shane: Can completely understand what background: red does without filling in the rest. shane: Some sets fill in missing pieces, others don't. fantasai: Do we want to have that distinction? why not follow shortest-output rule? shane: The typed OM representation should be able to read both of these. fantasai: Wouldn't that be the case for backgrounds as well? fantasai: There are two types of things here, e.g. flex-flow (like background), where an omitted value can also be present -- there is an explicit way to represent a missing value. fantasai: The there's things like text-decoration, where the a missing keyword represents a particular state which cannot be represented explicitly: the presence or absence of the keyword indicates state, as opposed to flex-flow where we have two keywords that represent the two states and one of them is merely the default. fantasai: Background is the same as flex-flow: you can explicitly represent the missing values. fantasai: Why would you treat one different than the other? fantasai: You're saying that the omitted values aren't interesting, but that's an opinion, it's not a structural difference as between text-decoration and flex-flow. shane: The background shorthand has two subcomponents, it's got background-color and then it has stack of images. shane: If it has no images, then the rest of it isn't interesting. shane: There's two parts: the color and the stack of images. dbaron: But that stack has a length of at least one. dbaron: Because originally there wasn't a stack, there was just one image. Scribe: nainar fantasai: We have had people suggest that we need a color on every layer - not an assumption you want to make. TabAtkins: We have that built into the image() function.. fantasai: We don't make a special case where background is ... I'm not sure. You should be able to read out that background-image is a null value. zcorpan: Is it possible to have none? Images in the spec along with other image. fantasai: Yes. fantasai: If you want just the color, read out backgroundColor. shane: I'm not sure - if background is a complicated thing - people will default to using color. Scribe: fantasai TabAtkins: We're hitting several concepts here. TabAtkins: One is canonicalization of typed OM stuff. TabAtkins: The other thing is serialization. TabAtkins: We do try to have serialization obey the minimal-representation thing. TabAtkins: If you only have a background color, you get 'background: red', 'background: repeat none 0 0 red' etc. TabAtkins: We need to define serialization. dbaron: There were a bunch of vague principles. dbaron: One is minimal representation, other is oldest form (for most compat) -- usually but not always the same. dbaron: Shortest in terms of fewest components, not fewest characters! zcorpan: CSSOM spec tries to define how serialization should work. I think the algorithm is broken in some ways. zcorpan: Tries to omit components that are the initial value, if it can be serialized that way. shane: Gets very tricky with e.g. flex shorthand. TabAtkins: Reason we have to do this, a bunch of properties esp. shorthands, have values can be easily represented in typed OM. TabAtkins: Using string access right now, want compatible way to expose the string value. TabAtkins: Without explicit guiding principles, was tasked with writing out serialization rules for al properties. shane: Flex is interesting because of 4 special values. shane: auto | initial | none | <integer> TabAtkins: It's not weird, it's pretty standard. TabAtkins: Auto is just a flex basis. TabAtkins: The expansion rules are a bit special, they don't just fill in the initial values always. TabAtkins: We have some keywords that are called out as especially useful. shane: If we have a constructed flex object, which matches one of these keywords that are called out shane: With flex-grow of 5 and flex-shrink of 1 and flex-basis of 0. fantasai: That would serialize as 'flex: 5' TabAtkins: Being the minimal representation. TabAtkins: This is different from a canonical data structure. shane: There may be cases where the canonicalization ... shane: might be cases where canonicalization gets you something that doesn't serialize out a minimal representation. TabAtkins: Why can you not produce the same string again? shane: e.g. top 50% right 50% shane: When we canonicalize, it's a pair of lengths. When you re-serialize out... fantasai: You get 50% 50% - fantasai: minimal representation. shane: So we canonicalize by representing all values, and serialize to the minimal representation. TabAtkins: Yeah. shane: Canonicalization fills out all the missing pieces. gregwhitworth: What is use case where someone asks for shorthand, then returns a string. TabAtkins: The use case right now is that typed OM object patterns don't currently have ability to capture all property patterns, esp for shorthands which are relatively complex. TabAtkins: For those, or for custom properties, we need to expose the values somehow. And that's a string. TabAtkins: We need to define what the string is. TabAtkins: We'd like to get this fixed so everyone is consistent. TabAtkins: We want typed OM to represent all properties with objects eventually TabAtkins: But right now trying to hit 80% case. gregwhitworth: [...] gregwhitworth: Should we maybe say V1 we don't handle shorthands? TabAtkins: We decided at TPAC we need to have shorthands defined. TabAtkins: That was one of dbaron's conditions. dbaron: I'm not sure minimal representation is web compatible. TabAtkins: We have ability to do it new and nice. <gregwhitworth> I'm primarily saying that most use cases for shorthands as an author, they'll then parse out to the longhands. So is it worth spending time on serializing to strings or could we focus on building out the shorthand typedOM models for the shorthands. fantasai: Have to consider future compat, so will need to have a "most compatible form" rule going forward. zcorpan: If you only care about defining serialization for typed OM, seems like a missed opportunity to achieve interop for old CSSOM. zcorpan: Seems like roughly same amount of work to define them to be the same serialization. shane: Those incompatible serializations have been shipped already. zcorpan: But we should try to get interop on those too. zcorpan: So pick the most web-compatible solution and define that as the way forward for both. zcorpan: Instead of defining new rules and leaving old CSSOM stuff. shane: I think we should have a consistent set of rules, and maybe we can move CSSOM towards that gradually. fantasai: Be consistent with the old OM rules even if they are not the most ideal ones. fantasai: So that you can keep as much compat with the two systems as possible. fantasai: Just drop the really weird idiosyncracies. fantasai: From the new OM, and then maybe gradually reduce those in the old OM. fantasai: Is the rule about most-backwards-compatible minimal representation in the CSSOM spec? zcorpan: Minimal representation is, compatible isn't. fantasai: Probably should put that in the spec then, since that's the actual principle. RESOLVED: Canonicalize by representing all values, and serialize to the most-backwards-compatible minimal representation to be mostly compatible with old CSSOM (minus some idiosyncrasies), and to gradually bring old CSSOM in line with new consistent serialization rules. break: lunch Custom Properties ================= [shane writes styleMap.set('--foo', 'invalid')] shane: Then register --foo as a color. shane: That's not a valid color. shane: If you register it as a color first, you get an exception. shane: You get a bit of raciness. TabAtkins: It's not racy unless you do racy things, but it's order dependent. TabAtkins: Could make it not order-dependent by making .set silently. astearns: First ordering trying to solve, setting something don't know what grammar applies, then using it in a context where grammar applies then gets thrown out. shane: Currently if you have a grammar and you set an invalid thing, an exception is raised. shane: If you set something and then register the grammar, don't get the exception. esprehn: Do we want it to throw an exception? shane: Yes. esprehn: That doesn't match the CSS fallback pattern. esprehn: Where you set multiple property declaration and the latest one that is valid wins. shane: This helps catch mishandling problems. shane: Much most JS-y shane: which makes sense because it's a JS API. esprehn: For unregistered case you want it to hold as a pending value? shane: It's a valid value until you register a type. TabAtkins: The question is, is it OK if this is order dependent? If not, what do we do about it? TabAtkins: Could make .set silently fail, probably not great. TabAtkins: Alternately make the registration throw. esprehn: That requires synchronously computing registration. shane: That's bad. shane: If you read --foo at this point what happens? TabAtkins: You recalc, and that results in throwing out the invalid value. shane: Other option is having explicit invalid value representation. TabAtkins: You don't get that if you set 'background' to 'invalid' zcorpan: What's the use case for setting a property without setting the grammar? TabAtkins: That's just a normal custom property. shane: This is more likely to be a conflict of two libraries than something intentional. fremy: What if it works, but did nothing? fremy: Set the value as an unparsed value fremy: when browser tries to use the declaration fremy: like if you did what is in your style sheet, it's still there in your style sheet but isn't there anymore. TabAtkins: It's same as 'background: invalid'--effectively thrown away during parsing. It's in your stylesheet, but not in the OM. ... TabAtkins: If you set style attribute, parsing still happens and we throw out the invalid stuff. kbabbitt: What happens if I subsequently unregister foo? shane: We resolved to remove unregistration at TPAC. shane: Not just this reason, but b/c complicated to support and didn't have use cases. Fortunately don't need to worry about that. fantasai: I think it's fine to not worry about this case, behavior seems reasonable and expected. fantasai: Could possibly throw an exception at registration, but likely to be more annoying than helpful. shane: It's also very expensive. RESOLVED: When you register a property that makes existing value invalid, we throw out the invalid value. shane: Let's say I have in a style sheet .... ---foo: red; --foo: invalid; shane: This is in a style sheet, and foo is registered as a color. shane: We don't fall back? TabAtkins: Of course we fall back. we know the grammar. TabAtkins: Once we know the grammar, can treat it as a property we know how to parse. shane: Might be some raciness. TabAtkins: But when you register you reparse the style sheet. TabAtkins: That's what needs to happen to make it consistent with the rest of CSS. TabAtkins: If we said you don't need to reparse the style sheets, you get the behavior where that invalid is used, treated as invalid, becomes invalid-at-computed-value-time ... esprehn: You have to reprocess the entire property set. shane: The behavior with not falling back is consistent with untyped properties. TabAtkins: Because it is literally impossible to know what the value space of a custom property is. esprehn: But reprocessing the style sheet on registration is very expensive. iank: What shane is proposing is that last value always wins, no fallback. shane: Even if we know that foo is typed as a color, I don't think we can deal with this case: color: red; color: var(--foo); shane: We can't fall back in that case. TabAtkins: At parsing time we don't know the value of --foo. TabAtkins: Here is where even typed custom properties behave same as ... TabAtkins: We could fall back there if we knew that --foo is typed as other than a color. shane: ... TabAtkins: Typed properties have an initial value that matches their type. TabAtkins: If --foo is typed as a color, you are guaranteed that --foo will give you a color. shane: No, --foo could still be invalid because of loops. TabAtkins: Loops just need to reset all the involved properties to something that is no longer referencing anything. TabAtkins: If you are a typed property, you have an initial value, we can use that. No reason to use invalid as a value there. shane: I think Tim ran into problems when he tried to do that. TabAtkins: There's no dependency value in falling back to initial. TabAtkins: Pretty sure we don't need to accept invalid as a bottom value. TabAtkins: Thus should be guaranteed that a typed property always resolves to given type. shane: So if foo in this case referenced another untyped custom property? TabAtkins: Either rando is a color, and parses correctly, or --foo itself will note that it's not got a color and will fall back. shane: Two scenarios on the table: shane: One is that when we register a custom property, we reparse the world. shane: In that scenario we can fall back on typed custom properties, and on typed vars in typed properties. shane: In other scenario we don't need to reparse the world, but never get fallback. shane: Typed custom properties behave like untyped custom properties. kbabbitt: Suppose I have property --foo registered as <length>+ and I say margin: var(--foo); kbabbitt: Since I don't know the length of the list, so can't tell if it's valid. TabAtkins: It's not a valid type match: you'd need <length>{1,4} <TabAtkins> (The general case for type-matching is actually rather difficult; a --prop registered as <length>{1,2} should theoretically work in "margin: 1px var(--prop) 2px;", but hoo-boy that's making parsing more complicated.) iank: Once subtle thing: <iank> https://gist.github.com/bfgeek/460c21569776f75fb707fa8d20419dbe iank: Arguments for custom paint has similar problem. iank: Say we specify input items iank: Initially this property would be invalid: <style> .painting { background-image: paint(typed, 10px); background-image: paint(typed, color); } </style> <script> registerPaint('typed', class { static inputArguments = [' <length>']; // etc. }); iank: What behavior do we want for input arguments? iank: Here we've registered custom paint argument of type length. iank: I'd argue that a paint function can never be invalid [unless it's empty paint()]. TabAtkins: The main reason we have fallback is because we know we are going to make changes in the future. TabAtkins: With custom properties, you don't have that problem -- you know what's supported because it's what's in the library. TabAtkins: So while consistency with CSS is nice TabAtkins: fallback is not so critical. esprehn: The use case is someone publishes a component that is compatible with two different versions of a library. TabAtkins: Wouldn't it be better to have two different style sheets, one per version? Avoids sending over duplicated data. TabAtkins: You can't do that with normal CSS. esprehn: So send different style sheet per UA version? TabAtkins: You can't predict that and don't have control over it. gregwhitworth: ... TabAtkins: Case is API changing out from under you, without your control. That's essential what browsers do. TabAtkins: But libraries aren't browsers. You control your dependencies. .... esprehn: There's an ancient spec from hixie that introduces a dependency attribute on scripts and styles and stuff. esprehn: I think simplifying this make sense. You control your dependencies. Don't go to /latest esprehn: If you link to jquery/latest you're probably broken. zcorpan: Are we saying that we don't want people to use /latest for libraries in general? TabAtkins: Should specify version ranges that you know work. <TabAtkins> (This is already best-practice in Node/etc) shane: What we're saying is don't reparse stylesheets when registering custom properties or paints. TabAtkins: And don't trigger parse-time fallback, in general. TabAtkins: When they do fail, they should fall back to their initial value if they're typed. Not to invalid. fremy: Let's say browser supports new color type. fremy: And you want your custom property to use the new color type if available in the browser. shane: Use @supports fantasai: I think conclusions here make sense, but should get some feedback from authors as well. [Following resolutions need to request author feedback...] RESOLVED: Typed custom properties do not trigger fallback. RESOLVED: Registering types for a property therefore does not force reparse. RESOLVED: When typed custom properties fail, they fall back to their initial value not to invalid. RESOLVED: Invalid argument for paint function produces an invalid image, does not trigger fallback or anything like that. <div id="DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2"><br /> <table style="border-top: 1px solid #D3D4DE;"> <tr> <td style="width: 55px; padding-top: 13px;"><a href="https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=icon" target="_blank"><img src="https://ipmcdn.avast.com/images/icons/icon-envelope-tick-round-orange-animated-no-repeat-v1.gif" width="46" height="29" style="width: 46px; height: 29px;" /></a></td> <td style="width: 470px; padding-top: 12px; color: #41424e; font-size: 13px; font-family: Arial, Helvetica, sans-serif; line-height: 18px;">Virus-free. <a href="https://www.avast.com/sig-email?utm_medium=email&utm_source=link&utm_campaign=sig-email&utm_content=webmail&utm_term=link" target="_blank" style="color: #4453ea;">www.avast.com</a> </td> </tr> </table><a href="#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2" width="1" height="1"></a></div>
Received on Sunday, 5 March 2017 16:01:31 UTC