diff --git a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java index 500313833..309c1f5eb 100644 --- a/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java +++ b/src/main/java/com/adobe/epubcheck/messages/DefaultSeverities.java @@ -137,6 +137,8 @@ private void initialize() severities.put(MessageId.HTM_053, Severity.INFO); severities.put(MessageId.HTM_054, Severity.ERROR); severities.put(MessageId.HTM_055, Severity.WARNING); + severities.put(MessageId.HTM_056, Severity.ERROR); + severities.put(MessageId.HTM_057, Severity.ERROR); // Media severities.put(MessageId.MED_001, Severity.ERROR); diff --git a/src/main/java/com/adobe/epubcheck/messages/MessageId.java b/src/main/java/com/adobe/epubcheck/messages/MessageId.java index 8ccbcb1e2..6219080ca 100644 --- a/src/main/java/com/adobe/epubcheck/messages/MessageId.java +++ b/src/main/java/com/adobe/epubcheck/messages/MessageId.java @@ -131,6 +131,8 @@ public enum MessageId implements Comparable HTM_053("HTM_053"), HTM_054("HTM_054"), HTM_055("HTM_055"), + HTM_056("HTM_056"), + HTM_057("HTM_057"), // Messages associated with media (images, audio and video) MED_001("MED-001"), diff --git a/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java b/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java index 2e2968da7..0def5866f 100644 --- a/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java +++ b/src/main/java/com/adobe/epubcheck/ops/OPSHandler30.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -11,6 +12,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.w3c.epubcheck.util.microsyntax.ViewportMeta; +import org.w3c.epubcheck.util.microsyntax.ViewportMeta.ParseError; + import com.adobe.epubcheck.api.EPUBLocation; import com.adobe.epubcheck.api.EPUBProfile; import com.adobe.epubcheck.messages.MessageId; @@ -701,19 +705,55 @@ protected void processMeta() if (EpubConstants.HtmlNamespaceUri.equals(e.getNamespace())) { String name = e.getAttribute("name"); - if ("viewport".equals(name)) + if ("viewport".equals(Strings.nullToEmpty(name).trim())) { + // Mark the viewport as seen + // (used when checking the existence of viewport metadata) hasViewport = true; - // For a fixed-layout document: - // check that the vieport declares both height and width + // For a fixed-layout documents: if (context.opfItem.isPresent() && context.opfItem.get().isFixedLayout()) { String contentAttribute = e.getAttribute("content"); - if (contentAttribute == null || !contentAttribute.contains("width=") - || !contentAttribute.contains("height=")) + + // parse viewport metadata + List syntaxErrors = new LinkedList<>(); + ViewportMeta viewport = ViewportMeta.parse(contentAttribute, + new ViewportMeta.ErrorHandler() + { + @Override + public void error(ParseError error, int position) + { + syntaxErrors.add(error); + } + }); + if (!syntaxErrors.isEmpty()) + { + // report any syntax error + report.message(MessageId.HTM_047, location(), contentAttribute); + } + else { - report.message(MessageId.HTM_047, location()); + // check that viewport metadata has a valid width value + if (!viewport.hasProperty("width")) + { + report.message(MessageId.HTM_056, location(), "width"); + } + else if (!ViewportMeta.isValidWidth(viewport.getValue("width"))) + { + report.message(MessageId.HTM_057, location(), "width"); + } + + // check that viewport metadata has a valid height value + if (!viewport.hasProperty("height")) + { + report.message(MessageId.HTM_056, location(), "height"); + } + else if (!ViewportMeta.isValidHeight(viewport.getValue("height"))) + { + report.message(MessageId.HTM_057, location(), "height"); + } } + } } } diff --git a/src/main/java/com/adobe/epubcheck/util/SourceSet.java b/src/main/java/com/adobe/epubcheck/util/SourceSet.java index cbf331fcb..f8e6ad058 100644 --- a/src/main/java/com/adobe/epubcheck/util/SourceSet.java +++ b/src/main/java/com/adobe/epubcheck/util/SourceSet.java @@ -1,10 +1,14 @@ package com.adobe.epubcheck.util; +import static org.w3c.epubcheck.util.infra.InfraUtil.isASCIIWhitespace; + import java.nio.CharBuffer; import java.util.LinkedList; import java.util.List; import java.util.regex.Pattern; +import org.w3c.epubcheck.util.infra.InfraUtil; + import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Preconditions; @@ -162,7 +166,7 @@ public SourceSet parse(CharSequence srcset) { case SPLIT: assert (url.length() == 0); - if (isASCIIWhitespace(c)) + if (InfraUtil.isASCIIWhitespace(c)) { // skip whitespace } @@ -271,15 +275,6 @@ else if (c == '(') return builder.build(); } - /** - * if a character is https://infra.spec.whatwg.org/#ascii-whitespace U+0009 TAB, - * U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE. - */ - private static boolean isASCIIWhitespace(char c) - { - return c == ' ' || c == '\t' || c == '\f' || c == '\n' || c == '\r'; - } - /** * Remove trailing commas and return the count of commas removed */ diff --git a/src/main/java/org/w3c/epubcheck/util/infra/InfraUtil.java b/src/main/java/org/w3c/epubcheck/util/infra/InfraUtil.java new file mode 100644 index 000000000..bf3c9fa7f --- /dev/null +++ b/src/main/java/org/w3c/epubcheck/util/infra/InfraUtil.java @@ -0,0 +1,19 @@ +package org.w3c.epubcheck.util.infra; + +public final class InfraUtil +{ + + private InfraUtil() + { + // static utility class + } + + /** + * if a character is https://infra.spec.whatwg.org/#ascii-whitespace U+0009 + * TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE. + */ + public static boolean isASCIIWhitespace(char c) + { + return c == ' ' || c == '\t' || c == '\f' || c == '\n' || c == '\r'; + } +} diff --git a/src/main/java/org/w3c/epubcheck/util/microsyntax/ViewportMeta.java b/src/main/java/org/w3c/epubcheck/util/microsyntax/ViewportMeta.java new file mode 100644 index 000000000..3120cd460 --- /dev/null +++ b/src/main/java/org/w3c/epubcheck/util/microsyntax/ViewportMeta.java @@ -0,0 +1,251 @@ +package org.w3c.epubcheck.util.microsyntax; + +import static org.w3c.epubcheck.util.infra.InfraUtil.isASCIIWhitespace; + +import java.nio.CharBuffer; +import java.util.Map; +import java.util.regex.Pattern; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; + +public class ViewportMeta +{ + private static Pattern VIEWPORT_HEIGHT_REGEX = Pattern.compile("\\d+|device-height"); + private static Pattern VIEWPORT_WIDTH_REGEX = Pattern.compile("\\d+|device-width"); + + public static ViewportMeta parse(String string, ErrorHandler errorHandler) + { + return new Parser(errorHandler).parse(string); + } + + public static boolean isValidHeight(String height) + { + Preconditions.checkArgument(height != null); + return VIEWPORT_HEIGHT_REGEX.matcher(height).matches(); + } + + public static boolean isValidWidth(String width) + { + Preconditions.checkArgument(width != null); + return VIEWPORT_WIDTH_REGEX.matcher(width).matches(); + } + + public static enum ParseError + { + NULL_OR_EMPTY, + NAME_EMPTY, + VALUE_EMPTY, + LEADING_SEPARATOR, + TRAILING_SEPARATOR, + ASSIGN_UNEXPECTED + } + + /** + * An error handler for the `srcset` parser + */ + public interface ErrorHandler + { + public void error(ParseError error, int position); + } + + private final static class Builder + { + public ImmutableMap.Builder properties = ImmutableMap.builder(); + + public ViewportMeta build() + { + return new ViewportMeta(this); + } + + public void withProperty(String name, String value) + { + Preconditions.checkArgument(name != null); + Preconditions.checkArgument(value != null); + properties.put(name, value); + } + + } + + private final static class Parser + { + private static enum State + { + NAME, + ASSIGN, + VALUE, + SEPARATOR, + SPACE_OR_SEPARATOR + } + + private final ErrorHandler errorHandler; + + public Parser(ErrorHandler errorHandler) + { + this.errorHandler = errorHandler; + } + + private void error(ParseError code, int position) + { + if (errorHandler != null) errorHandler.error(code, position); + } + + public ViewportMeta parse(CharSequence string) + { + Builder builder = new Builder(); + if (string == null || string.length() == 0) + { + error(ParseError.NULL_OR_EMPTY, -1); + return builder.build(); + } + CharBuffer input = CharBuffer.wrap(string); + StringBuilder name = new StringBuilder(); + StringBuilder value = new StringBuilder(); + State state = State.NAME; + boolean consume = true; + char c = ' '; + while (!consume || input.hasRemaining()) + { + if (consume) + { + c = input.get(); + } + else + { + consume = true; + } + switch (state) + { + case NAME: + if (isASCIIWhitespace(c) && name.length() == 0) + { + // skip leading whitespace + } + else if (c == '=' || isASCIIWhitespace(c)) + { + if (name.length() == 0) + { + error(ParseError.NAME_EMPTY, input.position()); + return builder.build(); + } + state = State.ASSIGN; + consume = false; + } + else if (c == ',' || c == ';') + { + if (name.length() == 0) + { + error(ParseError.LEADING_SEPARATOR, input.position()); + } + else + { + error(ParseError.VALUE_EMPTY, input.position()); + } + return builder.build(); + } + else + { + name.append(c); + } + break; + case ASSIGN: + if (isASCIIWhitespace(c)) + { + // skip whitespace + } + else if (c == '=') + { + state = State.VALUE; + } + else + { + // no '=' was matched (i.e. no value is set) + error(ParseError.VALUE_EMPTY, input.position()); + return builder.build(); + } + break; + case VALUE: + if (isASCIIWhitespace(c) && value.length() == 0) + { + // skip whitespace, the value hasn't started + } + else if (c == ',' || c == ';' || isASCIIWhitespace(c)) + { + if (value.length() == 0) + { + error(ParseError.VALUE_EMPTY, input.position()); + return builder.build(); + } + state = State.SPACE_OR_SEPARATOR; + consume = false; + } + else if (c == '=') + { + error(ParseError.ASSIGN_UNEXPECTED, input.position()); + return builder.build(); + } + else + { + value.append(c); + } + break; + case SPACE_OR_SEPARATOR: + if (isASCIIWhitespace(c)) + { + // skip whitespace + } + else + { + state = State.SEPARATOR; + consume = false; + } + case SEPARATOR: + if (c == ',' || c == ';' || isASCIIWhitespace(c)) + { + // skip repeating separators + } + else + { + builder.withProperty(name.toString(), value.toString()); + name = new StringBuilder(); + value = new StringBuilder(); + state = State.NAME; + consume = false; + } + break; + } + } + if (value.length() != 0) + { + builder.withProperty(name.toString(), value.toString()); + } + else if (name.length() != 0) + { + error(ParseError.VALUE_EMPTY, input.position()); + } + if (state == State.SEPARATOR) + { + error(ParseError.TRAILING_SEPARATOR, input.position()); + } + return builder.build(); + } + } + + private final Map properties; + + private ViewportMeta(Builder builder) + { + this.properties = builder.properties.build(); + } + + public boolean hasProperty(String name) + { + return properties.containsKey(name); + } + + public String getValue(String name) + { + return properties.get(name); + } + +} diff --git a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties index d6a7fb9e6..7f07a57dd 100644 --- a/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties +++ b/src/main/resources/com/adobe/epubcheck/messages/MessageBundle.properties @@ -111,10 +111,8 @@ HTM_044=Namespace uri "%1$s" was included but not used. HTM_044_SUG=Remove unused Namespace URIs. HTM_045=Encountered empty href. HTM_045_SUG=Empty hrefs are valid self-references. These should be validated to ensure that this is the desired intent. -HTM_046=Fixed format item has no viewport defined. -HTM_046_SUG=A viewport declaration is required for fixed format items. -HTM_047=Html viewport is missing height and/or width. -HTM_047_SUG=The viewport declaration must declare both width and height. +HTM_046=Fixed layout document has no "viewport" meta element. +HTM_047=Viewport metadata "%1$s" has a syntax error HTM_048=SVG Fixed-Layout Documents must have a "viewBox" attribute (on the outermost "svg" element). HTM_049=Html element does not have an xmlns set to "http://www.w3.org/1999/xhtml". HTM_049_SUG=Add xmlns="http://www.w3.org/1999/xhtml" to the html element. @@ -124,6 +122,8 @@ HTM_052=The property "region-based" is only allowed on nav elements in Data Navi HTM_053=Found an external file link (file://) in file: "%1$s". HTM_054=Custom attribute namespace ("%1$s") must not include the string "%2$s" in its domain. HTM_055=The "%1$s" element should not be used (discouraged construct) +HTM_056=Viewport metadata has no "%1$s" dimension (both "width" and "height" properties are required) +HTM_057=Viewport "%1$s" value must be a positive number or the keyword "device-%1$s" #media MED_001=Video poster must have core media image type. diff --git a/src/test/java/org/w3c/epubcheck/util/microsyntax/ViewportSteps.java b/src/test/java/org/w3c/epubcheck/util/microsyntax/ViewportSteps.java new file mode 100644 index 000000000..625473bfb --- /dev/null +++ b/src/test/java/org/w3c/epubcheck/util/microsyntax/ViewportSteps.java @@ -0,0 +1,75 @@ +package org.w3c.epubcheck.util.microsyntax; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.epubcheck.util.microsyntax.ViewportMeta.ErrorHandler; +import org.w3c.epubcheck.util.microsyntax.ViewportMeta.ParseError; + +import com.google.common.collect.ImmutableList; + +import io.cucumber.java.ParameterType; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; + +public class ViewportSteps +{ + + public static final class TestErrorHandler implements ErrorHandler + { + public final List errors = new LinkedList<>(); + + @Override + public void error(ParseError error, int position) + { + errors.add(error); + } + + public List errors() + { + return ImmutableList.copyOf(errors); + } + }; + + private final TestErrorHandler handler; + + public ViewportSteps(TestErrorHandler handler) + { + this.handler = handler; + } + + @ParameterType(".*") + public ParseError error(String error) + { + try + { + return ParseError.valueOf(error); + } catch (Exception e) + { + throw new IllegalArgumentException("unknown error code '" + error + "'"); + } + } + + @When("parsing viewport {string}") + public void parseViewport(String content) + { + ViewportMeta.parse(content, handler); + } + + @Then("no error is returned") + public void assertValid() + { + assertThat("Unexpected errors", handler.errors(), is(empty())); + } + + @Then("error {error} is returned") + public void assertError(ParseError error) + { + assertThat(handler.errors(), contains(error)); + } +} diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/content_001.xhtml new file mode 100644 index 000000000..29f2242a7 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + Minimal EPUB + + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/nav.xhtml similarity index 100% rename from src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/nav.xhtml rename to src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/nav.xhtml diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/package.opf new file mode 100644 index 000000000..013c82b7d --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/EPUB/package.opf @@ -0,0 +1,16 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/META-INF/container.xml similarity index 100% rename from src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/META-INF/container.xml rename to src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/META-INF/container.xml diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/mimetype similarity index 100% rename from src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/mimetype rename to src/test/resources/epub3/08-layout/files/content-fxl-item-xhtml-viewport-invalid-error/mimetype diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/content_001.xhtml new file mode 100644 index 000000000..a820d396e --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/package.opf similarity index 100% rename from src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/package.opf rename to src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/EPUB/package.opf diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-empty-error/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/content_001.xhtml similarity index 82% rename from src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/content_001.xhtml rename to src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/content_001.xhtml index 855ec7a39..240cdaee4 100644 --- a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-invalid-error/EPUB/content_001.xhtml +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/content_001.xhtml @@ -2,7 +2,7 @@ - + Minimal EPUB diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-height-missing-error/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/content_001.xhtml new file mode 100644 index 000000000..9b4fc899c --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-keywords-valid/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/content_001.xhtml new file mode 100644 index 000000000..cc9ac31b9 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/content_001.xhtml @@ -0,0 +1,13 @@ + + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-multiple-valid/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/content_001.xhtml new file mode 100644 index 000000000..ff331a5db --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-syntax-invalid-error/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/content_001.xhtml new file mode 100644 index 000000000..b41b24578 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-units-invalid-error/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/content_001.xhtml new file mode 100644 index 000000000..1713b79db --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/content_001.xhtml @@ -0,0 +1,12 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-valid/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/content_001.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/content_001.xhtml new file mode 100644 index 000000000..45c4aface --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/content_001.xhtml @@ -0,0 +1,13 @@ + + + + + + Minimal EPUB + + +

