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

Support for conditional styling. #128

Closed
plehegar opened this issue Nov 4, 2015 · 27 comments

Comments

Projects
None yet
4 participants
@plehegar
Copy link
Member

commented Nov 4, 2015

Consider the use case in which an author wishes to permit the viewer of a TTML2 document to select from one of a number of style choices, either depending on a parameter or a media query, for example choices that vary tts:fontSize and tts:extent to accommodate 'normal size font', 'large size font' and 'small size font' options.

The condition attribute can only be used to omit an element from semantic processing, not to change its behaviour. One might imagine that the following is a way to proceed:

<layout>
<region xml:id="r1" condition="parameter(text_size)=='large size font'" tts:extent="95vw 30vh" .../>
<region xml:id="r1" condition="parameter(text_size)=='normal size font'" tts:extent="80vw 20vh" .../>
<region xml:id="r1" condition="parameter(text_size)=='small size font'" tts:extent="60vw 15vh" .../>
</layout>
<styling>
<style xml:id="sFontSize" condition="parameter(text_size)=='large size font'" tts:fontSize="15vh"/>
<style xml:id="sFontSize" condition="parameter(text_size)=='normal size font'" tts:fontSize="10vh"/>
<style xml:id="sFontSize" condition="parameter(text_size)=='small size font'" tts:fontSize="7.5vh"/>
<style xml:id="sDefaultFont" style="sFontSize" tts:fontFamily="myFontFamily"/>
</styling>
...
<body>
<div region="r1" style="sDefaultFont">
...
</div>
</body>

However this construct, which requires use of xml:id for style and region reference, breaks xml:id uniqueness rules, resulting in invalid documents. What options are there for achieving this use case? I can see:

a) repeating all the content in the document with different style and region references and specifying condition only on the content,

b) basing everything on the initial element and making that conditional (since nothing needs to refer to initial by xml:id), and specifying all regions inline - unfortunately this may be very verbose in terms of repeating regions on many content elements, but it could work for cases where there are only a few regions and they can be associated with body or div elements.

Neither of these two options is particularly attractive - a) is highly repetitious and offers no advantage over the provision of multiple documents with any associated costs for asset management and distribution there. b) is limited in basing style on initial so it is a 'one chance' condition, and it is potentially repetitious in region definition.

By the way, there are at least three audience groups for which this use case exists: 1) Those who have reading difficulties with normal size text; 2) users of different devices, where it has been established that text needs to be rendered at different sizes on large screen televisions from smartphones for example; 3) those who just want to be able to customise the display.

It would be great if the condition construct could be used to allow some predefined viewing options to be authored into the document, i.e. in a controlled way by the document author. I can't see how this can be achieved at present though.

What solution choices are there? Perhaps the easiest is to redefine the condition construct so that it also includes an 'if then else if' syntax in which attributes can be defined, so you might end up with, for example:

<region xml:id="r1" condition="if parameter(text_size)=='large size font' then (tts:extent='95vw 30vh' elseif parameter(text_size)='normal size font' then (tts:extent='80vw 20vh') elseif parameter(text_size)='small size font' then (tts:extent='60vw 15vh') else (tts:extent='80vw 20vh')"/>

Then xml:id rules are not broken and region r1 can be referenced safely with the attribute evaluation only being conditional. I'd advocate retaining the ability to specify a condition that can be used to exclude the entire element from semantic processing, as now.

Another solution to this problem might be to define some preprocessing using XPath to select specific elements and/or attributes and set values on the basis of the same condition functions that have already been specified, i.e. parameter, media, supports. Something like:

<tt [parameters etc]>
<preprocess xmlns="...">
 <rule condition="parameter(text_size)=='large size text'" path="//region[@xml:id='r1']">
   <attributes tts:extent="95vw 30vh">
 </rule>
</preprocess>
<head>
  <layout><region xml:id="r1"/></layout>
</head>
...
</tt>

It would be an error for a path attribute to refer to anywhere except or or their descendants.

This option would also have the incidental effect that it would provide similar functionality to declarative styling. All the rules would be executed in document order prior to processing the . Preprocessing could of course also be performed externally to the document before processing, if a 'user style' is desirable (as is the case for any XML document) .

(raised by Nigel Megitt on 2015-01-16)
From tracker issue http://www.w3.org/AudioVideo/TT/tracker/issues/366

@skynavga skynavga changed the title xml:id uniqueness needs to be broken for some uses of condition The uniqueness of xml:id needs to be broken for some uses of condition Sep 10, 2016

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented Sep 10, 2016

