*/ | */ | ||||
private List<ChangeBar> changeBarList; | private List<ChangeBar> changeBarList; | ||||
private boolean fromFootnote; | |||||
/** | /** | ||||
* Returns the active change bar list. | * Returns the active change bar list. | ||||
* | * | ||||
ipd = effectiveIPD; | ipd = effectiveIPD; | ||||
} | } | ||||
} | } | ||||
public boolean isFromFootnote() { | |||||
return fromFootnote; | |||||
} | |||||
public void setFromFootnote(boolean fromFootnote) { | |||||
this.fromFootnote = fromFootnote; | |||||
} | |||||
} | } |
} | } | ||||
updateLevel(childArea.getBidiLevel()); | updateLevel(childArea.getBidiLevel()); | ||||
int childOffset = childArea.getVirtualOffset(); | 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 | @Override | ||||
} | } | ||||
} | } | ||||
@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); | |||||
} | |||||
} | |||||
} | } |
*/ | */ | ||||
private static final Log LOG = LogFactory.getLog(AbstractBaseLayoutManager.class); | private static final Log LOG = LogFactory.getLog(AbstractBaseLayoutManager.class); | ||||
private boolean fromFootnote; | |||||
/** | /** | ||||
* Abstract base layout manager. | * Abstract base layout manager. | ||||
*/ | */ | ||||
public void recreateChildrenLMs() { | public void recreateChildrenLMs() { | ||||
} | } | ||||
public boolean isFromFootnote() { | |||||
return fromFootnote || (getParent() != null && getParent().isFromFootnote()); | |||||
} | |||||
public void setFromFootnote(boolean fromFootnote) { | |||||
this.fromFootnote = fromFootnote; | |||||
} | |||||
} | } |
lc.setFlags(LayoutContext.LAST_AREA, | lc.setFlags(LayoutContext.LAST_AREA, | ||||
(layoutContext.isLastArea() && childLM == lastLM)); | (layoutContext.isLastArea() && childLM == lastLM)); | ||||
// Add the line areas to Area | // Add the line areas to Area | ||||
childLM.setFromFootnote(true); | |||||
childLM.addAreas(childPosIter, lc); | childLM.addAreas(childPosIter, lc); | ||||
} | } | ||||
} | } | ||||
@Override | @Override | ||||
public void addChildArea(Area childArea) { | public void addChildArea(Area childArea) { | ||||
childArea.setAreaClass(Area.CLASS_FOOTNOTE); | childArea.setAreaClass(Area.CLASS_FOOTNOTE); | ||||
childArea.setFromFootnote(true); | |||||
parentLayoutManager.addChildArea(childArea); | parentLayoutManager.addChildArea(childArea); | ||||
} | } | ||||
*/ | */ | ||||
List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | ||||
Position positionAtIPDChange, LayoutManager restartAtLM); | Position positionAtIPDChange, LayoutManager restartAtLM); | ||||
boolean isFromFootnote(); | |||||
void setFromFootnote(boolean fromFootnote); | |||||
} | } |
PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); | ||||
LayoutManager childLM; | LayoutManager childLM; | ||||
while ((childLM = childPosIter.getNextChildLM()) != null) { | while ((childLM = childPosIter.getNextChildLM()) != null) { | ||||
childLM.setFromFootnote(true); | |||||
childLM.addAreas(childPosIter, childContext); | childLM.addAreas(childPosIter, childContext); | ||||
childContext.setLeadingSpace(childContext.getTrailingSpace()); | childContext.setLeadingSpace(childContext.getTrailingSpace()); | ||||
childContext.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); | childContext.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true); |
// Not sure if lastPos can legally be null or if that masks a different problem. | // Not sure if lastPos can legally be null or if that masks a different problem. | ||||
// But it seems to fix bug 38053. | // But it seems to fix bug 38053. | ||||
setTraits(areaCreated, lastPos == null || !isLast(lastPos)); | setTraits(areaCreated, lastPos == null || !isLast(lastPos)); | ||||
getCurrentArea().setFromFootnote(isFromFootnote()); | |||||
parentLayoutManager.addChildArea(getCurrentArea()); | parentLayoutManager.addChildArea(getCurrentArea()); | ||||
registerMarkers( | registerMarkers( |
if (level >= 0) { | if (level >= 0) { | ||||
ls.setBidiLevel(level); | ls.setBidiLevel(level); | ||||
} | } | ||||
ls.setFromFootnote(isFromFootnote()); | |||||
parentArea.addChildArea(ls); | parentArea.addChildArea(ls); | ||||
} | } | ||||
} | } |
textArea.setTextLetterSpaceAdjust(letterSpaceDim); | textArea.setTextLetterSpaceAdjust(letterSpaceDim); | ||||
textArea.setTextWordSpaceAdjust(wordSpaceDim - spaceCharIPD | textArea.setTextWordSpaceAdjust(wordSpaceDim - spaceCharIPD | ||||
- 2 * textArea.getTextLetterSpaceAdjust()); | - 2 * textArea.getTextLetterSpaceAdjust()); | ||||
textArea.setFromFootnote(isFromFootnote()); | |||||
if (context.getIPDAdjust() != 0) { | if (context.getIPDAdjust() != 0) { | ||||
// add information about space width | // add information about space width | ||||
textArea.setSpaceDifference(wordSpaceIPD.getOpt() - spaceCharIPD | textArea.setSpaceDifference(wordSpaceIPD.getOpt() - spaceCharIPD |
/* | |||||
* 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; | |||||
} | |||||
} |
<?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> |