diff options
author | Simon Steiner <ssteiner@apache.org> | 2020-01-29 11:28:26 +0000 |
---|---|---|
committer | Simon Steiner <ssteiner@apache.org> | 2020-01-29 11:28:26 +0000 |
commit | 895a332bd65c6c3d5410c95fff61b576cdabfd8b (patch) | |
tree | 5eb6e537f87362b930cde2705bf4665ad81e69fb | |
parent | ed7ad907820b7221402d14bcea49646f6fa62384 (diff) | |
download | xmlgraphics-fop-895a332bd65c6c3d5410c95fff61b576cdabfd8b.tar.gz xmlgraphics-fop-895a332bd65c6c3d5410c95fff61b576cdabfd8b.zip |
FOP-2909: Hide empty blocks from structure tree
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1873298 13f79535-47bb-0310-9956-ffa450edef68
12 files changed, 582 insertions, 125 deletions
diff --git a/fop-core/src/main/java/org/apache/fop/accessibility/Accessibility.java b/fop-core/src/main/java/org/apache/fop/accessibility/Accessibility.java index 88ec6dbdd..8a28a94d6 100644 --- a/fop-core/src/main/java/org/apache/fop/accessibility/Accessibility.java +++ b/fop-core/src/main/java/org/apache/fop/accessibility/Accessibility.java @@ -28,6 +28,9 @@ public final class Accessibility { /** Constant string for the rendering options key to enable accessibility features. */ public static final String ACCESSIBILITY = "accessibility"; + /** Constant string for the rendering options key to suppress empty tags from structure tree. */ + public static final String KEEP_EMPTY_TAGS = "keep-empty-tags"; + /** * The value to be set on the 'role' property for the element and its descendants to * be considered as artifacts. diff --git a/fop-core/src/main/java/org/apache/fop/accessibility/fo/Event.java b/fop-core/src/main/java/org/apache/fop/accessibility/fo/Event.java new file mode 100644 index 000000000..d76345558 --- /dev/null +++ b/fop-core/src/main/java/org/apache/fop/accessibility/fo/Event.java @@ -0,0 +1,61 @@ +/* + * 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.accessibility.fo; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fop.fo.FOEventHandler; + +class Event { + private List<Event> children = new ArrayList<Event>(); + protected FOEventHandler eventHandler; + protected Event parent; + protected boolean hasContent; + + public Event(FO2StructureTreeConverter structureTreeConverter) { + eventHandler = structureTreeConverter.converter; + } + + public Event(Event parent) { + this.parent = parent; + } + + public void run() { + if (hasContent()) { + for (Event e : children) { + e.run(); + } + } + children.clear(); + } + + private boolean hasContent() { + for (Event e : children) { + if (e.hasContent()) { + return true; + } + } + return hasContent; + } + + public void add(Event child) { + children.add(child); + } +} diff --git a/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java b/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java index 4614a7005..2381f2f03 100644 --- a/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java +++ b/fop-core/src/main/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java @@ -73,7 +73,7 @@ import org.apache.fop.fo.properties.CommonAccessibilityHolder; public class FO2StructureTreeConverter extends DelegatingFOEventHandler { /** The top of the {@link converters} stack. */ - private FOEventHandler converter; + protected FOEventHandler converter; private Stack<FOEventHandler> converters = new Stack<FOEventHandler>(); @@ -99,6 +99,42 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } + private Event root = new Event((Event) null); + private Event currentNode = root; + + private void startContent(Event event, boolean hasContent) { + if (getUserAgent().isKeepEmptyTags()) { + event.run(); + } else { + Event node = new Event(currentNode); + event.hasContent = hasContent; + node.add(event); + currentNode.add(node); + currentNode = node; + } + } + + private void content(Event event, boolean hasContent) { + if (getUserAgent().isKeepEmptyTags()) { + event.run(); + } else { + currentNode.add(event); + event.hasContent = hasContent; + } + } + + private void endContent(Event event) { + if (getUserAgent().isKeepEmptyTags()) { + event.run(); + } else { + currentNode.add(event); + currentNode = currentNode.parent; + if (currentNode == root) { + root.run(); + } + } + } + /** * Creates a new instance. * @@ -149,51 +185,83 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override - public void startPageNumber(PageNumber pagenum) { - converter.startPageNumber(pagenum); + public void startPageNumber(final PageNumber pagenum) { + startContent(new Event(this) { + public void run() { + eventHandler.startPageNumber(pagenum); + } + }, true); super.startPageNumber(pagenum); } @Override - public void endPageNumber(PageNumber pagenum) { - converter.endPageNumber(pagenum); + public void endPageNumber(final PageNumber pagenum) { + endContent(new Event(this) { + public void run() { + eventHandler.endPageNumber(pagenum); + } + }); super.endPageNumber(pagenum); } @Override - public void startPageNumberCitation(PageNumberCitation pageCite) { - converter.startPageNumberCitation(pageCite); + public void startPageNumberCitation(final PageNumberCitation pageCite) { + startContent(new Event(this) { + public void run() { + eventHandler.startPageNumberCitation(pageCite); + } + }, true); super.startPageNumberCitation(pageCite); } @Override - public void endPageNumberCitation(PageNumberCitation pageCite) { - converter.endPageNumberCitation(pageCite); + public void endPageNumberCitation(final PageNumberCitation pageCite) { + endContent(new Event(this) { + public void run() { + eventHandler.endPageNumberCitation(pageCite); + } + }); super.endPageNumberCitation(pageCite); } @Override - public void startPageNumberCitationLast(PageNumberCitationLast pageLast) { - converter.startPageNumberCitationLast(pageLast); + public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) { + startContent(new Event(this) { + public void run() { + eventHandler.startPageNumberCitationLast(pageLast); + } + }, true); super.startPageNumberCitationLast(pageLast); } @Override - public void endPageNumberCitationLast(PageNumberCitationLast pageLast) { - converter.endPageNumberCitationLast(pageLast); + public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) { + endContent(new Event(this) { + public void run() { + eventHandler.endPageNumberCitationLast(pageLast); + } + }); super.endPageNumberCitationLast(pageLast); } @Override - public void startStatic(StaticContent staticContent) { + public void startStatic(final StaticContent staticContent) { handleStartArtifact(staticContent); - converter.startStatic(staticContent); + startContent(new Event(this) { + public void run() { + eventHandler.startStatic(staticContent); + } + }, true); super.startStatic(staticContent); } @Override - public void endStatic(StaticContent staticContent) { - converter.endStatic(staticContent); + public void endStatic(final StaticContent staticContent) { + endContent(new Event(this) { + public void run() { + eventHandler.endStatic(staticContent); + } + }); handleEndArtifact(staticContent); super.endStatic(staticContent); } @@ -211,277 +279,457 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override - public void startBlock(Block bl) { - converter.startBlock(bl); + public void startBlock(final Block bl) { + startContent(new Event(this) { + public void run() { + eventHandler.startBlock(bl); + } + }, false); super.startBlock(bl); } @Override - public void endBlock(Block bl) { - converter.endBlock(bl); + public void endBlock(final Block bl) { + endContent(new Event(this) { + public void run() { + eventHandler.endBlock(bl); + } + }); super.endBlock(bl); } @Override - public void startBlockContainer(BlockContainer blc) { - converter.startBlockContainer(blc); + public void startBlockContainer(final BlockContainer blc) { + startContent(new Event(this) { + public void run() { + eventHandler.startBlockContainer(blc); + } + }, false); super.startBlockContainer(blc); } @Override - public void endBlockContainer(BlockContainer blc) { - converter.endBlockContainer(blc); + public void endBlockContainer(final BlockContainer blc) { + endContent(new Event(this) { + public void run() { + eventHandler.endBlockContainer(blc); + } + }); super.endBlockContainer(blc); } @Override - public void startInline(Inline inl) { - converter.startInline(inl); + public void startInline(final Inline inl) { + startContent(new Event(this) { + public void run() { + eventHandler.startInline(inl); + } + }, true); super.startInline(inl); } @Override - public void endInline(Inline inl) { - converter.endInline(inl); + public void endInline(final Inline inl) { + endContent(new Event(this) { + public void run() { + eventHandler.endInline(inl); + } + }); super.endInline(inl); } @Override - public void startTable(Table tbl) { - converter.startTable(tbl); + public void startTable(final Table tbl) { + startContent(new Event(this) { + public void run() { + eventHandler.startTable(tbl); + } + }, true); super.startTable(tbl); } @Override - public void endTable(Table tbl) { - converter.endTable(tbl); + public void endTable(final Table tbl) { + endContent(new Event(this) { + public void run() { + eventHandler.endTable(tbl); + } + }); super.endTable(tbl); } @Override - public void startColumn(TableColumn tc) { - converter.startColumn(tc); + public void startColumn(final TableColumn tc) { + startContent(new Event(this) { + public void run() { + eventHandler.startColumn(tc); + } + }, true); super.startColumn(tc); } @Override - public void endColumn(TableColumn tc) { - converter.endColumn(tc); + public void endColumn(final TableColumn tc) { + endContent(new Event(this) { + public void run() { + eventHandler.endColumn(tc); + } + }); super.endColumn(tc); } @Override - public void startHeader(TableHeader header) { - converter.startHeader(header); + public void startHeader(final TableHeader header) { + startContent(new Event(this) { + public void run() { + eventHandler.startHeader(header); + } + }, true); super.startHeader(header); } @Override - public void endHeader(TableHeader header) { - converter.endHeader(header); + public void endHeader(final TableHeader header) { + endContent(new Event(this) { + public void run() { + eventHandler.endHeader(header); + } + }); super.endHeader(header); } @Override - public void startFooter(TableFooter footer) { - converter.startFooter(footer); + public void startFooter(final TableFooter footer) { + startContent(new Event(this) { + public void run() { + eventHandler.startFooter(footer); + } + }, true); super.startFooter(footer); } @Override - public void endFooter(TableFooter footer) { - converter.endFooter(footer); + public void endFooter(final TableFooter footer) { + endContent(new Event(this) { + public void run() { + eventHandler.endFooter(footer); + } + }); super.endFooter(footer); } @Override - public void startBody(TableBody body) { - converter.startBody(body); + public void startBody(final TableBody body) { + startContent(new Event(this) { + public void run() { + eventHandler.startBody(body); + } + }, true); super.startBody(body); } @Override - public void endBody(TableBody body) { - converter.endBody(body); + public void endBody(final TableBody body) { + endContent(new Event(this) { + public void run() { + eventHandler.endBody(body); + } + }); super.endBody(body); } @Override - public void startRow(TableRow tr) { - converter.startRow(tr); + public void startRow(final TableRow tr) { + startContent(new Event(this) { + public void run() { + eventHandler.startRow(tr); + } + }, true); super.startRow(tr); } @Override - public void endRow(TableRow tr) { - converter.endRow(tr); + public void endRow(final TableRow tr) { + endContent(new Event(this) { + public void run() { + eventHandler.endRow(tr); + } + }); super.endRow(tr); } @Override - public void startCell(TableCell tc) { - converter.startCell(tc); + public void startCell(final TableCell tc) { + startContent(new Event(this) { + public void run() { + eventHandler.startCell(tc); + } + }, true); super.startCell(tc); } @Override - public void endCell(TableCell tc) { - converter.endCell(tc); + public void endCell(final TableCell tc) { + endContent(new Event(this) { + public void run() { + eventHandler.endCell(tc); + } + }); super.endCell(tc); } @Override - public void startList(ListBlock lb) { - converter.startList(lb); + public void startList(final ListBlock lb) { + startContent(new Event(this) { + public void run() { + eventHandler.startList(lb); + } + }, true); super.startList(lb); } @Override - public void endList(ListBlock lb) { - converter.endList(lb); + public void endList(final ListBlock lb) { + endContent(new Event(this) { + public void run() { + eventHandler.endList(lb); + } + }); super.endList(lb); } @Override - public void startListItem(ListItem li) { - converter.startListItem(li); + public void startListItem(final ListItem li) { + startContent(new Event(this) { + public void run() { + eventHandler.startListItem(li); + } + }, true); super.startListItem(li); } @Override - public void endListItem(ListItem li) { - converter.endListItem(li); + public void endListItem(final ListItem li) { + endContent(new Event(this) { + public void run() { + eventHandler.endListItem(li); + } + }); super.endListItem(li); } @Override - public void startListLabel(ListItemLabel listItemLabel) { - converter.startListLabel(listItemLabel); + public void startListLabel(final ListItemLabel listItemLabel) { + startContent(new Event(this) { + public void run() { + eventHandler.startListLabel(listItemLabel); + } + }, true); super.startListLabel(listItemLabel); } @Override - public void endListLabel(ListItemLabel listItemLabel) { - converter.endListLabel(listItemLabel); + public void endListLabel(final ListItemLabel listItemLabel) { + endContent(new Event(this) { + public void run() { + eventHandler.endListLabel(listItemLabel); + } + }); super.endListLabel(listItemLabel); } @Override - public void startListBody(ListItemBody listItemBody) { - converter.startListBody(listItemBody); + public void startListBody(final ListItemBody listItemBody) { + startContent(new Event(this) { + public void run() { + eventHandler.startListBody(listItemBody); + } + }, true); super.startListBody(listItemBody); } @Override - public void endListBody(ListItemBody listItemBody) { - converter.endListBody(listItemBody); + public void endListBody(final ListItemBody listItemBody) { + endContent(new Event(this) { + public void run() { + eventHandler.endListBody(listItemBody); + } + }); super.endListBody(listItemBody); } @Override public void startMarkup() { - converter.startMarkup(); + startContent(new Event(this) { + public void run() { + eventHandler.startMarkup(); + } + }, true); super.startMarkup(); } @Override public void endMarkup() { - converter.endMarkup(); + endContent(new Event(this) { + public void run() { + eventHandler.endMarkup(); + } + }); super.endMarkup(); } @Override - public void startLink(BasicLink basicLink) { - converter.startLink(basicLink); + public void startLink(final BasicLink basicLink) { + startContent(new Event(this) { + public void run() { + eventHandler.startLink(basicLink); + } + }, true); super.startLink(basicLink); } @Override - public void endLink(BasicLink basicLink) { - converter.endLink(basicLink); + public void endLink(final BasicLink basicLink) { + endContent(new Event(this) { + public void run() { + eventHandler.endLink(basicLink); + } + }); super.endLink(basicLink); } @Override - public void image(ExternalGraphic eg) { - converter.image(eg); + public void image(final ExternalGraphic eg) { + content(new Event(this) { + public void run() { + eventHandler.image(eg); + } + }, true); super.image(eg); } @Override public void pageRef() { - converter.pageRef(); + content(new Event(this) { + public void run() { + eventHandler.pageRef(); + } + }, true); super.pageRef(); } @Override - public void startInstreamForeignObject(InstreamForeignObject ifo) { - converter.startInstreamForeignObject(ifo); + public void startInstreamForeignObject(final InstreamForeignObject ifo) { + startContent(new Event(this) { + public void run() { + eventHandler.startInstreamForeignObject(ifo); + } + }, true); super.startInstreamForeignObject(ifo); } @Override - public void endInstreamForeignObject(InstreamForeignObject ifo) { - converter.endInstreamForeignObject(ifo); + public void endInstreamForeignObject(final InstreamForeignObject ifo) { + endContent(new Event(this) { + public void run() { + eventHandler.endInstreamForeignObject(ifo); + } + }); super.endInstreamForeignObject(ifo); } @Override - public void startFootnote(Footnote footnote) { - converter.startFootnote(footnote); + public void startFootnote(final Footnote footnote) { + startContent(new Event(this) { + public void run() { + eventHandler.startFootnote(footnote); + } + }, true); super.startFootnote(footnote); } @Override - public void endFootnote(Footnote footnote) { - converter.endFootnote(footnote); + public void endFootnote(final Footnote footnote) { + endContent(new Event(this) { + public void run() { + eventHandler.endFootnote(footnote); + } + }); super.endFootnote(footnote); } @Override - public void startFootnoteBody(FootnoteBody body) { - converter.startFootnoteBody(body); + public void startFootnoteBody(final FootnoteBody body) { + startContent(new Event(this) { + public void run() { + eventHandler.startFootnoteBody(body); + } + }, true); super.startFootnoteBody(body); } @Override - public void endFootnoteBody(FootnoteBody body) { - converter.endFootnoteBody(body); + public void endFootnoteBody(final FootnoteBody body) { + endContent(new Event(this) { + public void run() { + eventHandler.endFootnoteBody(body); + } + }); super.endFootnoteBody(body); } @Override - public void startLeader(Leader l) { + public void startLeader(final Leader l) { converters.push(converter); converter = eventSwallower; - converter.startLeader(l); + startContent(new Event(this) { + public void run() { + eventHandler.startLeader(l); + } + }, true); super.startLeader(l); } @Override - public void endLeader(Leader l) { - converter.endLeader(l); + public void endLeader(final Leader l) { + endContent(new Event(this) { + public void run() { + eventHandler.endLeader(l); + } + }); converter = converters.pop(); super.endLeader(l); } @Override - public void startWrapper(Wrapper wrapper) { + public void startWrapper(final Wrapper wrapper) { handleStartArtifact(wrapper); - converter.startWrapper(wrapper); + startContent(new Event(this) { + public void run() { + eventHandler.startWrapper(wrapper); + } + }, true); super.startWrapper(wrapper); } @Override - public void endWrapper(Wrapper wrapper) { - converter.endWrapper(wrapper); + public void endWrapper(final Wrapper wrapper) { + endContent(new Event(this) { + public void run() { + eventHandler.endWrapper(wrapper); + } + }); handleEndArtifact(wrapper); super.endWrapper(wrapper); } @Override - public void startRetrieveMarker(RetrieveMarker retrieveMarker) { - converter.startRetrieveMarker(retrieveMarker); + public void startRetrieveMarker(final RetrieveMarker retrieveMarker) { + startContent(new Event(this) { + public void run() { + eventHandler.startRetrieveMarker(retrieveMarker); + } + }, true); saveState(retrieveMarker); super.startRetrieveMarker(retrieveMarker); } @@ -491,15 +739,23 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override - public void endRetrieveMarker(RetrieveMarker retrieveMarker) { - converter.endRetrieveMarker(retrieveMarker); + public void endRetrieveMarker(final RetrieveMarker retrieveMarker) { + endContent(new Event(this) { + public void run() { + eventHandler.endRetrieveMarker(retrieveMarker); + } + }); super.endRetrieveMarker(retrieveMarker); } @Override - public void restoreState(RetrieveMarker retrieveMarker) { + public void restoreState(final RetrieveMarker retrieveMarker) { restoreRetrieveMarkerState(retrieveMarker); - converter.restoreState(retrieveMarker); + content(new Event(this) { + public void run() { + eventHandler.restoreState(retrieveMarker); + } + }, true); super.restoreState(retrieveMarker); } @@ -511,46 +767,74 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler { } @Override - public void startRetrieveTableMarker(RetrieveTableMarker retrieveTableMarker) { - converter.startRetrieveTableMarker(retrieveTableMarker); + public void startRetrieveTableMarker(final RetrieveTableMarker retrieveTableMarker) { + startContent(new Event(this) { + public void run() { + eventHandler.startRetrieveTableMarker(retrieveTableMarker); + } + }, true); saveState(retrieveTableMarker); super.startRetrieveTableMarker(retrieveTableMarker); } @Override - public void endRetrieveTableMarker(RetrieveTableMarker retrieveTableMarker) { - converter.endRetrieveTableMarker(retrieveTableMarker); + public void endRetrieveTableMarker(final RetrieveTableMarker retrieveTableMarker) { + endContent(new Event(this) { + public void run() { + eventHandler.endRetrieveTableMarker(retrieveTableMarker); + } + }); super.endRetrieveTableMarker(retrieveTableMarker); } @Override - public void restoreState(RetrieveTableMarker retrieveTableMarker) { + public void restoreState(final RetrieveTableMarker retrieveTableMarker) { restoreRetrieveMarkerState(retrieveTableMarker); - converter.restoreState(retrieveTableMarker); + currentNode.add(new Event(this) { + public void run() { + eventHandler.restoreState(retrieveTableMarker); + } + }); super.restoreState(retrieveTableMarker); } @Override - public void character(Character c) { - converter.character(c); + public void character(final Character c) { + content(new Event(this) { + public void run() { + eventHandler.character(c); + } + }, true); super.character(c); } @Override - public void characters(FOText foText) { - converter.characters(foText); + public void characters(final FOText foText) { + content(new Event(this) { + public void run() { + eventHandler.characters(foText); + } + }, foText.length() > 0); super.characters(foText); } @Override - public void startExternalDocument(ExternalDocument document) { - converter.startExternalDocument(document); + public void startExternalDocument(final ExternalDocument document) { + startContent(new Event(this) { + public void run() { + eventHandler.startExternalDocument(document); + } + }, true); super.startExternalDocument(document); } @Override - public void endExternalDocument(ExternalDocument document) { - converter.endExternalDocument(document); + public void endExternalDocument(final ExternalDocument document) { + endContent(new Event(this) { + public void run() { + eventHandler.endExternalDocument(document); + } + }); super.endExternalDocument(document); } diff --git a/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java b/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java index 3fd2c9167..9b1566d2e 100644 --- a/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java +++ b/fop-core/src/main/java/org/apache/fop/apps/FOUserAgent.java @@ -149,6 +149,7 @@ public class FOUserAgent { this.resourceResolver = resourceResolver; setTargetResolution(factory.getTargetResolution()); setAccessibility(factory.isAccessibilityEnabled()); + setKeepEmptyTags(factory.isKeepEmptyTags()); imageSessionContext = new AbstractImageSessionContext(factory.getFallbackResolver()) { public ImageContext getParentContext() { @@ -817,4 +818,17 @@ public class FOUserAgent { public HyphenationTreeCache getHyphenationTreeCache() { return factory.getHyphenationTreeCache(); } + + public void setKeepEmptyTags(boolean b) { + getRendererOptions().put(Accessibility.KEEP_EMPTY_TAGS, b); + } + + public boolean isKeepEmptyTags() { + Boolean enabled = (Boolean)getRendererOptions().get(Accessibility.KEEP_EMPTY_TAGS); + if (enabled != null) { + return enabled; + } else { + return true; + } + } } diff --git a/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java b/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java index 7dcbae34c..04b020277 100644 --- a/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java +++ b/fop-core/src/main/java/org/apache/fop/apps/FopConfParser.java @@ -38,6 +38,7 @@ import org.apache.xmlgraphics.image.loader.spi.ImageImplRegistry; import org.apache.xmlgraphics.image.loader.util.Penalty; import org.apache.xmlgraphics.io.ResourceResolver; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.apps.io.InternalResourceResolver; import org.apache.fop.apps.io.ResourceResolverFactory; import org.apache.fop.configuration.Configuration; @@ -185,6 +186,8 @@ public class FopConfParser { if (cfg.getChild("accessibility", false) != null) { try { fopFactoryBuilder.setAccessibility(cfg.getChild("accessibility").getValueAsBoolean()); + fopFactoryBuilder.setKeepEmptyTags( + cfg.getChild("accessibility").getAttributeAsBoolean(Accessibility.KEEP_EMPTY_TAGS, true)); } catch (ConfigurationException e) { LogUtil.handleException(log, e, false); } diff --git a/fop-core/src/main/java/org/apache/fop/apps/FopFactory.java b/fop-core/src/main/java/org/apache/fop/apps/FopFactory.java index e2f81b140..35a0bc373 100644 --- a/fop-core/src/main/java/org/apache/fop/apps/FopFactory.java +++ b/fop-core/src/main/java/org/apache/fop/apps/FopFactory.java @@ -328,6 +328,10 @@ public final class FopFactory implements ImageContext { return config.isAccessibilityEnabled(); } + boolean isKeepEmptyTags() { + return config.isKeepEmptyTags(); + } + /** @see FopFactoryConfig#getImageManager() */ public ImageManager getImageManager() { return config.getImageManager(); diff --git a/fop-core/src/main/java/org/apache/fop/apps/FopFactoryBuilder.java b/fop-core/src/main/java/org/apache/fop/apps/FopFactoryBuilder.java index 84f85cdbd..3fd8414fb 100644 --- a/fop-core/src/main/java/org/apache/fop/apps/FopFactoryBuilder.java +++ b/fop-core/src/main/java/org/apache/fop/apps/FopFactoryBuilder.java @@ -160,6 +160,11 @@ public final class FopFactoryBuilder { return this; } + public FopFactoryBuilder setKeepEmptyTags(boolean b) { + fopFactoryConfigBuilder.setKeepEmptyTags(b); + return this; + } + /** * Sets the {@link LayoutManagerMaker} so that users can configure how FOP creates * {@link org.apache.fop.layoutmgr.LayoutManager}s. @@ -330,6 +335,8 @@ public final class FopFactoryBuilder { private boolean accessibility; + private boolean keepEmptyTags = true; + private LayoutManagerMaker layoutManagerMaker; private URI baseURI; @@ -385,6 +392,10 @@ public final class FopFactoryBuilder { return accessibility; } + public boolean isKeepEmptyTags() { + return keepEmptyTags; + } + /** {@inheritDoc} */ public LayoutManagerMaker getLayoutManagerMakerOverride() { return layoutManagerMaker; @@ -485,6 +496,7 @@ public final class FopFactoryBuilder { private interface FopFactoryConfigBuilder { void setAccessibility(boolean enableAccessibility); + void setKeepEmptyTags(boolean b); void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker); @@ -531,6 +543,9 @@ public final class FopFactoryBuilder { public void setAccessibility(boolean enableAccessibility) { throwIllegalStateException(); } + public void setKeepEmptyTags(boolean b) { + throwIllegalStateException(); + } public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { throwIllegalStateException(); @@ -612,6 +627,10 @@ public final class FopFactoryBuilder { config.accessibility = enableAccessibility; } + public void setKeepEmptyTags(boolean b) { + config.keepEmptyTags = b; + } + public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) { config.layoutManagerMaker = lmMaker; } diff --git a/fop-core/src/main/java/org/apache/fop/apps/FopFactoryConfig.java b/fop-core/src/main/java/org/apache/fop/apps/FopFactoryConfig.java index 37482244b..69b7b25e9 100644 --- a/fop-core/src/main/java/org/apache/fop/apps/FopFactoryConfig.java +++ b/fop-core/src/main/java/org/apache/fop/apps/FopFactoryConfig.java @@ -67,6 +67,7 @@ public interface FopFactoryConfig { * @return true if accessibility features have been requested */ boolean isAccessibilityEnabled(); + boolean isKeepEmptyTags(); /** * Returns the overriding LayoutManagerMaker instance, if any. diff --git a/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java index eddd90ec4..ef7b57f47 100644 --- a/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java @@ -19,12 +19,15 @@ package org.apache.fop.accessibility.fo; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.StringWriter; +import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; @@ -33,6 +36,7 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; @@ -44,6 +48,7 @@ import org.w3c.dom.Document; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -132,6 +137,52 @@ public class FO2StructureTreeConverterTestCase { assertNull(d.getStructureTreeEventHandler().startNode("table-body", null, null)); } + @Test + public void testRemoveBlocks() throws Exception { + compare("<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n" + + " <fo:layout-master-set>\n" + + " <fo:simple-page-master master-name=\"simple\">\n" + + " <fo:region-body />\n" + + " </fo:simple-page-master>\n" + + " </fo:layout-master-set>\n" + + " <fo:page-sequence master-reference=\"simple\">\n" + + " <fo:flow flow-name=\"xsl-region-body\">\n" + + " <fo:block/>" + + " <fo:block><fo:block/></fo:block>\n" + + " <fo:block>a</fo:block>\n" + + " </fo:flow>\n" + + " </fo:page-sequence>\n" + + "</fo:root>\n", + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<structure-tree-sequence>\n" + + "<structure-tree xmlns=\"http://xmlgraphics.apache.org/fop/intermediate\" " + + "xmlns:foi=\"http://xmlgraphics.apache.org/fop/internal\" " + + "xmlns:fox=\"http://xmlgraphics.apache.org/fop/extensions\">\n" + + "<fo:flow xmlns:fo=\"http://www.w3.org/1999/XSL/Format\" flow-name=\"xsl-region-body\">\n" + + "<fo:block>\n" + + "<marked-content/>\n" + + "</fo:block>\n" + + "</fo:flow>\n" + + "</structure-tree>\n" + + "</structure-tree-sequence>\n"); + } + + private void compare(final String fo, String tree) throws Exception { + foLoader = new FOLoader("") { + public InputStream getFoInputStream() { + return new ByteArrayInputStream(fo.getBytes()); + } + }; + DOMResult actualStructureTree = buildActualStructureTree(); + Document doc = (Document) actualStructureTree.getNode(); + StringWriter sw = new StringWriter(); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.transform(new DOMSource(doc), new StreamResult(sw)); + assertEquals(tree, sw.toString()); + } + private void testConverter(String foResourceName) throws Exception { foLoader = new FOLoader(foResourceName); DOMResult expectedStructureTree = loadExpectedStructureTree(); @@ -216,6 +267,7 @@ public class FO2StructureTreeConverterTestCase { private static FOUserAgent createFOUserAgent(FODocumentParser documentParser) { FOUserAgent userAgent = documentParser.createFOUserAgent(); userAgent.setAccessibility(true); + userAgent.setKeepEmptyTags(false); return userAgent; } diff --git a/fop-core/src/test/java/org/apache/fop/apps/FopConfBuilder.java b/fop-core/src/test/java/org/apache/fop/apps/FopConfBuilder.java index 8ad0192d6..f8a3d2822 100644 --- a/fop-core/src/test/java/org/apache/fop/apps/FopConfBuilder.java +++ b/fop-core/src/test/java/org/apache/fop/apps/FopConfBuilder.java @@ -43,6 +43,7 @@ import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.render.RendererConfigOption; /** @@ -137,8 +138,12 @@ public class FopConfBuilder implements FontConfigurator<FopConfBuilder> { * @param setAccessibility true to enable accessibility features * @return <b>this</b> */ - public FopConfBuilder setAccessibility(boolean setAccessibility) { - return createElement("accessibility", String.valueOf(setAccessibility)); + public FopConfBuilder setAccessibility(boolean setAccessibility, boolean keepEmptyTags) { + Element el = fopConfDOM.createElement(Accessibility.ACCESSIBILITY); + el.setAttribute(Accessibility.KEEP_EMPTY_TAGS, String.valueOf(keepEmptyTags)); + el.appendChild(fopConfDOM.createTextNode(String.valueOf(setAccessibility))); + root.appendChild(el); + return this; } @Deprecated diff --git a/fop-core/src/test/java/org/apache/fop/apps/FopConfParserTestCase.java b/fop-core/src/test/java/org/apache/fop/apps/FopConfParserTestCase.java index dc794fdb8..d632c02f3 100644 --- a/fop-core/src/test/java/org/apache/fop/apps/FopConfParserTestCase.java +++ b/fop-core/src/test/java/org/apache/fop/apps/FopConfParserTestCase.java @@ -89,11 +89,17 @@ public class FopConfParserTestCase { @Test public void testAccessibility() { - builder.setAccessibility(false); + builder.setAccessibility(false, true); assertFalse(buildFactory().isAccessibilityEnabled()); } @Test + public void testAccessibilityKeepEmptyTags() { + builder.setAccessibility(true, false); + assertFalse(buildFactory().isKeepEmptyTags()); + } + + @Test public void testSourceResolution() { float srcRes = 123.456f; builder.setSourceResolution(srcRes); diff --git a/fop-core/src/test/java/org/apache/fop/apps/MutableConfig.java b/fop-core/src/test/java/org/apache/fop/apps/MutableConfig.java index 201408235..2f70f4124 100644 --- a/fop-core/src/test/java/org/apache/fop/apps/MutableConfig.java +++ b/fop-core/src/test/java/org/apache/fop/apps/MutableConfig.java @@ -52,6 +52,11 @@ public final class MutableConfig implements FopFactoryConfig { return delegate.isAccessibilityEnabled(); } + + public boolean isKeepEmptyTags() { + return delegate.isKeepEmptyTags(); + } + public LayoutManagerMaker getLayoutManagerMakerOverride() { return delegate.getLayoutManagerMakerOverride(); } |