Skip to content

Commit f49aa84

Browse files
mattgarrishrdeltour
authored andcommitted
feat: check references between Media Overlays and Content documents
Add the following new errors: - Error MED-010 when an item is missing a media-overlay attribute - Error MED-011 when the media-overlay attribute references the wrong overlay - Error MED-012 when the media-overlay attribute references an overlay that does not reference the underlying content document - Error MED-013 when a content doc is referenced from multiple overlays Also Add tests for the new errors. Implementation note: - pull the unique references from the text elements while parsing the overlay documents - then run checks on the affected content documents in the post-processing function.
1 parent 11b652e commit f49aa84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+492
-5
lines changed

src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ private void initialize()
146146
severities.put(MessageId.MED_007, Severity.ERROR);
147147
severities.put(MessageId.MED_008, Severity.ERROR);
148148
severities.put(MessageId.MED_009, Severity.ERROR);
149+
severities.put(MessageId.MED_010, Severity.ERROR);
150+
severities.put(MessageId.MED_011, Severity.ERROR);
151+
severities.put(MessageId.MED_012, Severity.ERROR);
152+
severities.put(MessageId.MED_013, Severity.ERROR);
149153

150154
// NAV
151155
severities.put(MessageId.NAV_001, Severity.ERROR);

src/main/java/com/adobe/epubcheck/messages/MessageId.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ public enum MessageId implements Comparable<MessageId>
140140
MED_007("MED_007"),
141141
MED_008("MED-008"),
142142
MED_009("MED-009"),
143+
MED_010("MED_010"),
144+
MED_011("MED_011"),
145+
MED_012("MED_012"),
146+
MED_013("MED_013"),
143147

144148
// Epub3 based table of content errors
145149
NAV_001("NAV-001"),

src/main/java/com/adobe/epubcheck/opf/OPFChecker.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.adobe.epubcheck.ocf.OCFPackage;
4444
import com.adobe.epubcheck.opf.ValidationContext.ValidationContextBuilder;
4545
import com.adobe.epubcheck.ops.OPSCheckerFactory;
46+
import com.adobe.epubcheck.overlay.OverlayTextChecker;
4647
import com.adobe.epubcheck.util.EPUBVersion;
4748
import com.adobe.epubcheck.util.FeatureEnum;
4849
import com.adobe.epubcheck.util.PathUtil;
@@ -114,6 +115,7 @@ public OPFChecker(ValidationContext context)
114115
newContext.pubTypes(opfData != null ? opfData.getTypes() : null);
115116
newContext.xrefChecker(new XRefChecker(context.ocf.get(), context.report, context.version));
116117
newContext.profile(EPUBProfile.makeOPFCompatible(context.profile, opfData, path, report));
118+
newContext.overlayTextChecker(new OverlayTextChecker());
117119
}
118120
this.context = newContext.build();
119121

src/main/java/com/adobe/epubcheck/opf/OPFChecker30.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.adobe.epubcheck.opf.ResourceCollection.Roles;
4141
import com.adobe.epubcheck.ops.OPSCheckerFactory;
4242
import com.adobe.epubcheck.overlay.OverlayCheckerFactory;
43+
import com.adobe.epubcheck.overlay.OverlayTextChecker;
4344
import com.adobe.epubcheck.util.EPUBVersion;
4445
import com.adobe.epubcheck.util.FeatureEnum;
4546
import com.adobe.epubcheck.util.PathUtil;
@@ -182,6 +183,29 @@ else if (xrefChecker.getTypes(item.getPath()).isEmpty())
182183
}
183184
}
184185
}
186+
187+
if (isBlessedItemType(mediatype, version)) {
188+
// check whether media-overlay attribute needs to be specified
189+
OverlayTextChecker overlayTextChecker = context.overlayTextChecker.get();
190+
String mo = item.getMediaOverlay();
191+
String docpath = item.getPath();
192+
if (overlayTextChecker.isReferencedByOverlay(docpath)) {
193+
if (Strings.isNullOrEmpty(mo)) {
194+
// missing media-overlay attribute
195+
report.message(MessageId.MED_010, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getPath()));
196+
}
197+
else if (!overlayTextChecker.isCorrectOverlay(docpath,mo)) {
198+
// media-overlay attribute references the wrong media overlay
199+
report.message(MessageId.MED_012, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getPath()));
200+
}
201+
}
202+
else {
203+
if (!Strings.isNullOrEmpty(mo)) {
204+
// referenced overlay does not reference this content document
205+
report.message(MessageId.MED_013, EPUBLocation.create(path, item.getLineNumber(), item.getColumnNumber(), item.getPath()));
206+
}
207+
}
208+
}
185209
}
186210

