Browse Source

FOP-3164: basic-link not navigating to corresponding footnote by João André Gonçalves

pull/76/merge
Simon Steiner 3 months ago
parent
commit
bfc5d5277a

+ 10
- 0
fop-core/src/main/java/org/apache/fop/area/Area.java View File

@@ -135,6 +135,8 @@ public class Area extends AreaTreeObject implements Serializable {
*/
private List<ChangeBar> changeBarList;

private boolean fromFootnote;

/**
* Returns the active change bar list.
*
@@ -540,4 +542,12 @@ public class Area extends AreaTreeObject implements Serializable {
ipd = effectiveIPD;
}
}

public boolean isFromFootnote() {
return fromFootnote;
}

public void setFromFootnote(boolean fromFootnote) {
this.fromFootnote = fromFootnote;
}
}

+ 19
- 2
fop-core/src/main/java/org/apache/fop/area/inline/InlineParent.java View File

@@ -71,8 +71,16 @@ public class InlineParent extends InlineArea {
}
updateLevel(childArea.getBidiLevel());
int childOffset = childArea.getVirtualOffset();
minChildOffset = Math.min(minChildOffset, childOffset);
maxAfterEdge = Math.max(maxAfterEdge, childOffset + childArea.getVirtualBPD());

// do not offset if the childArea comes from a footnote
// or if the parent itself comes from a footnote
if (!(childArea.isFromFootnote() || isFromFootnote())) {
minChildOffset = Math.min(minChildOffset, childOffset);
maxAfterEdge = Math.max(maxAfterEdge, childOffset + childArea.getVirtualBPD());
} else {
minChildOffset = Math.min(minChildOffset, childArea.getBlockProgressionOffset());
maxAfterEdge = minChildOffset + childArea.getVirtualBPD();
}
}

@Override
@@ -148,5 +156,14 @@ public class InlineParent extends InlineArea {
}
}

@Override
public void setFromFootnote(boolean fromFootnote) {
super.setFromFootnote(fromFootnote);

// set all the children to avoid offsetting any of them
// otherwise we would offset the parent by offsetting the child
for (InlineArea area : inlines) {
area.setFromFootnote(fromFootnote);
}
}
}

+ 10
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java View File

@@ -51,6 +51,8 @@ public abstract class AbstractBaseLayoutManager
*/
private static final Log LOG = LogFactory.getLog(AbstractBaseLayoutManager.class);

private boolean fromFootnote;

/**
* Abstract base layout manager.
*/
@@ -294,4 +296,12 @@ public abstract class AbstractBaseLayoutManager
public void recreateChildrenLMs() {

}

public boolean isFromFootnote() {
return fromFootnote || (getParent() != null && getParent().isFromFootnote());
}

public void setFromFootnote(boolean fromFootnote) {
this.fromFootnote = fromFootnote;
}
}

+ 2
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java View File

@@ -85,6 +85,7 @@ public class FootnoteBodyLayoutManager extends BlockStackingLayoutManager {
lc.setFlags(LayoutContext.LAST_AREA,
(layoutContext.isLastArea() && childLM == lastLM));
// Add the line areas to Area
childLM.setFromFootnote(true);
childLM.addAreas(childPosIter, lc);
}
}
@@ -93,6 +94,7 @@ public class FootnoteBodyLayoutManager extends BlockStackingLayoutManager {
@Override
public void addChildArea(Area childArea) {
childArea.setAreaClass(Area.CLASS_FOOTNOTE);
childArea.setFromFootnote(true);
parentLayoutManager.addChildArea(childArea);
}


+ 4
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/LayoutManager.java View File

@@ -271,4 +271,8 @@ public interface LayoutManager extends PercentBaseContext {
*/
List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
Position positionAtIPDChange, LayoutManager restartAtLM);

boolean isFromFootnote();

void setFromFootnote(boolean fromFootnote);
}

+ 1
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java View File