Loomings

+

Call me Ishmael.

+ + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/nav.xhtml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/nav.xhtml new file mode 100644 index 000000000..240745e63 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/nav.xhtml @@ -0,0 +1,14 @@ + + + + + Minimal Nav + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/package.opf b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/package.opf new file mode 100644 index 000000000..d16a30d60 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/EPUB/package.opf @@ -0,0 +1,17 @@ + + + + Minimal EPUB 3.0 + en + NOID + 2017-06-14T00:00:01Z + pre-paginated + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/META-INF/container.xml b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/META-INF/container.xml new file mode 100644 index 000000000..318782179 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/META-INF/container.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/mimetype b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/mimetype new file mode 100644 index 000000000..57ef03f24 --- /dev/null +++ b/src/test/resources/epub3/08-layout/files/content-fxl-xhtml-viewport-whitespace-valid/mimetype @@ -0,0 +1 @@ +application/epub+zip \ No newline at end of file diff --git a/src/test/resources/epub3/08-layout/layout.feature b/src/test/resources/epub3/08-layout/layout.feature index b1e564a1f..0beedd609 100644 --- a/src/test/resources/epub3/08-layout/layout.feature +++ b/src/test/resources/epub3/08-layout/layout.feature @@ -207,6 +207,26 @@ Feature: EPUB 3 — Layout Rendering Control #### 8.2.2.6 Content document dimensions + @spec @xref:sec-fxl-content-dimensions + Scenario: Verify a fixed-layout XHTML document with a valid viewport + When checking EPUB 'content-fxl-xhtml-viewport-valid' + Then no errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Verify a fixed-layout XHTML document with a valid viewport with whitespace + When checking EPUB 'content-fxl-xhtml-viewport-whitespace-valid' + Then no errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Verify a fixed-layout XHTML document with a valid viewport using keywords value + When checking EPUB 'content-fxl-xhtml-viewport-keywords-valid' + Then no errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Verify a fixed-layout XHTML document with multiple viewport meta tags + When checking EPUB 'content-fxl-xhtml-viewport-multiple-valid' + Then no errors or warnings are reported + @spec @xref:sec-fxl-content-dimensions Scenario: Report a fixed-layout XHTML document with no viewport When checking EPUB 'content-fxl-xhtml-viewport-missing-error' @@ -214,8 +234,32 @@ Feature: EPUB 3 — Layout Rendering Control And no other errors or warnings are reported @spec @xref:sec-fxl-content-dimensions - Scenario: Report a fixed-layout XHTML document with an invalid viewport - When checking EPUB 'content-fxl-xhtml-viewport-invalid-error' + Scenario: Report a fixed-layout XHTML document with a syntactically invalid viewport + When checking EPUB 'content-fxl-xhtml-viewport-syntax-invalid-error' + Then error HTM-047 is reported + And no other errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Report a fixed-layout XHTML document with a viewport using units + When checking EPUB 'content-fxl-xhtml-viewport-units-invalid-error' + Then error HTM-057 is reported 2 times + And no other errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Report a fixed-layout XHTML document with a viewport with no height + When checking EPUB 'content-fxl-xhtml-viewport-height-missing-error' + Then error HTM-056 is reported + And no other errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Report a fixed-layout XHTML document with a viewport missing the height value + When checking EPUB 'content-fxl-xhtml-viewport-height-empty-error' + Then error HTM-047 is reported + And no other errors or warnings are reported + + @spec @xref:sec-fxl-content-dimensions + Scenario: Report a single fixed-layout XHTML document with an invalid viewport in a reflowable publication + When checking EPUB 'content-fxl-item-xhtml-viewport-invalid-error' Then error HTM-047 is reported And no other errors or warnings are reported diff --git a/src/test/resources/epub3/F-viewport-meta-tag/viewport-syntax.feature b/src/test/resources/epub3/F-viewport-meta-tag/viewport-syntax.feature new file mode 100644 index 000000000..1eb7c7c65 --- /dev/null +++ b/src/test/resources/epub3/F-viewport-meta-tag/viewport-syntax.feature @@ -0,0 +1,49 @@ +Feature: Viewport meta tag syntax + + Tests the parser for the viewport meta tag syntax as defined + in EPUB 3.3: + https://www.w3.org/TR/epub-33/#app-viewport-meta-syntax + + Scenario Outline: parsing valid viewport values + When parsing viewport + Then no error is returned + + Scenarios: + | viewport | + | "width=1200, height=600" | + | "p1=value" | + | " p1 = value " | + | " p1 = value " | + | "p1 = value" | + | "p1=value,p2=value" | + | "p1=value;p2=value" | + | "p1=value,,,p2=value" | + | "p1=value;;;p2=value" | + | "p1=value p2=value" | + | "p1=value, ;p2=value" | + | "p1=value,p2=value,p3=value" | + + Scenario Outline: parsing invalid viewport values + When parsing viewport + Then error is returned + + Scenarios: + | viewport | error | + | "" | NULL_OR_EMPTY | + | "p1==value" | ASSIGN_UNEXPECTED | + | "p1=value=value" | ASSIGN_UNEXPECTED | + | "p1" | VALUE_EMPTY | + | "p1 value" | VALUE_EMPTY | + | "p1=value value" | VALUE_EMPTY | + | "p1,p2=value" | VALUE_EMPTY | + | "p1=value,p2" | VALUE_EMPTY | + | "p1=" | VALUE_EMPTY | + | "p1= " | VALUE_EMPTY | + | "p1=value,p2=" | VALUE_EMPTY | + | "=value" | NAME_EMPTY | + | "p1=value,=value" | NAME_EMPTY | + | "p1=value, =value" | NAME_EMPTY | + | ",p1=value" | LEADING_SEPARATOR | + | ";p1=value" | LEADING_SEPARATOR | + | "p1=value," | TRAILING_SEPARATOR | + | "p1=value;" | TRAILING_SEPARATOR |