187211
@Override

src/main/java/com/adobe/epubcheck/opf/OPFHandler.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ else if (name.equals("item"))
314314
itemBuilders.put(id.trim(), itemBuilder);
315315
itemBuildersByPath.put(href, itemBuilder);
316316

317+
String mediaOverlay = e.getAttribute("media-overlay");
318+
itemBuilder.mediaOverlay(mediaOverlay);
319+
317320
report.info(href, FeatureEnum.UNIQUE_IDENT, id);
318321
}
319322
}

src/main/java/com/adobe/epubcheck/opf/OPFItem.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,11 @@ public class OPFItem
5454
private final boolean scripted;
5555
private final boolean linear;
5656
private final boolean fixedLayout;
57+
private final String mediaOverlay;
5758

5859
private OPFItem(String id, String path, String mimetype, int lineNumber, int columnNumber,
5960
Optional<String> fallback, Optional<String> fallbackStyle, Set<Property> properties,
60-
boolean ncx, int spinePosition, boolean nav, boolean scripted, boolean linear, boolean fxl)
61+
boolean ncx, int spinePosition, boolean nav, boolean scripted, boolean linear, boolean fxl, String mediaOverlay)
6162
{
6263
this.id = id;
6364
this.path = path;
@@ -74,6 +75,7 @@ private OPFItem(String id, String path, String mimetype, int lineNumber, int col
7475
this.scripted = scripted;
7576
this.linear = linear;
7677
this.fixedLayout = fxl;
78+
this.mediaOverlay = mediaOverlay;
7779
}
7880

7981
/**
@@ -240,6 +242,11 @@ public boolean isFixedLayout()
240242
return fixedLayout;
241243
}
242244

245+
public String getMediaOverlay()
246+
{
247+
return mediaOverlay;
248+
}
249+
243250
@Override
244251
public String toString()
245252
{
@@ -293,6 +300,7 @@ public static final class Builder
293300
private boolean linear = true;
294301
private int spinePosition = -1;
295302
private boolean fxl = false;
303+
private String mediaOverlay;
296304
private ImmutableSet.Builder<Property> propertiesBuilder = new ImmutableSet.Builder<Property>();
297305

298306
/**
@@ -339,6 +347,12 @@ public Builder fixedLayout()
339347

340348
}
341349

350+
public Builder mediaOverlay(String path)
351+
{
352+
this.mediaOverlay = path;
353+
return this;
354+
}
355+
342356
public Builder ncx()
343357
{
344358
this.ncx = true;
@@ -388,7 +402,7 @@ public OPFItem build()
388402
properties, ncx, spinePosition,
389403
properties.contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.NAV)),
390404
properties.contains(PackageVocabs.ITEM_VOCAB.get(PackageVocabs.ITEM_PROPERTIES.SCRIPTED)),
391-
linear, fxl);
405+
linear, fxl, mediaOverlay);
392406
}
393407
}
394408
}

src/main/java/com/adobe/epubcheck/opf/ValidationContext.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.adobe.epubcheck.api.LocalizableReport;
1111
import com.adobe.epubcheck.api.Report;
1212
import com.adobe.epubcheck.ocf.OCFPackage;
13+
import com.adobe.epubcheck.overlay.OverlayTextChecker;
1314
import com.adobe.epubcheck.util.EPUBVersion;
1415
import com.adobe.epubcheck.util.GenericResourceProvider;
1516
import com.adobe.epubcheck.vocab.Property;
@@ -77,6 +78,10 @@ public final class ValidationContext
7778
* The cross-reference checker, absent for single-file validation.
7879
*/
7980
public final Optional<XRefChecker> xrefChecker;
81+
/**
82+
* The src checker for media overlay text elements, absent for single-file validation
83+
*/
84+
public final Optional<OverlayTextChecker> overlayTextChecker;
8085
/**
8186
* The set of 'dc:type' values declared at the OPF level. Guaranteed non-null,
8287
* can be empty.
@@ -90,7 +95,7 @@ public final class ValidationContext
9095
private ValidationContext(String path, String mimeType, EPUBVersion version, EPUBProfile profile,
9196
Report report, Locale locale, FeatureReport featureReport,
9297
GenericResourceProvider resourceProvider, Optional<OPFItem> opfItem, Optional<OCFPackage> ocf,
93-
Optional<XRefChecker> xrefChecker, Set<String> pubTypes, Set<Property> properties)
98+
Optional<XRefChecker> xrefChecker, Optional<OverlayTextChecker> overlayTextChecker, Set<String> pubTypes, Set<Property> properties)
9499
{
95100
super();
96101
this.path = path;
@@ -104,6 +109,7 @@ private ValidationContext(String path, String mimeType, EPUBVersion version, EPU
104109
this.opfItem = opfItem;
105110
this.ocf = ocf;
106111
this.xrefChecker = xrefChecker;
112+
this.overlayTextChecker = overlayTextChecker;
107113
this.pubTypes = pubTypes;
108114
this.properties = properties;
109115
}
@@ -125,6 +131,7 @@ public static final class ValidationContextBuilder
125131
private GenericResourceProvider resourceProvider = null;
126132
private OCFPackage ocf = null;
127133
private XRefChecker xrefChecker = null;
134+
private OverlayTextChecker overlayTextChecker = null;
128135
private Set<String> pubTypes = null;
129136
private ImmutableSet.Builder<Property> properties = ImmutableSet.<Property> builder();
130137

@@ -148,6 +155,7 @@ public ValidationContextBuilder copy(ValidationContext context)
148155
resourceProvider = context.resourceProvider;
149156
ocf = context.ocf.orNull();
150157
xrefChecker = context.xrefChecker.orNull();
158+
overlayTextChecker = context.overlayTextChecker.orNull();
151159
pubTypes = context.pubTypes;
152160
properties = ImmutableSet.<Property> builder().addAll(context.properties);
153161
return this;
@@ -207,6 +215,12 @@ public ValidationContextBuilder xrefChecker(XRefChecker xrefChecker)
207215
return this;
208216
}
209217

218+
public ValidationContextBuilder overlayTextChecker(OverlayTextChecker overlayTextChecker)
219+
{
220+
this.overlayTextChecker = overlayTextChecker;
221+
return this;
222+
}
223+
210224
public ValidationContextBuilder pubTypes(Set<String> pubTypes)
211225
{
212226
this.pubTypes = pubTypes;
@@ -243,7 +257,7 @@ public ValidationContext build()
243257
profile != null ? profile : EPUBProfile.DEFAULT, report, locale,
244258
featureReport != null ? featureReport : new FeatureReport(), resourceProvider,
245259
(xrefChecker != null) ? xrefChecker.getResource(path) : Optional.<OPFItem> absent(),
246-
Optional.fromNullable(ocf), Optional.fromNullable(xrefChecker),
260+
Optional.fromNullable(ocf), Optional.fromNullable(xrefChecker), Optional.fromNullable(overlayTextChecker),
247261
pubTypes != null ? ImmutableSet.copyOf(pubTypes) : ImmutableSet.<String> of(),
248262
properties.build());
249263
}

src/main/java/com/adobe/epubcheck/overlay/OverlayHandler.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.adobe.epubcheck.overlay;
22

3+
import java.util.HashSet;
34
import java.util.Map;
45
import java.util.Set;
56

@@ -20,6 +21,7 @@
2021
import com.adobe.epubcheck.xml.XMLElement;
2122
import com.adobe.epubcheck.xml.XMLHandler;
2223
import com.adobe.epubcheck.xml.XMLParser;
24+
import com.google.common.base.Strings;
2325
import com.google.common.collect.ImmutableMap;
2426
import com.google.common.collect.ImmutableSet;
2527

@@ -40,6 +42,8 @@ public class OverlayHandler implements XMLHandler
4042

4143
private Map<String, Vocab> vocabs = RESERVED_VOCABS;
4244

45+
private Set<String> resourceRefs = new HashSet<String>();
46+
4347
public OverlayHandler(ValidationContext context, XMLParser parser)
4448
{
4549
this.context = context;
@@ -158,6 +162,14 @@ private void processRef(String ref, XRefChecker.Type type)
158162
report.message(MessageId.MED_005, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), ref, mimeType);
159163
}
160164
}
165+
else {
166+
String uniqueResource = PathUtil.removeFragment(ref);
167+
if (!Strings.isNullOrEmpty(uniqueResource)) {
168+
if (!context.overlayTextChecker.get().add(uniqueResource, context.opfItem.get().getId())) {
169+
report.message(MessageId.MED_011, EPUBLocation.create(path, parser.getLineNumber(), parser.getColumnNumber()), ref);
170+
}
171+
}
172+
}
161173
context.xrefChecker.get().registerReference(path, parser.getLineNumber(),
162174
parser.getColumnNumber(), ref, type);
163175
}
@@ -176,6 +188,12 @@ public void characters(char[] chars, int arg1, int arg2)
176188

177189
public void endElement()
178190
{
191+
XMLElement e = parser.getCurrentElement();
192+
String name = e.getName();
193+
if (name.equals("smil"))
194+
{
195+
checkItemReferences();
196+
}
179197
}
180198

181199
public void ignorableWhitespace(char[] chars, int arg1, int arg2)
@@ -185,4 +203,13 @@ public void ignorableWhitespace(char[] chars, int arg1, int arg2)
185203
public void processingInstruction(String arg0, String arg1)
186204
{
187205
}
206+
207+
private void checkItemReferences() {
208+
209+
if(this.resourceRefs.isEmpty()) {
210+
return;
211+
}
212+
213+
}
214+
188215
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.adobe.epubcheck.overlay;
2+
3+
import java.util.Map;
4+
import java.util.HashMap;
5+
6+
public class OverlayTextChecker {
7+
8+
private Map<String,String> refs;
9+
10+
public OverlayTextChecker() {
11+
refs = new HashMap<String,String>();
12+
}
13+
14+
public boolean add(String ref, String overlay) {
15+
if (!refs.containsKey(ref)) {
16+
refs.put(ref, overlay);
17+
return true;
18+
}
19+
else if (!refs.get(ref).equalsIgnoreCase(overlay)) {
20+
return false;
21+
}
22+
return true;
23+
}
24+
25+
public boolean isReferencedByOverlay(String path) {
26+
if (path == null || path.equals("")) {
27+
return false;
28+
}
29+
return refs.containsKey(path) ? true : false;
30+
}
31+
32+
public boolean isCorrectOverlay(String path, String overlay) {
33+
return overlay.equalsIgnoreCase(refs.get(path)) ? true : false;
34+
}
35+
}

src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ MED_006=Some browsers do not support rendering SVG images which use a filename i
133133
MED_007=Foreign resources can only be referenced from "source" elements with an explicit "type" attribute; found resource "%1$s" of foreign type "%2$s".
134134
MED_008=The time specified in the clipBegin attribute must not be after clipEnd.
135135
MED_009=The time specified in the clipBegin attribute must not be the same as clipEnd.
136+
MED_010=EPUB Content Documents referenced from a Media Overlay must specify the "media-overlay" attribute.
137+
MED_011=EPUB Content Document referenced from multiple Media Overlay Documents.
138+
MED_012=The "media-overlay" attribute does not match the ID of the Media Overlay that refers to this document.
139+
MED_013=Media Overlay Document referenced from the "media-overlay" attribute does not contain a reference to this Content Document.
136140

137141
#NAV EPUB v3 Table of contents
138142
NAV_001=The nav file is not supported for EPUB v2.

0 commit comments

Comments
 (0)