<div dir="ltr">Thanks Skef.<div><br></div><div>I think I found the right approach for this (taking ideas from COLRv1 paint tree / graph). Ignoring your other proposals, we add these:</div><div><br></div><div>We add new Condition's that implement AND of a bunch of Conditions (like the current ConditionSet does), another for OR, and another for NEGATE:</div><div><br></div><div>struct ConditionAnd</div><div>{</div><div>  uint16 format; // 2</div><div>  uint16    conditionCount; // Number of conditions for this conjunction expression.</div>  Offset32To<Condition> conditionOffsets[conditionCount];<div>}</div><div><br></div><div><div>struct ConditionOr<br></div><div>{</div><div>  uint16 format; // 3</div><div>  uint16    conditionCount; // Number of conditions for this disjunction expression.</div>  Offset32To<Condition> conditionOffsets[conditionCount];<div>}</div><div></div></div><div><div><div><br></div><div>struct ConditionNegate<br></div><div>{</div><div>  uint16 format; // 4</div>  Offset32To<Condition> condition;<div>}</div><div><br></div><div>WDYT?</div><div></div></div><div></div><div><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">behdad<br><a href="http://behdad.org/" target="_blank">http://behdad.org/</a></div></div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 11, 2024 at 6:26 AM Skef Iterum <<a href="mailto:skef@skef.org">skef@skef.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
    
  
  <div>
    <p>I'm still trying to think through all of this stuff, but I
      tentatively think that if we added a hack to negate a condition
      set then we'll have enough. <br>
    </p>
    <p>To see the issues involved it may be easiest to work backwards.
      It's not an accident that most programming languages contain the
      combination of boolean expressions (with AND, OR, NOT and some
      equivalent of parentheses) + an if/else if/.../else structure. The
      former lets you express anything you need to, typically quite
      compactly. The latter expresses a set of alternatives such that
      it's guaranteed you'll only get one of them. <br>
    </p>
    <p>With arbitrary boolean expressions it's easy to fake up the
      if/else if/else. If you would have had</p>
    <blockquote>
      <p><font face="monospace">if A<br>
              R<br>
          else if B<br>
              S<br>
          else if C<br>
              T<br>
          else if D<br>
              U<br>
          else<br>
              V</font></p>
    </blockquote>
    <p>you can just do</p>
    <blockquote>
      <p><font face="monospace">if A<br>
              R<br>
          if ~A & B<br>
              S<br>
          if ~A & ~B & C<br>
              T<br>
          if ~A & ~B & ~C & D<br>
              U<br>
          if ~A & ~B & ~C & ~D<br>
              V</font></p>
    </blockquote>
    <p>at the cost of a bit more computation (typically). <br>
    </p>
    <p>This kind of generality was (presumably) thought to be <i>over</i>-general
      for variable fonts, and I don't disagree. But it's worth noting
      what you lose if you lack <i>both</i> arbitrary boolean
      expressions <i>and</i> if/else if/.../else. Say we add condition
      set negation. Then if you have a fairly typical case like the
      following (where brackets indicate a set)<br>
    </p>
    <blockquote>
      <p><font face="monospace">if [A & C]<br>
              R<br>
          else<br>
              S</font></p>
    </blockquote>
    <p>You can replace that with</p>
    <blockquote>
      <p><font face="monospace">if [A & C]<br>
              R<br>
          if ~[A & C]<br>
              S</font></p>
    </blockquote>
    <p>However, <i>at a single level</i> that doesn't extend further.
      So if you have</p>
    <blockquote>
      <p><font face="monospace">if [A & C]<br>
              R<br>
          else if [D & E]<br>
              S<br>
          else<br>
              T</font></p>
    </blockquote>
    <p>(which is just adding a third case), there's no easy way to adapt
      that into pure "if" conditions using the tools available. And
      that's what I've been worried about -- it seems annoying not to be
      able to have three alternatives (with non-trivial conditions)
      spread out over the design space. <br>
    </p>
    <p>However, it seems like you can accomplish the equivalent with an
      extra level. Assume <font face="monospace">R</font>, <font face="monospace">S</font>, and <font face="monospace">T</font>
      are "existing" components. Then you can just do</p>
    <blockquote>
      <p><font face="monospace">a:</font><br>
        <font face="monospace">if [D & E]<br>
              S<br>
          if ~[D & E]<br>
              T</font></p>
      <p><font face="monospace">b:</font><br>
        <font face="monospace">if [A & C]<br>
              R<br>
          if ~[A & C]<br>
              a</font></p>
    </blockquote>
    <p>Now <font face="monospace">b</font> has the right qualities. In
      effect, <font face="monospace">a</font> sometimes has the "wrong"
      contents when <font face="monospace">[A & C]</font> applies
      but you never <i>see</i> it in that case.<br>
    </p>
    <p>So like I said I want to think about this a bit more but I
      tentatively think the thing to do is add means of negating the
      condition set (and I think the Format 5 condition hack would be
      fine for that, actually), and remove the "else" from the
      lookup-based feature variations mechanism to simplify it.</p>
    <p>Skef<br>
    </p>
    <div>On 4/11/24 01:20, Behdad Esfahbod
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="ltr">Hi Skef,
        <div><br>
        </div>
        <div>I'm a bit uncomfortable encoding if/else in VARC. As you
          said on the call, the current design seems like a practical
          compromise. As for negation, we *can* add a flag to the
          component to negate the condition. Maybe that's the right
          approach. But I feel like the conditionSet itself should
          contain the negation. That would reduce sharing though.</div>
        <div><br>
        </div>
        <div>A "negate the rest" condition type sounds good to me.<br>
        </div>
        <div><br clear="all">
          <div>
            <div dir="ltr" class="gmail_signature">behdad<br>
              <a href="http://behdad.org/" target="_blank">http://behdad.org/</a></div>
          </div>
          <br>
        </div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Apr 8, 2024 at 1:55 PM
          Skef Iterum via mpeg-otspec <<a href="mailto:mpeg-otspec@lists.aau.at" target="_blank">mpeg-otspec@lists.aau.at</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <p>A note on conditions as defined in
              WG03-varc-and-other-updates-03.pdf (up for review tomorrow
              morning).</p>
            <p>When I sketched out the VARC condition idea I had them
              arranged in if/else if/.../else sequences. From my reading
              of the document they're currently in "if" form -- a
              condition set can be attached to a component and if it is
              it will only be used if the condition set evaluates to
              true.</p>
            <p>There's nothing wrong with that semantic; it may be
              preferable because it's simpler. However, the most common
              case with this system is that you want one shape to render
              in some region of design space (defined by the condition
              set) and another shape to render outside of that. And
              negating a condition <i>set</i> can be expensive and/or
              tricky. So I would recommend that one of these two things
              change:<br>
            </p>
            <ul>
              <li>The if/else if/.../else semantic is restored</li>
              <li>Some way of negating a condition set is added to the
                specification<br>
              </li>
            </ul>
            <p>We talked about the possibility of condition set negation
              in a previous meeting but didn't come to any conclusions.
              It's tricky because the table has no versioning. If we
              wanted to hack negations into the current format the way
              to do that might be to add a new condition format
              (possibly 5 if newfeatvar_spec.pdf is accepted) that looks
              something like:<br>
            </p>
            <blockquote>
              <p>ConditionTableFormat5</p>
            </blockquote>
            <blockquote>
              <p><b>Type                   
                  Name                                Description</b></p>
              <p>uint16                 
                Format                              Format (set to 5)</p>
            </blockquote>
            <blockquote>
              <p>When present in a condition set this condition
                indicates the set should apply when<br>
                at least one of the other conditions is false and not
                otherwise. That is, it makes the<br>
                condition set apply when it would normally not and
                vice-versa. There should be at <br>
                most one format 5 condition in a condition set and it
                should be the first.<br>
              </p>
            </blockquote>
            <p>If this is preferred it could be used to replace/simplify
              the trueLookupIndexListOffset/falseLookupIndexListOffset
              pair in the LookupCondition record of newfeatvar_spec.pdf
              to just lookupIndexListOffset (because one could just
              follow the record<br>
              with the "positive" condition set with another record with
              the negated one when needed).</p>
            <p>Skef<br>
            </p>
          </div>
          _______________________________________________<br>
          mpeg-otspec mailing list<br>
          <a href="mailto:mpeg-otspec@lists.aau.at" target="_blank">mpeg-otspec@lists.aau.at</a><br>
          <a href="https://lists.aau.at/mailman/listinfo/mpeg-otspec" rel="noreferrer" target="_blank">https://lists.aau.at/mailman/listinfo/mpeg-otspec</a><br>
        </blockquote>
      </div>
    </blockquote>
  </div>

</blockquote></div>