@@ -155,6 +155,7 @@ public class FootnoteLayoutManager extends InlineStackingLayoutManager {
PositionIterator childPosIter = new PositionIterator(positionList.listIterator());
LayoutManager childLM;
while ((childLM = childPosIter.getNextChildLM()) != null) {
childLM.setFromFootnote(true);
childLM.addAreas(childPosIter, childContext);
childContext.setLeadingSpace(childContext.getTrailingSpace());
childContext.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);

+ 1
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java View File

@@ -540,6 +540,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
// Not sure if lastPos can legally be null or if that masks a different problem.
// But it seems to fix bug 38053.
setTraits(areaCreated, lastPos == null || !isLast(lastPos));
getCurrentArea().setFromFootnote(isFromFootnote());
parentLayoutManager.addChildArea(getCurrentArea());

registerMarkers(

+ 2
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java View File

@@ -187,6 +187,8 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
if (level >= 0) {
ls.setBidiLevel(level);
}
ls.setFromFootnote(isFromFootnote());

parentArea.addChildArea(ls);
}
}

+ 1
- 0
fop-core/src/main/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java View File

@@ -333,6 +333,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
textArea.setTextLetterSpaceAdjust(letterSpaceDim);
textArea.setTextWordSpaceAdjust(wordSpaceDim - spaceCharIPD
- 2 * textArea.getTextLetterSpaceAdjust());
textArea.setFromFootnote(isFromFootnote());
if (context.getIPDAdjust() != 0) {
// add information about space width
textArea.setSpaceDifference(wordSpaceIPD.getOpt() - spaceCharIPD

+ 116
- 0
fop-core/src/test/java/org/apache/fop/area/inline/InlineParentTestCase.java View File

@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.area.inline;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class InlineParentTestCase {

private static final int BLOCK_PROG_OFFSET = -12;

private static final int BPD = 25;

@Test
public void testAddChildAreaMixedFromFootnote() {
InlineParent parent = new InlineParent();
InlineParent firstChild = createChildInlineParent(BLOCK_PROG_OFFSET, BPD, false);
InlineParent secondChild = createChildInlineParent(3 * BLOCK_PROG_OFFSET, 3 * BPD, false);
InlineParent thirdChild = createChildInlineParent(2 * BLOCK_PROG_OFFSET, 2 * BPD, true);
InlineParent forthChild = createChildInlineParent(0, 0, true);

assertEquals("Default Values must be zero", 0, parent.minChildOffset);
assertEquals("Default Values must be zero", 0, parent.getVirtualBPD());

assertAddChildArea(parent, firstChild, -12, 0);
assertAddChildArea(parent, secondChild, -36, 0);
assertAddChildArea(parent, thirdChild, -36, -36);
assertAddChildArea(parent, forthChild, -36, -36);
}

@Test
public void testAddChildAreaNotFromFootnote() {
InlineParent parent = new InlineParent();
InlineParent firstChild = createChildInlineParent(BLOCK_PROG_OFFSET, BPD, false);
InlineParent secondChild = createChildInlineParent(3 * BLOCK_PROG_OFFSET, 3 * BPD, false);
InlineParent thirdChild = createChildInlineParent(2 * BLOCK_PROG_OFFSET, 2 * BPD, false);
InlineParent forthChild = createChildInlineParent(0, 0, false);

assertEquals("Default Values must be zero", 0, parent.minChildOffset);
assertEquals("Default Values must be zero", 0, parent.getVirtualBPD());

assertAddChildArea(parent, firstChild, -12, 0);
assertAddChildArea(parent, secondChild, -36, 0);
assertAddChildArea(parent, thirdChild, -36, 0);
assertAddChildArea(parent, forthChild, -36, 0);
}

@Test
public void testAddChildAreaFromFootnote() {
InlineParent parent = new InlineParent();
InlineParent firstChild = createChildInlineParent(BLOCK_PROG_OFFSET, BPD, true);
InlineParent secondChild = createChildInlineParent(3 * BLOCK_PROG_OFFSET, 3 * BPD, true);
InlineParent thirdChild = createChildInlineParent(2 * BLOCK_PROG_OFFSET, 2 * BPD, true);
InlineParent forthChild = createChildInlineParent(0, 0, true);

assertEquals("Default Values must be zero", 0, parent.minChildOffset);
assertEquals("Default Values must be zero", 0, parent.getVirtualBPD());

assertAddChildArea(parent, firstChild, -12, -12);
assertAddChildArea(parent, secondChild, -36, -36);
assertAddChildArea(parent, thirdChild, -36, -36);
assertAddChildArea(parent, forthChild, -36, -36);
}

private void assertAddChildArea(InlineParent parent, InlineParent child,
int minChildOffset, int maxAfterEdge) {
parent.addChildArea(child);

// the virtualBPD is the subtraction of the maxAfterEdge with the minChildOffset
// by adding the minChildOffset to the virtualBPD we get the maxAfterEdge alone
int parentMaxAfterEdge = parent.getVirtualBPD() + parent.minChildOffset;

if (!child.isFromFootnote()) {
assertEquals("Must be set to the min of the current minChildOffset and the "
+ "sum of the child's virtualOffset with the current value of the minChildOffset",
minChildOffset, parent.minChildOffset);
assertEquals("Must be set to the max of the current maxAfterEdge and the "
+ "result of the sum of the child's virtualOffset with child's the virtualBPD",
maxAfterEdge, parentMaxAfterEdge);
} else {
assertEquals("Must be set to the min of the current minChildOffset and the "
+ "sum of the child's blockProgressionOffset with the current value "
+ "of the minChildOffset",
minChildOffset, parent.minChildOffset);
assertEquals("Must be the result of the sum of the maxAfterEdge "
+ "with the child's virtualBPD", maxAfterEdge, parentMaxAfterEdge);
}
}

private InlineParent createChildInlineParent(int bpo, int bpd, boolean footnote) {
InlineParent child = new InlineParent();
child.setBlockProgressionOffset(bpo);
child.setBPD(bpd);
child.setFromFootnote(footnote);

return child;
}
}

+ 90
- 0
fop/test/layoutengine/standard-testcases/footnote_basic_link.xml View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<testcase>
<info>
<p>
This test checks footnotes.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
<fo:simple-page-master master-name="normal" page-width="5in" page-height="3in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<!-- Mid-Link Footnote -->
<fo:block>
<fo:basic-link external-destination="https://www.google.com/">
<fo:inline>This is a link with a footnote</fo:inline>
<fo:footnote>
<fo:inline>
<fo:basic-link id="fn-ref-2" internal-destination="fn-2" color="blue">
<fo:inline baseline-shift="super" font-size="80%">1</fo:inline>
</fo:basic-link>
</fo:inline>
<fo:footnote-body>
<fo:block color="black" text-decoration="none">
<fo:table table-layout="fixed" width="100%">
<fo:table-column column-width="proportional-column-width(5)"/>
<fo:table-column column-width="proportional-column-width(95)"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell>
<fo:block>
<fo:basic-link id="fn-2" internal-destination="fn-ref-2" color="blue">1</fo:basic-link>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>Note text</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:block>
</fo:footnote-body>
</fo:footnote>
<fo:inline> inside</fo:inline>
</fo:basic-link>
</fo:block>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- block with footnote -->
<eval expected="This is a link with a footnote 1 inside" xpath="//inlineparent[1]"/>
<eval expected=" 1" xpath="//inlineparent[2]"/>
<!-- the footnote -->
<eval expected="4552" xpath="//inlineparent[1]/@offset"/>
<eval expected="11100" xpath="//inlineparent[1]/@bpd"/>
<eval expected="11100" xpath="//inlineparent[1]/@bpda"/>

<eval expected="0" xpath="//inlineparent[2]/@offset"/>
<eval expected="11100" xpath="//inlineparent[2]/@bpd"/>
<eval expected="11100" xpath="//inlineparent[2]/@bpda"/>

<eval expected="15652" xpath="//lineArea/@bpd"/>
<eval expected="18952" xpath="//lineArea/@bpda"/>
</checks>
</testcase>

Loading…
Cancel
Save