Search code examples
xsl-foantenna-house

Align fo:float top-flush with wrapping text's ascender line


Is there a technique/method to align a side-float top flush with the ascender line of the text flowing around it?

Here's my example code:

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>
    <fo:simple-page-master master-name="pages">
      <fo:region-body margin-left="1in" margin-right="1in" margin-top="1in" margin-bottom="1in" />
    </fo:simple-page-master>
  </fo:layout-master-set>
  <fo:page-sequence master-reference="pages">
    <fo:flow flow-name="xsl-region-body">
      <fo:wrapper line-stacking-strategy="font-height" line-height.conditionality="discard" line-height="1.8" font-size="24pt">
    
      <fo:block space-after="2lh">
        <fo:float float="start">
          <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
            <fo:block>FLOAT-1</fo:block>
          </fo:block-container>
        </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
    
        <fo:block space-after="2lh">
          <fo:float float="start">
            <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
              <fo:block>FLOAT-2</fo:block>
            </fo:block-container>
        </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
    
      </fo:wrapper>
    </fo:flow>
  </fo:page-sequence>
</fo:root>

I think I understand why this is: For FLOAT-1, the line-height.conditionality="discard" of the wrapping fo:block kicks in at the top of the reference area and removes the upper half-leading portion. This is intended, so that any element in my document starts at the same perceived vertical position, be it a table, image or paragraph. However, when we're not at the top edge of a reference area, the upper portion of the half-leading is not discarded, and the fo:float aligns with the before edge of the line box (not the before edge of the nominal-requested-line-rectangle).

Is there a programmatic, universal technique to have floats anchored at the start of a paragraph align with the paragraph font's ascender line, not its first line box?

I'd like to have FLOAT-2 be aligned the same way visually as FLOAT-1, in any potential location throughout the document. Generally wrapping each and every paragraph also in an outer fo:block-container is likely not an option in my case, as that would have spacing/layout side-effects in many other places, I fear…

I am trying with Antennahouse FO Formatter 7.2.


Solution

    • If the floats are graphics, you can use the axf:initial-letters extension (see https://www.antenna.co.jp/AHF/help/en/ahf-ext.html#axf.initial-letters) to position and size the graphics.
    • You can specify space-before on the fo:block-container in the float.
    • I'm not sure why the line-height.conditionality="discard" isn't always applied, but you can get it back with an fo:initial-property-set.
    • You can set axf:baseline-grid="new" on each fo:block.
    • You can put an fo:block-container around each fo:block (although you've already discounted that option)

    Screenshot of five alternative solutions

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
         line-height="1.8" font-size="24pt"
         line-stacking-strategy="font-height">
      <fo:layout-master-set>
        <fo:simple-page-master master-name="pages">
          <fo:region-body margin-left="1in" margin-right="1in" margin-top="1in" margin-bottom="1in" />
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body" axf:baseline-grid="new">
          <fo:block space-after="2lh" axf:initial-letters="2">
          <fo:external-graphic src="logo-antenna-200x200.png"/>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
          <fo:block space-after="2lh" axf:initial-letters="2">
          <fo:external-graphic src="logo-antenna-200x200.png"/>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body" line-height.conditionality="discard">
        <fo:block space-after="2lh">
              <fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block>FLOAT-1</fo:block>
                </fo:block-container>
            </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
            <fo:block space-after="2lh">
              <fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black" space-before="(1lh - 1em) div 2" space-before.conditionality="retain">
                  <fo:block>FLOAT-2</fo:block>
                </fo:block-container>
            </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body" line-height.conditionality="discard">
          <fo:block space-after="2lh"><fo:initial-property-set line-height.conditionality="discard" />
          <fo:float float="start">
            <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
              <fo:block>FLOAT-1</fo:block>
            </fo:block-container>
          </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
          <fo:block space-after="2lh"><fo:initial-property-set line-height.conditionality="discard" />
          <fo:float float="start">
            <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
              <fo:block>FLOAT-2</fo:block>
            </fo:block-container>
          </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body">
          <fo:block space-after="2lh" axf:baseline-grid="new">
          <fo:float float="start">
            <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
              <fo:block>FLOAT-1</fo:block>
            </fo:block-container>
          </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
          <fo:block space-after="2lh" axf:baseline-grid="new">
          <fo:float float="start">
            <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
              <fo:block>FLOAT-2</fo:block>
            </fo:block-container>
          </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body" line-height.conditionality="discard">
          <fo:block space-after="2lh">
            <fo:float float="start">
              <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                <fo:block>FLOAT-1</fo:block>
              </fo:block-container>
          </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
          <fo:block-container space-after="2lh">
        <fo:block>
              <fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block>FLOAT-2</fo:block>
                </fo:block-container>
            </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
          </fo:block-container>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
    

    Another alternative that uses text-altitude:

      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body">
        <fo:block space-after="2lh" text-altitude="0">
              <fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block line-height.conditionality="discard">FLOAT-1</fo:block>
                </fo:block-container>
            </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
            <fo:block space-after="2lh" text-altitude="0">
              <fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block line-height.conditionality="discard">FLOAT-2</fo:block>
                </fo:block-container>
            </fo:float>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
    

    <fo:inline line-height.conditionality="discard"> around the fo:float:

      <fo:page-sequence master-reference="pages">
        <fo:flow flow-name="xsl-region-body">
        <fo:block line-height.conditionality="discard" space-after="2lh">
              <fo:inline line-height.conditionality="discard"><fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block>FLOAT-1</fo:block>
                </fo:block-container>
            </fo:float></fo:inline>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
            <fo:block line-height.conditionality="discard" space-after="2lh">
              <fo:inline line-height.conditionality="discard"><fo:float float="start">
                <fo:block-container inline-progression-dimension="20%" background-color="yellow" border="1px solid black">
                  <fo:block>FLOAT-2</fo:block>
                </fo:block-container>
            </fo:float></fo:inline>Torem dolor amet adipisicing sed eiusmod incididunt labore dolore aliqua enim minim quis exercitation laboris ut ex commodo Duis irure in in velit cillum eu nulla Excepteur occaecat non sunt.</fo:block>
        </fo:flow>
      </fo:page-sequence>
    

    The fo:inline is aligned with the dominant alphabetic baseline, and the fo:float is aligned with the top of the fo:inline. It's not clear to me why line-height.conditionality="discard" should work on the fo:inline, but it does.