Since it will not be possible to break the uniqueness constraint without making content invalid XML, a different solution will be required for this use case.

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented Sep 10, 2016

@skynavga I'd appreciate your thoughts on the alternative solutions described in the issue.

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented Sep 20, 2016

Notes from 2016-09-20 f2f meeting: one option to consider here is to use a conditional set element that may optionally have no associated timing attributes, to apply region or style attributes based on some condition. That would probably work but may need some more thought.

@palemieux

This comment has been minimized.

Copy link
Contributor

commented May 4, 2017

@nigelmegitt Are you still interested in adding this capability to TTML2? If so, can you suggest a PR based on the set approach mentioned in #128 (comment)? If not, ok to defer to TTML vNext?

@palemieux palemieux assigned palemieux and nigelmegitt and unassigned palemieux May 4, 2017

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 11, 2017

@skynavga please review and comment on this

@skynavga skynavga self-assigned this May 13, 2017

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 14, 2017

@palemieux as discussed, yes, I believe this still needs to be addressed so that there are clear usable patterns for applying attributes based on condition that we can list by example. Using the set element looks like the cleanest way to me. From my recollection we discussed three possible approaches:

Possible approaches

1. Chained referential styling

This is where conditionally removed elements may still be referenced by other elements and define the behaviour in that case to be "do nothing", e.g.

<style xml:id="dependentStyleHighContrast" condition="parameter('high_contrast')='true'" tts:backgroundColor="#000000ff"/>
<style xml:id="dependentStyleNotHighContrast" condition="parameter('high_contrast')='false'" tts:backgroundColor="#00000080"/>
<style xml:id="backgroundStyle" style="dependentStyleHighContrast dependentStyleNotHighContrast"/>

This appears to be possible now (so in that case one might say that this "works for me") however I think it rather inelegant from an authoring perspective and even slightly weird. Still, if no other resolution can be found then this would work I suppose - I would really like there to be clear examples and probably an appendix describing this pattern.

Action point: Specifically, we need to explain/clarify in the style resolution process that a style whose condition evaluates to false results an empty style set, not that the exclusion of the element is intended to result in an IDREFS reference failure due to the element apparently not existing at all.

2a. Conditional anonymous set elements

Here we use aconditional anonymous set element to modify the applicable style set of a content or style element. This would require a modification to permit set to be a child of the style element. For example:

<style xml:id="backgroundStyle">
   <set condition="parameter('high_contrast')='true'" tts:backgroundColor="#000000ff"/>
   <set condition="parameter('high_contrast')='false'" tts:backgroundColor="#00000080"/>
</style>

By the way when we discussed this in Lisbon we realised it is related to the proposed change to make non-applicable style attributes on content elements, such as tts:origin or tts:extent on tt:p elements, act as anonymous sets that act on the currently active region.

2b. Styles reference set elements using the animate attribute.

This is a variant of 2a, in which the set elements are contained within an animation parent and the style element is permitted to include an animate attribute:

<style xml:id="backgroundStyle" animate="setHighContrast setNotHighContrast"/>
...
<animation>
   <set xml:id="setHighContrast" condition="parameter('high_contrast')='true'" tts:backgroundColor="#000000ff"/>
   <set xml:id="setNotHighContrast" condition="parameter('high_contrast')='false'" tts:backgroundColor="#00000080"/>
</animation>

Arguably this is simply a syntactic rearrangement of 1. above however it retains a single way to reference conditional behaviour rather than allowing that additionally into the style element.

My preferred choice

My key take-aways from this are:

  1. Strictly, there are techniques available already in TTML2 to resolve the apparent issue.
  2. I need them to be clarified, exemplified and explained (e.g. see bullet 4 below).
  3. Option 2a. has several advantages so I would like to see it added:
    • it is (to me) the most readable/understandable of the choices;
    • it works in environments where chained referential styling is prohibited;
    • it allows content elements to reference a single style and have the evaluation of that style change over time since the set element can include begin and end attributes, which presumably are resolved relative to the referring element's syncbase. This is a point of stylistic elegance more than anything else, since logically this must already be achievable some other way.
  4. Option 1. will not be removed since we cannot sensibly remove it; however we need to add a Note to clarify that referencing a style whose condition evaluates to false returns an empty style set in the style resolution process. In other words, it does not make the element 'disappear', just its style attributes.
  5. This mainly seems to be an issue with the style element, but there must be an analogous problem with the region element since the syntax region="r1 r2" is prohibited; instead the region itself must be modified to take different position, extent etc attributes in a conditional way. I would prefer that we had a single pattern used to solve to this problem that works equally for region and style, however it looks like fixing that would either a) be a huge change or b) should have happened a long time ago.

