/* * Copyright 2013-2016 Skynav, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.skynav.ttx.transformer.isd; import java.io.Serializable; import java.util.List; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import org.w3c.dom.Element; import com.skynav.ttv.model.ttml.TTML1; import com.skynav.ttv.model.ttml1.tt.Body; import com.skynav.ttv.model.ttml1.tt.Break; import com.skynav.ttv.model.ttml1.tt.Division; import com.skynav.ttv.model.ttml1.tt.Head; import com.skynav.ttv.model.ttml1.tt.Layout; import com.skynav.ttv.model.ttml1.tt.ObjectFactory; import com.skynav.ttv.model.ttml1.tt.Paragraph; import com.skynav.ttv.model.ttml1.tt.Region; import com.skynav.ttv.model.ttml1.tt.Set; import com.skynav.ttv.model.ttml1.tt.Span; import com.skynav.ttv.model.ttml1.tt.TimedText; import com.skynav.ttv.model.ttml1.ttd.TimeContainer; import com.skynav.ttv.util.PreVisitor; import com.skynav.ttv.util.StyleSet; import com.skynav.ttv.util.StyleSpecification; import com.skynav.ttv.util.Visitor; import com.skynav.ttv.verifier.ttml.TTML1StyleVerifier; import com.skynav.ttx.transformer.TransformerContext; import com.skynav.xml.helpers.Documents; public class TTML1Helper extends TTMLHelper { public static final QName actorElementName = new QName(NAMESPACE_TT_METADATA, "actor"); public static final QName agentElementName = new QName(NAMESPACE_TT_METADATA, "agent"); public static final QName bodyElementName = new QName(NAMESPACE_TT, "body"); public static final QName breakElementName = new QName(NAMESPACE_TT, "br"); public static final QName copyrightElementName = new QName(NAMESPACE_TT_METADATA, "copyright"); public static final QName descriptionElementName = new QName(NAMESPACE_TT_METADATA, "desc"); public static final QName divisionElementName = new QName(NAMESPACE_TT, "div"); public static final QName extensionElementName = new QName(NAMESPACE_TT_PARAMETER, "extension"); public static final QName extensionsElementName = new QName(NAMESPACE_TT_PARAMETER, "extensions"); public static final QName featureElementName = new QName(NAMESPACE_TT_PARAMETER, "feature"); public static final QName featuresElementName = new QName(NAMESPACE_TT_PARAMETER, "features"); public static final QName headElementName = new QName(NAMESPACE_TT, "head"); public static final QName layoutElementName = new QName(NAMESPACE_TT, "layout"); public static final QName metadataElementName = new QName(NAMESPACE_TT, "metadata"); public static final QName nameElementName = new QName(NAMESPACE_TT_METADATA, "name"); public static final QName paragraphElementName = new QName(NAMESPACE_TT, "p"); public static final QName profileElementName = new QName(NAMESPACE_TT_PARAMETER, "profile"); public static final QName regionElementName = new QName(NAMESPACE_TT, "region"); public static final QName setElementName = new QName(NAMESPACE_TT, "set"); public static final QName spanElementName = new QName(NAMESPACE_TT, "span"); public static final QName styleElementName = new QName(NAMESPACE_TT, "style"); public static final QName stylingElementName = new QName(NAMESPACE_TT, "styling"); public static final QName timedTextElementName = new QName(NAMESPACE_TT, "tt"); public static final QName titleElementName = new QName(NAMESPACE_TT_METADATA, "title"); public static final QName nameAttributeName = new QName("", "name"); public static final int ttml1Version = TTML1.MODEL_VERSION; private static final ObjectFactory spanFactory = new ObjectFactory(); @Override public int getVersion() { return ttml1Version; } @Override public void traverse(Object tt, Visitor v) throws Exception { if (tt instanceof TimedText) traverse((TimedText) tt, v); else super.traverse(tt, v); } private static void traverse(TimedText tt, Visitor v) throws Exception { if (!v.preVisit(tt, null)) return; Head head = tt.getHead(); if (head != null) traverse(head, tt, v); Body body = tt.getBody(); if (body != null) traverse(body, tt, v); if (!v.postVisit(tt, null)) return; } private static void traverse(Head head, Object parent, Visitor v) throws Exception { if (!v.preVisit(head, parent)) return; Layout layout = head.getLayout(); if (layout != null) traverse(layout, head, v); if (!v.postVisit(head, parent)) return; } private static void traverse(Layout layout, Object parent, Visitor v) throws Exception { if (!v.preVisit(layout, parent)) return; for (Region r : layout.getRegion()) traverse(r, layout, v); if (!v.postVisit(layout, parent)) return; } private static void traverse(Region region, Object parent, Visitor v) throws Exception { if (!v.preVisit(region, parent)) return; if (!v.postVisit(region, parent)) return; } private static void traverse(Body body, Object parent, Visitor v) throws Exception { if (!v.preVisit(body, parent)) return; for (Set a : body.getAnimationClass()) traverse(a, body, v); for (Division d : body.getDiv()) traverse(d, body, v); if (!v.postVisit(body, parent)) return; } private static void traverse(Division division, Object parent, Visitor v) throws Exception { if (!v.preVisit(division, parent)) return; for (Set a : division.getAnimationClass()) traverse(a, division, v); for (Object b : division.getBlockClass()) traverseBlock(b, division, v); if (!v.postVisit(division, parent)) return; } private static void traverse(Paragraph paragraph, Object parent, Visitor v) throws Exception { if (!v.preVisit(paragraph, parent)) return; for (Serializable s : paragraph.getContent()) traverseContent(s, paragraph, v); if (!v.postVisit(paragraph, parent)) return; } private static void traverse(Span span, Object parent, Visitor v) throws Exception { if (!v.preVisit(span, parent)) return; for (Serializable s : span.getContent()) traverseContent(s, span, v); if(!v.postVisit(span, parent)) return; } private static void traverse(Break br, Object parent, Visitor v) throws Exception { if(!v.preVisit(br, parent)) return; for (Set a : br.getAnimationClass()) traverse(a, br, v); if (!v.postVisit(br, parent)) return; } private static void traverse(Set set, Object parent, Visitor v) throws Exception { if (!v.preVisit(set, parent)) return; if (!v.postVisit(set, parent)) return; } private static void traverse(String string, Object parent, Visitor v) throws Exception { if (!v.preVisit(string, parent)) return; if (!v.postVisit(string, parent)) return; } private static void traverseBlock(Object block, Object parent, Visitor v) throws Exception { if (block instanceof Division) traverse((Division) block, parent, v); else if (block instanceof Paragraph) traverse((Paragraph) block, parent, v); } private static void traverseContent(Serializable content, Object parent, Visitor v) throws Exception { if (content instanceof JAXBElement<?>) { Object element = ((JAXBElement<?>)content).getValue(); if (element instanceof Set) traverse((Set) element, parent, v); else if (element instanceof Span) traverse((Span) element, parent, v); else if (element instanceof Break) traverse((Break) element, parent, v); } else if (content instanceof String) { traverse((String) content, parent, v); } } @Override public void generateAnonymousSpans(Object tt, final TransformerContext context) { if (tt instanceof TimedText) { try { traverse(tt, new PreVisitor() { public boolean visit(Object content, Object parent, Visitor.Order order) { if (content instanceof String) { List<Serializable> contentChildren; if (parent instanceof Paragraph) contentChildren = ((Paragraph) parent).getContent(); else if (parent instanceof Span) contentChildren = ((Span) parent).getContent(); else contentChildren = null; if (contentChildren != null) { if (!(parent instanceof Span) || (contentChildren.size() > 1)) contentChildren.set(contentChildren.indexOf(content), wrapInAnonymousSpan(content, context)); } } return true; } }); } catch (Exception e) { throw new RuntimeException(e); } } else super.generateAnonymousSpans(tt, context); } private JAXBElement<Span> wrapInAnonymousSpan(Object content, TransformerContext context) { assert content instanceof String; Span span = spanFactory.createSpan(); span.setId(generateAnonymousSpanId(context)); span.getContent().add((Serializable) content); return spanFactory.createSpan(span); } @Override @SuppressWarnings({"rawtypes","unchecked"}) public List getChildren(Object content) { List children = null; if (content instanceof TimedText) { children = new java.util.ArrayList<Object>(); Head head = ((TimedText) content).getHead(); if (head != null) children.add(head); Body body = ((TimedText) content).getBody(); if (body != null) children.add(body); } else if (content instanceof Head) { children = new java.util.ArrayList<Object>(); Layout layout = ((Head) content).getLayout(); if (layout != null) children.add(layout); } else if (content instanceof Layout) { children = ((Layout) content).getRegion(); } else if (content instanceof Body) { children = ((Body) content).getDiv(); } else if (content instanceof Division) { children = ((Division) content).getBlockClass(); } else if (content instanceof Paragraph) { children = dereferenceAsContent(((Paragraph) content).getContent()); } else if (content instanceof Span) { children = dereferenceAsContent(((Span) content).getContent()); } else { children = super.getChildren(content); } return children; } private List<Object> dereferenceAsContent(List<Serializable> content) { List<Object> dereferencedContent = new java.util.ArrayList<Object>(content.size()); for (Serializable s: content) { if (s instanceof JAXBElement<?>) { Object element = ((JAXBElement<?>)s).getValue(); if (element instanceof Span) dereferencedContent.add(element); else if (element instanceof Break) dereferencedContent.add(element); } } return dereferencedContent; } @Override public boolean isTimedText(Object content) { if (content instanceof TimedText) return true; else return super.isTimedText(content); } @Override public boolean isAnonymousSpan(Object content) { if (content instanceof Span) { String value = getStringValuedAttribute(content, "id"); return (value != null) && (value.indexOf("ttxSpan") == 0); } else return super.isAnonymousSpan(content); } @Override public boolean isTimed(Object content) { if (content instanceof TimedText) return true; else if (content instanceof Head) return true; else if (content instanceof Layout) return true; else if (content instanceof Region) return true; else if (content instanceof Body) return true; else if (content instanceof Division) return true; else if (content instanceof Paragraph) return true; else if (content instanceof Span) return true; else if (content instanceof Break) return true; else if (content instanceof Set) return true; else return super.isTimed(content); } @Override public boolean isTimedContainer(Object content) { if (content instanceof TimedText) return true; else if (content instanceof Head) return true; else if (content instanceof Layout) return true; else if (content instanceof Body) return true; else if (content instanceof Division) return true; else if (content instanceof Paragraph) return true; else if (content instanceof Span) return true; else return super.isTimedContainer(content); } @Override public boolean isSequenceContainer(Object content) { TimeContainer container = getTimeContainer(content); if (container != null) return container.value().equals("seq"); else return super.isSequenceContainer(content); } private TimeContainer getTimeContainer(Object content) { if (isTimedContainer(content)) { TimeContainer container = null; if (content instanceof TimedText) container = TimeContainer.PAR; else if (content instanceof Head) container = TimeContainer.PAR; else if (content instanceof Layout) container = TimeContainer.PAR; else if (content instanceof Body) container = ((Body) content).getTimeContainer(); else if (content instanceof Division) container = ((Division) content).getTimeContainer(); else if (content instanceof Paragraph) container = ((Paragraph) content).getTimeContainer(); else if (content instanceof Span) container = ((Span) content).getTimeContainer(); return container; } else return null; } @Override public String getClassString(Object content) { String cls = content.getClass().toString(); cls = cls.substring(cls.lastIndexOf('.') + 1); if (isAnonymousSpan(content)) { List<Serializable> spanContent = ((Span) content).getContent(); if (spanContent.size() == 1) { Serializable spanContentFirst = spanContent.get(0); if (spanContentFirst instanceof String) { String spanText = (String) spanContentFirst; cls = "AnonSpan(" + escapeControls(spanText) + ")"; } } } else cls = super.getClassString(content); return cls; } public static boolean hasExplicitExtent(Element root) { QName n = TTML1StyleVerifier.extentAttributeName; return Documents.hasAttribute(root, n); } public static String getExplicitExtent(Element root) { QName n = TTML1StyleVerifier.extentAttributeName; return Documents.getAttribute(root, n); } public static boolean hasShowBackgroundAlways(Element region, StyleSet ss) { QName n = TTML1StyleVerifier.showBackgroundAttributeName; String v = null; if (ss != null) { StyleSpecification s = ss.get(n); if (s != null) v = s.getValue(); } if (v == null) v = Documents.getAttribute(region, n); return (v != null) ? v.equals("always") : true; } }