git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1608314 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
if (log.isDebugEnabled()) { | if (log.isDebugEnabled()) { | ||||
log.debug("BD: RESOLVE: " + ps); | log.debug("BD: RESOLVE: " + ps); | ||||
} | } | ||||
List ranges = pruneEmptyRanges(ps.collectDelimitedTextRanges(new Stack())); | |||||
// 1. collect delimited text ranges | |||||
List ranges = ps.collectDelimitedTextRanges(new Stack()); | |||||
if (log.isDebugEnabled()) { | |||||
dumpRanges("BD: RESOLVE: RANGES:", ranges); | |||||
} | |||||
// 2. prune empty ranges | |||||
ranges = pruneEmptyRanges(ranges); | |||||
if (log.isDebugEnabled()) { | |||||
dumpRanges("BD: RESOLVE: PRUNED RANGES:", ranges); | |||||
} | |||||
// 3. resolve inline directionaly of unpruned ranges | |||||
resolveInlineDirectionality(ranges); | resolveInlineDirectionality(ranges); | ||||
} | } | ||||
log.debug(ir); | log.debug(ir); | ||||
} | } | ||||
} | } | ||||
private static List pruneEmptyRanges(Stack ranges) { | |||||
private static void dumpRanges(String header, List ranges) { | |||||
log.debug(header); | |||||
for (Iterator it = ranges.iterator(); it.hasNext(); ) { | |||||
DelimitedTextRange r = (DelimitedTextRange) it.next(); | |||||
log.debug(r); | |||||
} | |||||
} | |||||
private static List pruneEmptyRanges(List ranges) { | |||||
Vector rv = new Vector(); | Vector rv = new Vector(); | ||||
for (Iterator it = ranges.iterator(); it.hasNext(); ) { | for (Iterator it = ranges.iterator(); it.hasNext(); ) { | ||||
DelimitedTextRange r = (DelimitedTextRange) it.next(); | DelimitedTextRange r = (DelimitedTextRange) it.next(); |
/** | /** | ||||
* logging instance | * logging instance | ||||
*/ | */ | ||||
private static final Log log = LogFactory.getLog(BidiResolver.class); | |||||
private static final Log log = LogFactory.getLog(UnicodeBidiAlgorithm.class); | |||||
private UnicodeBidiAlgorithm() { | private UnicodeBidiAlgorithm() { | ||||
} | } |
* @param ranges a stack of delimited text ranges | * @param ranges a stack of delimited text ranges | ||||
* @return the (possibly) updated stack of delimited text ranges | * @return the (possibly) updated stack of delimited text ranges | ||||
*/ | */ | ||||
public Stack collectDelimitedTextRanges(Stack ranges) { | |||||
public Stack collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges) { | |||||
// if boundary before, then push new range | // if boundary before, then push new range | ||||
if (isRangeBoundaryBefore()) { | if (isRangeBoundaryBefore()) { | ||||
maybeNewRange(ranges); | maybeNewRange(ranges); | ||||
// get current range, if one exists | // get current range, if one exists | ||||
DelimitedTextRange currentRange; | DelimitedTextRange currentRange; | ||||
if (ranges.size() > 0) { | if (ranges.size() > 0) { | ||||
currentRange = (DelimitedTextRange) ranges.peek(); | |||||
currentRange = ranges.peek(); | |||||
} else { | } else { | ||||
currentRange = null; | currentRange = null; | ||||
} | } | ||||
* @param currentRange the current range or null (if none) | * @param currentRange the current range or null (if none) | ||||
* @return the (possibly) updated stack of delimited text ranges | * @return the (possibly) updated stack of delimited text ranges | ||||
*/ | */ | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, DelimitedTextRange currentRange) { | |||||
for (Iterator it = getChildNodes(); (it != null) && it.hasNext();) { | for (Iterator it = getChildNodes(); (it != null) && it.hasNext();) { | ||||
ranges = ((FONode) it.next()).collectDelimitedTextRanges(ranges); | ranges = ((FONode) it.next()).collectDelimitedTextRanges(ranges); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Conditionally add a new delimited text range to RANGES, where new range is | |||||
* associated with current FONode. A new text range is added unless all of the following are | |||||
* true: | |||||
* <ul> | |||||
* <li>there exists a current range RCUR in RANGES</li> | |||||
* <li>RCUR is empty</li> | |||||
* <li>the node of the RCUR is the same node as FN or a descendent node of FN</li> | |||||
* </ul> | |||||
* Conditionally add a new delimited text range to RANGES. Always add new | |||||
* range unless there are no ranges on the stack yet and this node is not a block item. | |||||
* @param ranges stack of delimited text ranges | * @param ranges stack of delimited text ranges | ||||
* @return new range (if constructed and pushed onto stack) or current range (if any) or null | * @return new range (if constructed and pushed onto stack) or current range (if any) or null | ||||
*/ | */ | ||||
private DelimitedTextRange maybeNewRange(Stack ranges) { | |||||
DelimitedTextRange rCur = null; // current range (top of range stack) | |||||
DelimitedTextRange rNew = null; // new range to be pushed onto range stack | |||||
if (ranges.empty()) { | |||||
if (isBidiRangeBlockItem()) { | |||||
rNew = new DelimitedTextRange(this); | |||||
} | |||||
private DelimitedTextRange maybeNewRange(Stack<DelimitedTextRange> ranges) { | |||||
DelimitedTextRange rCur = !ranges.empty() ? ranges.peek() : null; | |||||
DelimitedTextRange rNew; | |||||
if ((rCur != null) || isBidiRangeBlockItem()) { | |||||
rNew = new DelimitedTextRange(this); | |||||
} else { | } else { | ||||
rCur = (DelimitedTextRange) ranges.peek(); | |||||
if (rCur != null) { | |||||
if (!rCur.isEmpty() || !isSelfOrDescendent(rCur.getNode(), this)) { | |||||
rNew = new DelimitedTextRange(this); | |||||
} | |||||
} | |||||
rNew = null; | |||||
} | } | ||||
if (rNew != null) { | if (rNew != null) { | ||||
ranges.push(rNew); | ranges.push(rNew); | ||||
return isDelimitedTextRangeBoundary(Constants.EN_AFTER); | return isDelimitedTextRangeBoundary(Constants.EN_AFTER); | ||||
} | } | ||||
/** | |||||
* Determine if node N2 is the same or a descendent of node N1. | |||||
*/ | |||||
private static boolean isSelfOrDescendent(FONode n1, FONode n2) { | |||||
for (FONode n = n2; n != null; n = n.getParent()) { | |||||
if (n == n1) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
/** | /** | ||||
* Base iterator interface over a FO's children | * Base iterator interface over a FO's children | ||||
*/ | */ |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
if (currentRange != null) { | if (currentRange != null) { | ||||
currentRange.append(charIterator(), this); | currentRange.append(charIterator(), this); | ||||
} | } |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
if (currentRange != null) { | if (currentRange != null) { | ||||
currentRange.append(CharUtilities.OBJECT_REPLACEMENT_CHARACTER, this); | currentRange.append(CharUtilities.OBJECT_REPLACEMENT_CHARACTER, this); | ||||
} | } |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
if (currentRange != null) { | if (currentRange != null) { | ||||
currentRange.append(CharUtilities.OBJECT_REPLACEMENT_CHARACTER, this); | currentRange.append(CharUtilities.OBJECT_REPLACEMENT_CHARACTER, this); | ||||
} | } |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
char pfx = 0; | char pfx = 0; | ||||
char sfx = 0; | char sfx = 0; | ||||
int unicodeBidi = getUnicodeBidi(); | int unicodeBidi = getUnicodeBidi(); |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
if (currentRange != null) { | if (currentRange != null) { | ||||
currentRange.append(charIterator(), this); | currentRange.append(charIterator(), this); | ||||
} | } |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
if (currentRange != null) { | if (currentRange != null) { | ||||
if (leaderPattern == EN_USECONTENT) { | if (leaderPattern == EN_USECONTENT) { | ||||
ranges = super.collectDelimitedTextRanges(ranges, currentRange); | ranges = super.collectDelimitedTextRanges(ranges, currentRange); |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
ListItemLabel label = getLabel(); | ListItemLabel label = getLabel(); | ||||
if (label != null) { | if (label != null) { | ||||
ranges = label.collectDelimitedTextRanges(ranges); | ranges = label.collectDelimitedTextRanges(ranges); |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
// header sub-tree | // header sub-tree | ||||
TableHeader header = getTableHeader(); | TableHeader header = getTableHeader(); | ||||
if (header != null) { | if (header != null) { |
} | } | ||||
@Override | @Override | ||||
protected Stack collectDelimitedTextRanges(Stack ranges, DelimitedTextRange currentRange) { | |||||
protected Stack<DelimitedTextRange> collectDelimitedTextRanges(Stack<DelimitedTextRange> ranges, | |||||
DelimitedTextRange currentRange) { | |||||
// collect ranges from static content flows | // collect ranges from static content flows | ||||
Map<String, FONode> flows = getFlowMap(); | Map<String, FONode> flows = getFlowMap(); | ||||
if (flows != null) { | if (flows != null) { |
users, i.e. when the behaviour changes and could affect the layout of existing | users, i.e. when the behaviour changes and could affect the layout of existing | ||||
documents. Example: the fix of marks layering will be such a case when it's done. | documents. Example: the fix of marks layering will be such a case when it's done. | ||||
--> | --> | ||||
<release version="FOP Trunk" date="01 November 2013"> | |||||
<release version="FOP Trunk" date="06 July 2014"> | |||||
<action context="Layout" dev="GA" type="fix" fixes-bug="FOP-2388"> | |||||
Fix Arabic text left justified on the first cell of a table with writing mode rl-tb. | |||||
</action> | |||||
<action context="Code" dev="GA" type="fix" fixes-bug="FOP-2311"> | <action context="Code" dev="GA" type="fix" fixes-bug="FOP-2311"> | ||||
Eliminate regression to shorthand properties from Bugzilla 37114 (FOP-1069). | Eliminate regression to shorthand properties from Bugzilla 37114 (FOP-1069). | ||||
</action> | </action> |
<?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 is a testcase for jira #2388: when a 2-row table with WM(rl-tb) is contained in a block | |||||
with WM(lr-tb), then content from both rows should, by default, use WM(rl-tb) from table. Prior | |||||
to fix, the first row was obtaining default WM(lr-tb) from the container block rather than table. | |||||
</p> | |||||
</info> | |||||
<fo> | |||||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||||
<fo:layout-master-set> | |||||
<fo:simple-page-master margin="20mm" master-name="letterPage" page-width="210mm" page-height="297mm"> | |||||
<fo:region-body region-name="letterPageBody"/> | |||||
</fo:simple-page-master> | |||||
</fo:layout-master-set> | |||||
<fo:page-sequence master-reference="letterPage"> | |||||
<fo:flow flow-name="letterPageBody"> | |||||
<fo:block> | |||||
<fo:table writing-mode="rl-tb" table-layout="fixed" width="100%"> | |||||
<fo:table-column column-width="proportional-column-width(100)" column-number="1"/> | |||||
<fo:table-body> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:block font-family="Arial" font-size="12pt" font-weight="normal">يرحب بكم ستاندرد تشارترد بنك و يتطلع لتقديم خدمات الحسابات المصرفية لكم</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
<fo:table-row> | |||||
<fo:table-cell> | |||||
<fo:block font-family="Arial" font-size="12pt" font-weight="normal">يرحب بكم ستاندرد تشارترد بنك و يتطلع لتقديم خدمات الحسابات المصرفية لكم</fo:block> | |||||
</fo:table-cell> | |||||
</fo:table-row> | |||||
</fo:table-body> | |||||
</fo:table> | |||||
</fo:block> | |||||
</fo:flow> | |||||
</fo:page-sequence> | |||||
</fo:root> | |||||
</fo> | |||||
<checks> | |||||
<eval expected="2" xpath="count(//lineArea)"/> | |||||
<eval expected="1" xpath="(//lineArea)[1]/@level"/> | |||||
<eval expected="88800" xpath="(//lineArea)[1]/@end-indent"/> | |||||
<eval expected="1" xpath="(//lineArea)[2]/@level"/> | |||||
<eval expected="88800" xpath="(//lineArea)[2]/@end-indent"/> | |||||
</checks> | |||||
</testcase> |