Looking forward to @skynavga 's comments and review on this also.

@palemieux

This comment has been minimized.

Copy link
Contributor

commented May 15, 2017

When are condition expressions evaluated? At time of parsing or time of rendering or something else?

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 15, 2017

Evaluation time is currently undefined as far as I can tell.

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 15, 2017

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 15, 2017

  • evaluation must not occur more than once, i.e., the condition should
    not be re-evaluated every time its semantics need to be used;

This is too limiting. For responsive scenarios such as windows that can be resized, that would modify the input data for the equivalent of media queries, so it must be an available option to re-evaluate based on changing input data.

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 15, 2017

@skynavga skynavga removed their assignment May 15, 2017

@palemieux

This comment has been minimized.

Copy link
Contributor

commented May 18, 2017

If condition is evaluated at arbitrary times, then 2(a) above increases processing complexity since referential styling resolution has to be deferred until condition is evaluated/changes.

What about simply using set on content elements, potentially using inheritance?

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 18, 2017

Some preliminary comments, without reviewing the above:

  • @condition may be (re)evaluated at any time a dependent parameter changes, which, since some parameters derive from run-time state, means it may be re-evaluated at run-time;

  • the current spec text says that the semantics of an element are ignored when @condition evaluates to false; it does not say that the element is not parsed or not stored in the reduced infoset; indeed, it must be stored in the latter and potentially retained in ISDs for re-evaluation in the case that it references a run-time parameter (directly or indirectly);

  • the meaning of ignoring semantics may need qualifying for specific elements in order to retain partial semantics; e.g., I presently hold that the chained style references of a conditionalized <style/> element are retained; i.e., the chain is not broken, but the style attributes that the element would contribute are ignored;

At present, the TTT toolset implements the above semantics, and needs this behavior in order to support an effective mapping of the IMSC1 tts:forcedDisplay property.

I should also mention that the use and support of conditionalized styling does not prevent merging/flattening/reducing style specifications with respect to ISD instances; however, it does mean that conditionalized styling cannot be fully merged/flattened/reduced at ISD generation time.

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 18, 2017

I'm not sure yet where I stand on breaking/not breaking chains of referential styles, but it seems intuitive to me to expect conditionally excluded style to break the chain. Otherwise a larger group of styles might all need the same condition to be applied.

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 18, 2017

@nigelmegitt or the author could merely collect into the conditionalized style all style attribute they think should be ignored (while retaining the chain overall);

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 19, 2017

@skynavga sorry, I don't follow you - please could you elaborate on #128 (comment) ? Are you saying that there should be an equivalent of tts:someStyleAttribute="fromChain" which could be put into a style element to explicitly cause chain breakage for that single style attribute in the event that the condition on the style element containing it resolves to false?

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 19, 2017

I am saying that if you have

<style style="chain" condition="false" tts:color="" ... more styles .../>

then tts:color ... more styles ... is ignored, but that the chain remains active, i.e., that styles contributed from style="chain" are not ignored.

The context where this came up was in supporting IMSC1's tts:forcedDisplay, where it is necessary to insert a style as follows at the front of an existing chain:

<style style="chain" condition="parameter('forced')" tts:visibility="visible"/>

where chain references a chain of existing styles previously specified in the source IMSC1 document, e.g.,

IMSC1 Input

<style xml:id="s1" .../>
<style xml:id="s2" style="s1" .../>
...
<p style="s2" itts:forcedDisplay="true">Forced Display</p>

TTML2 Output

<style xml:id="s1" .../>
<style xml:id="s2" style="s1" .../>
<style xml:id="s3Generated" style="s2" condition="parameter('forced')" tts:visibility="visible"/>
...
<p style="s3Generated">Forced Display</p>
@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 19, 2017

@skynavga okay, then what happens in this case:

<styling>
   <initial tts:color="blue"/>
   <style xml:id="s1" tts:color="yellow"/>
   <style xml:id="s2" style="s1" condition="false" tts:color="white"/>
</styling>
...
<p style="s2">Blue, white or yellow?</p>

In other words does the exclusion of a named style attribute cause all similarly named style attributes to be excluded or just the attribute defined in a context where the condition evaluates to false?

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 19, 2017

yellow

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 19, 2017

Thanks, I understand, so the proposal is that it is impossible to break the chain, only to conditionally set some specified style attributes when condition evaluates to true. Makes some kind of sense I think. Now what about this:

<styling>
   <initial tts:color="blue"/>
   <style xml:id="s1" tts:color="lime"/>
   <style xml:id="s2" style="s1" condition="false"/> <!-- only there to define the chain? -->
   <style xml:id="s3" style="s2" tts:backgroundColor="black"/>
</styling>
...
<p style="s3">Lime or blue?</p>

in this example the conditional style defines no style attributes, so the assumption might be that the only thing the condition affects is the chain. But if I've understood correctly that isn't the case and the text comes out lime regardless?

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 19, 2017

background color is black, from s3, and foreground color is lime, from s3->s2->s1

s2 doesn't specify any styles directly so the condition is vacuous in this case

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 19, 2017

Okay that's consistent, and should be covered by the already requested clarification of what the condition semantic includes (and excludes), possibly with an informative note to say that there is no way to break style chaining using condition.

Additionally, now that we have a bit more clarity about what is intended, we should also check that this approach does not exclude any use cases that we expect to be supported.

@skynavga skynavga modified the milestone: Editor's WR Work List May 29, 2017

@skynavga skynavga assigned skynavga and unassigned nigelmegitt May 29, 2017

@skynavga skynavga changed the title The uniqueness of xml:id needs to be broken for some uses of condition Support for conditional styling. May 29, 2017

@skynavga skynavga added the question label May 29, 2017

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 29, 2017

Changing this issue to the question "how to conditionalize styles?". Since style vocabulary is already subject to @condition usage, what remains is to clarify how this is done and any special semantics that need to be defined, such as whether style chaining is broken when a style element's @condition evaluates to false.

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 30, 2017

A few comments on #128 (comment) above:

  • the expression parameter('high_contrast')='true' is not only invalid but is also poorly expressed; it is invalid because the equals operator is == and not = (the latter is not a valid operator in the condition expression language); it is poorly expressed because it is not necessary to compare the value of the parameter function with a boolean; rather, the value of the parameter function can be used directly, e.g., condition="parameter('high_contrast')";

  • regarding the application of <set> to <style> and also the use of non-applicable styles to mean they apply to the current region, I have concluded that, in general, this approach requires far too much semantic overload on the part of the specification, the implementer, and the content author; I am now opposed to having any properties other than tts:extent and tts:origin have such special semantics, and that allowing these two properties to have special semantics is strictly for the purpose of accommodating a non-compliant, but fielded practice that grew out of a particular implementation; in any case, this proposal (of using an explicit or anonymous set) is not technically required since @condition on <style> achieves the same results;

  • your 2b variant also requires applying animation effects to <style> elements, which I believe significantly complicates the specification, implementation and authoring without any technical benefit not supported by the direct use of @condition on a content element or on an explicit animation element;

My conclusion is that no new technical mechanism is required, and that this issue can be fully resolved by adding clarifications to the effect:

  • @condition never causes an element to not be parsed or not appear in reduced infoset;
  • @condition on style when evaluated to false means that the styles specified on that style are not added to a related specified style set, but chained styling is not affected, i.e., chains aren't broken;
  • information about evaluation time of condition expressions needs to be added.

I will post a PR that adds such clarifying language.

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 31, 2017

OK I can accept not adding set to style, but I see also that the region element permits condition. Since the region attribute can only reference a single region, and there is no chaining of regions, what region applies to an element that specifies a region whose condition evaluates to false?

@skynavga

This comment has been minimized.

Copy link
Collaborator

commented May 31, 2017

@nigelmegitt

This comment has been minimized.

Copy link
Contributor

commented May 31, 2017

Multiple conditional explicit inline regions can be specified where the
first one whose condition is not false gets used.

I think that's too limiting and syntactically awkward - we should be able to use referential region specification too, but are blocked by this part of the spec:

If specified, the value of a region attribute must adhere to the IDREF data type

The easiest (!) solution seems to be to change this to IDREFS and resolve the computed value to the first listed region whose condition resolves to true.

@skynavga skynavga closed this in #347 Jun 3, 2017

@skynavga skynavga added pr merged and removed pr open labels Jun 3, 2017

@skynavga skynavga removed their assignment Dec 25, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.