http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/XMLOutputFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/XMLOutputFormat.java 
b/src/main/java/org/apache/freemarker/core/XMLOutputFormat.java
deleted file mode 100644
index 898b569..0000000
--- a/src/main/java/org/apache/freemarker/core/XMLOutputFormat.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- */
-package org.apache.freemarker.core;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.apache.freemarker.core.util._StringUtil;
-
-/**
- * Represents the XML output format (MIME type "application/xml", name "XML"). 
This format escapes by default (via
- * {@link _StringUtil#XMLEnc(String)}). The {@code ?html}, {@code ?xhtml} and 
{@code ?xml} built-ins silently bypass
- * template output values of the type produced by this output format ({@link 
TemplateXHTMLOutputModel}).
- * 
- * @since 2.3.24
- */
-public final class XMLOutputFormat extends 
CommonMarkupOutputFormat<TemplateXMLOutputModel> {
-
-    /**
-     * The only instance (singleton) of this {@link OutputFormat}.
-     */
-    public static final XMLOutputFormat INSTANCE = new XMLOutputFormat();
-
-    private XMLOutputFormat() {
-        // Only to decrease visibility
-    }
-
-    @Override
-    public String getName() {
-        return "XML";
-    }
-
-    @Override
-    public String getMimeType() {
-        return "application/xml";
-    }
-
-    @Override
-    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
-        _StringUtil.XMLEnc(textToEsc, out);
-    }
-
-    @Override
-    public String escapePlainText(String plainTextContent) {
-        return _StringUtil.XMLEnc(plainTextContent);
-    }
-
-    @Override
-    public boolean isLegacyBuiltInBypassed(String builtInName) {
-        return builtInName.equals("xml");
-    }
-
-    @Override
-    protected TemplateXMLOutputModel newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent) {
-        return new TemplateXMLOutputModel(plainTextContent, markupContent);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java 
b/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
index c74bfbc..9c18db0 100644
--- 
a/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
+++ 
b/src/main/java/org/apache/freemarker/core/_ObjectBuilderSettingEvaluator.java
@@ -42,6 +42,11 @@ import 
org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.impl.DefaultObjectWrapper;
 import org.apache.freemarker.core.model.impl.SimpleObjectWrapper;
 import org.apache.freemarker.core.model.impl.beans.BeansWrapper;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.PlainTextOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
 import org.apache.freemarker.core.templateresolver.AndMatcher;
 import 
org.apache.freemarker.core.templateresolver.ConditionalTemplateConfigurationFactory;
 import org.apache.freemarker.core.templateresolver.FileExtensionMatcher;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java
 
b/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java
index 7935cdb..1360d43 100644
--- 
a/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java
+++ 
b/src/main/java/org/apache/freemarker/core/_ParserConfigurationWithInheritedFormat.java
@@ -18,6 +18,8 @@
  */
 package org.apache.freemarker.core;
 
+import org.apache.freemarker.core.outputformat.OutputFormat;
+
 /**
  * For internal use only; don't depend on this, there's no backward 
compatibility guarantee at all!
  */ 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/_TemplateAPI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/_TemplateAPI.java 
b/src/main/java/org/apache/freemarker/core/_TemplateAPI.java
index 05906da..c8b712c 100644
--- a/src/main/java/org/apache/freemarker/core/_TemplateAPI.java
+++ b/src/main/java/org/apache/freemarker/core/_TemplateAPI.java
@@ -21,6 +21,7 @@ package org.apache.freemarker.core;
 
 import java.util.Set;
 
+import org.apache.freemarker.core.outputformat.OutputFormat;
 import org.apache.freemarker.core.templateresolver.CacheStorage;
 import org.apache.freemarker.core.util._NullArgumentException;
 

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/model/TemplateMarkupOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/model/TemplateMarkupOutputModel.java 
b/src/main/java/org/apache/freemarker/core/model/TemplateMarkupOutputModel.java
new file mode 100644
index 0000000..cb3fbf9
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/model/TemplateMarkupOutputModel.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.model;
+
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+
+/**
+ * "markup output" template language data-type; stores markup (some kind of 
"rich text" / structured format, as opposed
+ * to plain text) that meant to be printed as template output. This type is 
related to the {@link OutputFormat}
+ * mechanism. Values of this kind are exempt from {@link OutputFormat}-based 
automatic escaping.
+ * 
+ * <p>
+ * Each implementation of this type has a {@link OutputFormat} subclass pair, 
whose singleton instance is returned by
+ * {@link #getOutputFormat()}. See more about how markup output values work at 
{@link OutputFormat}.
+ * 
+ * <p>
+ * Note that {@link TemplateMarkupOutputModel}-s are by design not treated 
like {@link TemplateScalarModel}-s, and so
+ * the implementations of this interface usually shouldn't implement {@link 
TemplateScalarModel}. (Because, operations
+ * applicable on plain strings, like converting to upper case, substringing, 
etc., can corrupt markup.) If the template
+ * author wants to pass in the "source" of the markup as string somewhere, he 
should use {@code ?markup_string}.
+ * 
+ * @param <MO>
+ *            Refers to the interface's own type, which is useful in 
interfaces that extend
+ *            {@link TemplateMarkupOutputModel} (Java Generics trick).
+ * 
+ * @since 2.3.24
+ */
+public interface TemplateMarkupOutputModel<MO extends 
TemplateMarkupOutputModel<MO>> extends TemplateModel {
+
+    /**
+     * Returns the singleton {@link OutputFormat} object that implements the 
operations for the "markup output" value.
+     */
+    MarkupOutputFormat<MO> getOutputFormat();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/model/impl/beans/OverloadedMethods.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/model/impl/beans/OverloadedMethods.java
 
b/src/main/java/org/apache/freemarker/core/model/impl/beans/OverloadedMethods.java
index e53e563..f53596b 100644
--- 
a/src/main/java/org/apache/freemarker/core/model/impl/beans/OverloadedMethods.java
+++ 
b/src/main/java/org/apache/freemarker/core/model/impl/beans/OverloadedMethods.java
@@ -25,10 +25,10 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.freemarker.core.TemplateMarkupOutputModel;
 import org.apache.freemarker.core._DelayedConversionToString;
 import org.apache.freemarker.core._ErrorDescriptionBuilder;
 import org.apache.freemarker.core._TemplateModelException;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.util.FTLUtil;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/model/impl/beans/SimpleMethod.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/model/impl/beans/SimpleMethod.java 
b/src/main/java/org/apache/freemarker/core/model/impl/beans/SimpleMethod.java
index df16ae1..f863486 100644
--- 
a/src/main/java/org/apache/freemarker/core/model/impl/beans/SimpleMethod.java
+++ 
b/src/main/java/org/apache/freemarker/core/model/impl/beans/SimpleMethod.java
@@ -24,12 +24,12 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.freemarker.core.TemplateMarkupOutputModel;
 import org.apache.freemarker.core._DelayedFTLTypeDescription;
 import org.apache.freemarker.core._DelayedOrdinal;
 import org.apache.freemarker.core._ErrorDescriptionBuilder;
 import org.apache.freemarker.core._TemplateModelException;
 import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
 import org.apache.freemarker.core.model.TemplateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.util._ClassUtil;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/CommonMarkupOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/CommonMarkupOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/CommonMarkupOutputFormat.java
new file mode 100644
index 0000000..df1b872
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/CommonMarkupOutputFormat.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+
+/**
+ * Common superclass for implementing {@link MarkupOutputFormat}-s that use a 
{@link CommonTemplateMarkupOutputModel}
+ * subclass.
+ * 
+ * @since 2.3.24
+ */
+public abstract class CommonMarkupOutputFormat<MO extends 
CommonTemplateMarkupOutputModel>
+        extends MarkupOutputFormat<MO> {
+
+    protected CommonMarkupOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public final MO fromPlainTextByEscaping(String textToEsc) throws 
TemplateModelException {
+        return newTemplateMarkupOutputModel(textToEsc, null);
+    }
+
+    @Override
+    public final MO fromMarkup(String markupText) throws 
TemplateModelException {
+        return newTemplateMarkupOutputModel(null, markupText);
+    }
+
+    @Override
+    public final void output(MO mo, Writer out) throws IOException, 
TemplateModelException {
+        String mc = mo.getMarkupContent();
+        if (mc != null) {
+            out.write(mc);
+        } else {
+            output(mo.getPlainTextContent(), out);
+        }
+    }
+
+    @Override
+    public abstract void output(String textToEsc, Writer out) throws 
IOException, TemplateModelException;
+    
+    @Override
+    public final String getSourcePlainText(MO mo) throws 
TemplateModelException {
+        return mo.getPlainTextContent();
+    }
+
+    @Override
+    public final String getMarkupString(MO mo) throws TemplateModelException {
+        String mc = mo.getMarkupContent();
+        if (mc != null) {
+            return mc;
+        }
+        
+        mc = escapePlainText(mo.getPlainTextContent());
+        mo.setMarkupContent(mc);
+        return mc;
+    }
+    
+    @Override
+    public final MO concat(MO mo1, MO mo2) throws TemplateModelException {
+        String pc1 = mo1.getPlainTextContent();
+        String mc1 = mo1.getMarkupContent();
+        String pc2 = mo2.getPlainTextContent();
+        String mc2 = mo2.getMarkupContent();
+        
+        String pc3 = pc1 != null && pc2 != null ? pc1 + pc2 : null;
+        String mc3 = mc1 != null && mc2 != null ? mc1 + mc2 : null;
+        if (pc3 != null || mc3 != null) {
+            return newTemplateMarkupOutputModel(pc3, mc3);
+        }
+        
+        if (pc1 != null) {
+            return newTemplateMarkupOutputModel(null, getMarkupString(mo1) + 
mc2);
+        } else {
+            return newTemplateMarkupOutputModel(null, mc1 + 
getMarkupString(mo2));
+        }
+    }
+    
+    @Override
+    public boolean isEmpty(MO mo) throws TemplateModelException {
+        String s = mo.getPlainTextContent();
+        if (s != null) {
+            return s.length() == 0;
+        }
+        return mo.getMarkupContent().length() == 0;
+    }
+    
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+    
+    @Override
+    public boolean isAutoEscapedByDefault() {
+        return true;
+    }
+
+    /**
+     * Creates a new {@link CommonTemplateMarkupOutputModel} that's bound to 
this {@link OutputFormat} instance.
+     */
+    protected abstract MO newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent)
+            throws TemplateModelException;
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/CommonTemplateMarkupOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/CommonTemplateMarkupOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/CommonTemplateMarkupOutputModel.java
new file mode 100644
index 0000000..91cba3a
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/CommonTemplateMarkupOutputModel.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat;
+
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
+
+/**
+ * Common superclass for implementing {@link TemplateMarkupOutputModel}-s that 
belong to a
+ * {@link CommonMarkupOutputFormat} subclass format.
+ * 
+ * <p>
+ * Thread-safe after proper publishing. Calculated fields (typically, the 
markup calculated from plain text) might will
+ * be re-calculated for multiple times if accessed from multiple threads (this 
only affects performance, not
+ * functionality).
+ * 
+ * @since 2.3.24
+ */
+public abstract class CommonTemplateMarkupOutputModel<MO extends 
CommonTemplateMarkupOutputModel<MO>>
+        implements TemplateMarkupOutputModel<MO> {
+
+    private final String plainTextContent;
+    private String markupContent;
+
+    /**
+     * A least one of the parameters must be non-{@code null}!
+     */
+    protected CommonTemplateMarkupOutputModel(String plainTextContent, String 
markupContent) {
+        this.plainTextContent = plainTextContent;
+        this.markupContent = markupContent;
+    }
+
+    @Override
+    public abstract CommonMarkupOutputFormat<MO> getOutputFormat();
+
+    /** Maybe {@code null}, but then {@link #getMarkupContent()} isn't {@code 
null}. */
+    final String getPlainTextContent() {
+        return plainTextContent;
+    }
+
+    /** Maybe {@code null}, but then {@link #getPlainTextContent()} isn't 
{@code null}. */
+    final String getMarkupContent() {
+        return markupContent;
+    }
+
+    /**
+     * Use only to set the value calculated from {@link 
#getPlainTextContent()}, when {@link #getMarkupContent()} was
+     * still {@code null}!
+     */
+    final void setMarkupContent(String markupContent) {
+        this.markupContent = markupContent;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/MarkupOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/MarkupOutputFormat.java 
b/src/main/java/org/apache/freemarker/core/outputformat/MarkupOutputFormat.java
new file mode 100644
index 0000000..ab7a33d
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/MarkupOutputFormat.java
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.TemplateHTMLOutputModel;
+
+/**
+ * Superclass of {@link OutputFormat}-s that represent a "markup" format, 
which is any format where certain character
+ * sequences have special meaning and thus may need escaping. (Escaping is 
important for FreeMarker, as typically it has
+ * to insert non-markup text from the data-model into the output markup. See 
also:
+ * {@link Configuration#setOutputFormat(OutputFormat)}.)
+ * 
+ * <p>
+ * A {@link MarkupOutputFormat} subclass always has a corresponding {@link 
TemplateMarkupOutputModel} subclass pair
+ * (like {@link HTMLOutputFormat} has {@link TemplateHTMLOutputModel}). The 
{@link OutputFormat} implements the
+ * operations related to {@link TemplateMarkupOutputModel} objects of that 
kind, while the
+ * {@link TemplateMarkupOutputModel} only encapsulates the data (the actual 
markup or text).
+ * 
+ * <p>
+ * To implement a custom output format, you may want to extend {@link 
CommonMarkupOutputFormat}.
+ * 
+ * @param <MO>
+ *            The {@link TemplateMarkupOutputModel} class this output format 
can deal with.
+ * 
+ * @since 2.3.24
+ */
+public abstract class MarkupOutputFormat<MO extends TemplateMarkupOutputModel> 
extends OutputFormat {
+
+    protected MarkupOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    /**
+     * Converts a {@link String} that's assumed to be plain text to {@link 
TemplateMarkupOutputModel}, by escaping any
+     * special characters in the plain text. This corresponds to {@code ?esc}, 
or, to outputting with auto-escaping if
+     * that wasn't using {@link #output(String, Writer)} as an optimization.
+     * 
+     * @see #escapePlainText(String)
+     * @see #getSourcePlainText(TemplateMarkupOutputModel)
+     */
+    public abstract MO fromPlainTextByEscaping(String textToEsc) throws 
TemplateModelException;
+
+    /**
+     * Wraps a {@link String} that's already markup to {@link 
TemplateMarkupOutputModel} interface, to indicate its
+     * format. This corresponds to {@code ?noEsc}. (This methods is allowed to 
throw {@link TemplateModelException} if
+     * the parameter markup text is malformed, but it's unlikely that an 
implementation chooses to parse the parameter
+     * until, and if ever, that becomes necessary.)
+     * 
+     * @see #getMarkupString(TemplateMarkupOutputModel)
+     */
+    public abstract MO fromMarkup(String markupText) throws 
TemplateModelException;
+
+    /**
+     * Prints the parameter model to the output.
+     */
+    public abstract void output(MO mo, Writer out) throws IOException, 
TemplateModelException;
+
+    /**
+     * Equivalent to calling {@link #fromPlainTextByEscaping(String)} and then
+     * {@link #output(TemplateMarkupOutputModel, Writer)}, but the 
implementation may uses a more efficient solution.
+     */
+    public abstract void output(String textToEsc, Writer out) throws 
IOException, TemplateModelException;
+    
+    /**
+     * If this {@link TemplateMarkupOutputModel} was created with {@link 
#fromPlainTextByEscaping(String)}, it returns
+     * the original plain text, otherwise it returns {@code null}. Useful for 
converting between different types
+     * of markups, as if the source format can be converted to plain text 
without loss, then that just has to be
+     * re-escaped with the target format to do the conversion.
+     */
+    public abstract String getSourcePlainText(MO mo) throws 
TemplateModelException;
+
+    /**
+     * Returns the content as markup text; never {@code null}. If this {@link 
TemplateMarkupOutputModel} was created
+     * with {@link #fromMarkup(String)}, it might returns the original markup 
text literally, but this is not required
+     * as far as the returned markup means the same. If this {@link 
TemplateMarkupOutputModel} wasn't created
+     * with {@link #fromMarkup(String)} and it doesn't yet have the markup, it 
has to generate the markup now.
+     */
+    public abstract String getMarkupString(MO mo) throws 
TemplateModelException;
+    
+    /**
+     * Returns a {@link TemplateMarkupOutputModel} that contains the content 
of both {@link TemplateMarkupOutputModel}
+     * objects concatenated.
+     */
+    public abstract MO concat(MO mo1, MO mo2) throws TemplateModelException;
+    
+    /**
+     * Should give the same result as {@link #fromPlainTextByEscaping(String)} 
and then
+     * {@link #getMarkupString(TemplateMarkupOutputModel)}, but the 
implementation may uses a more efficient solution.
+     */
+    public abstract String escapePlainText(String plainTextContent) throws 
TemplateModelException;
+
+    /**
+     * Returns if the markup is empty (0 length). This is used by at least 
{@code ?hasContent}.
+     */
+    public abstract boolean isEmpty(MO mo) throws TemplateModelException;
+    
+    /**
+     * Tells if a string built-in that can't handle a {@link 
TemplateMarkupOutputModel} left hand operand can bypass
+     * this object as is. A typical such case would be when a {@link 
TemplateHTMLOutputModel} of "HTML" format bypasses
+     * {@code ?html}.
+     */
+    public abstract boolean isLegacyBuiltInBypassed(String builtInName) throws 
TemplateModelException;
+    
+    /**
+     * Tells if by default auto-escaping should be on for this format. It 
should be {@code true} if you need to escape
+     * on most of the places where you insert values.
+     * 
+     * @see Configuration#setAutoEscapingPolicy(int)
+     */
+    public abstract boolean isAutoEscapedByDefault();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/OutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/OutputFormat.java 
b/src/main/java/org/apache/freemarker/core/outputformat/OutputFormat.java
new file mode 100644
index 0000000..035081a
--- /dev/null
+++ b/src/main/java/org/apache/freemarker/core/outputformat/OutputFormat.java
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.util._ClassUtil;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents an output format. If you need auto-escaping, see its subclass, 
{@link MarkupOutputFormat}.
+ * 
+ * @see Configuration#setOutputFormat(OutputFormat)
+ * @see Configuration#setRegisteredCustomOutputFormats(java.util.Collection)
+ * @see MarkupOutputFormat
+ * 
+ * @since 2.3.24
+ */
+public abstract class OutputFormat {
+
+    /**
+     * The short name used to refer to this format (like in the {@code #ftl} 
header).
+     */
+    public abstract String getName();
+    
+    /**
+     * Returns the MIME type of the output format. This might comes handy when 
generating a HTTP response. {@code null}
+     * {@code null} if this output format doesn't clearly corresponds to a 
specific MIME type.
+     */
+    public abstract String getMimeType();
+
+    /**
+     * Tells if this output format allows inserting {@link 
TemplateMarkupOutputModel}-s of another output formats into
+     * it. If {@code true}, the foreign {@link TemplateMarkupOutputModel} will 
be inserted into the output as is (like
+     * if the surrounding output format was the same). This is usually a bad 
idea to allow, as such an event could
+     * indicate application bugs. If this method returns {@code false} 
(recommended), then FreeMarker will try to
+     * assimilate the inserted value by converting its format to this format, 
which will currently (2.3.24) cause
+     * exception, unless the inserted value is made by escaping plain text and 
the target format is non-escaping, in
+     * which case format conversion is trivially possible. (It's not 
impossible that conversions will be extended beyond
+     * this, if there will be demand for that.)
+     * 
+     * <p>
+     * {@code true} value is used by {@link UndefinedOutputFormat}.
+     */
+    public abstract boolean isOutputFormatMixingAllowed();
+
+    /**
+     * Returns the short description of this format, to be used in error 
messages.
+     * Override {@link #toStringExtraProperties()} to customize this.
+     */
+    @Override
+    public final String toString() {
+        String extras = toStringExtraProperties();
+        return getName() + "("
+                + "mimeType=" + _StringUtil.jQuote(getMimeType()) + ", "
+                + "class=" + _ClassUtil.getShortClassNameOfObject(this, true)
+                + (extras.length() != 0 ? ", " : "") + extras
+                + ")";
+    }
+    
+    /**
+     * Should be like {@code "foo=\"something\", bar=123"}; this will be 
inserted inside the parentheses in
+     * {@link #toString()}. Shouldn't return {@code null}; should return 
{@code ""} if there are no extra properties.  
+     */
+    protected String toStringExtraProperties() {
+        return "";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/UnregisteredOutputFormatException.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/UnregisteredOutputFormatException.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/UnregisteredOutputFormatException.java
new file mode 100644
index 0000000..0dd9976
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/UnregisteredOutputFormatException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat;
+
+import org.apache.freemarker.core.Configuration;
+
+/**
+ * Thrown by {@link Configuration#getOutputFormat(String)}.
+ * 
+ * @since 2.3.24
+ */
+@SuppressWarnings("serial")
+public class UnregisteredOutputFormatException extends Exception {
+
+    public UnregisteredOutputFormatException(String message) {
+        this(message, null);
+    }
+    
+    public UnregisteredOutputFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormat.java
new file mode 100644
index 0000000..b6b045b
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/CombinedMarkupOutputFormat.java
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+
+/**
+ * Represents two markup formats nested into each other. For example, markdown 
nested into HTML.
+ * 
+ * @since 2.3.24
+ */
+public final class CombinedMarkupOutputFormat extends 
CommonMarkupOutputFormat<TemplateCombinedMarkupOutputModel> {
+
+    private final String name;
+    
+    private final MarkupOutputFormat outer;
+    private final MarkupOutputFormat inner;
+
+    /**
+     * Same as {@link #CombinedMarkupOutputFormat(String, MarkupOutputFormat, 
MarkupOutputFormat)} with {@code null} as
+     * the {@code name} parameter.
+     */
+    public CombinedMarkupOutputFormat(MarkupOutputFormat outer, 
MarkupOutputFormat inner) {
+        this(null, outer, inner);
+    }
+    
+    /**
+     * @param name
+     *            Maybe {@code null}, in which case it defaults to
+     *            <code>outer.getName() + "{" + inner.getName() + "}"</code>.
+     */
+    public CombinedMarkupOutputFormat(String name, MarkupOutputFormat outer, 
MarkupOutputFormat inner) {
+        this.name = name != null ? null : outer.getName() + "{" + 
inner.getName() + "}";
+        this.outer = outer;
+        this.inner = inner;
+    }
+    
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getMimeType() {
+        return outer.getMimeType();
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
+        outer.output(inner.escapePlainText(textToEsc), out);
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) throws 
TemplateModelException {
+        return outer.escapePlainText(inner.escapePlainText(plainTextContent));
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) throws 
TemplateModelException {
+        return outer.isLegacyBuiltInBypassed(builtInName);
+    }
+
+    @Override
+    public boolean isAutoEscapedByDefault() {
+        return outer.isAutoEscapedByDefault();
+    }
+    
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return outer.isOutputFormatMixingAllowed();
+    }
+
+    public MarkupOutputFormat getOuterOutputFormat() {
+        return outer;
+    }
+
+    public MarkupOutputFormat getInnerOutputFormat() {
+        return inner;
+    }
+
+    @Override
+    protected TemplateCombinedMarkupOutputModel newTemplateMarkupOutputModel(
+            String plainTextContent, String markupContent) {
+        return new TemplateCombinedMarkupOutputModel(plainTextContent, 
markupContent, this);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormat.java
new file mode 100644
index 0000000..a9a4266
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/HTMLOutputFormat.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents the HTML output format (MIME type "text/html", name "HTML"). 
This format escapes by default (via
+ * {@link _StringUtil#XHTMLEnc(String)}). The {@code ?html}, {@code ?xhtml} 
and {@code ?xml} built-ins silently bypass
+ * template output values of the type produced by this output format ({@link 
TemplateHTMLOutputModel}).
+ * 
+ * @since 2.3.24
+ */
+public final class HTMLOutputFormat extends 
CommonMarkupOutputFormat<TemplateHTMLOutputModel> {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final HTMLOutputFormat INSTANCE = new HTMLOutputFormat();
+    
+    private HTMLOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "HTML";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/html";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
+        _StringUtil.XHTMLEnc(textToEsc, out);
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return _StringUtil.XHTMLEnc(plainTextContent);
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return builtInName.equals("html") || builtInName.equals("xml") || 
builtInName.equals("xhtml");
+    }
+
+    @Override
+    protected TemplateHTMLOutputModel newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent) {
+        return new TemplateHTMLOutputModel(plainTextContent, markupContent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/JSONOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/JSONOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/JSONOutputFormat.java
new file mode 100644
index 0000000..a60e390
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/JSONOutputFormat.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.OutputFormat;
+
+/**
+ * Represents the JSON output format (MIME type "application/json", name 
"JSON"). This format doesn't support escaping.
+ * 
+ * @since 2.3.24
+ */
+public class JSONOutputFormat extends OutputFormat {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final JSONOutputFormat INSTANCE = new JSONOutputFormat();
+    
+    private JSONOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "JSON";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/json";
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/PlainTextOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/PlainTextOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/PlainTextOutputFormat.java
new file mode 100644
index 0000000..f768888
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/PlainTextOutputFormat.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.OutputFormat;
+
+/**
+ * Represents the plain text output format (MIME type "text/plain", name 
"plainText"). This format doesn't support
+ * escaping. This format doesn't allow mixing in template output values of 
other output formats.
+ * 
+ * <p>
+ * The main difference from {@link UndefinedOutputFormat} is that this format 
doesn't allow inserting values of another
+ * output format into itself (unless they can be converted to plain text), 
while {@link UndefinedOutputFormat} would
+ * just insert the foreign "markup" as is. Also, this format has 
{"text/plain"} MIME type, while
+ * {@link UndefinedOutputFormat} has {@code null}.
+ * 
+ * @since 2.3.24
+ */
+public final class PlainTextOutputFormat extends OutputFormat {
+
+    public static final PlainTextOutputFormat INSTANCE = new 
PlainTextOutputFormat();
+    
+    private PlainTextOutputFormat() {
+        // Only to decrease visibility
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "plainText";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "text/plain";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormat.java
new file mode 100644
index 0000000..d29e8aa
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/RTFOutputFormat.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents the Rich Text Format output format (MIME type "application/rtf", 
name "RTF"). This format escapes by
+ * default (via {@link _StringUtil#RTFEnc(String)}). The {@code ?rtf} built-in 
silently bypasses template output values
+ * of the type produced by this output format ({@link TemplateRTFOutputModel}).
+ * 
+ * @since 2.3.24
+ */
+public final class RTFOutputFormat extends 
CommonMarkupOutputFormat<TemplateRTFOutputModel> {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final RTFOutputFormat INSTANCE = new RTFOutputFormat();
+    
+    private RTFOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "RTF";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/rtf";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
+        _StringUtil.RTFEnc(textToEsc, out);
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return _StringUtil.RTFEnc(plainTextContent);
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return builtInName.equals("rtf");
+    }
+
+    @Override
+    protected TemplateRTFOutputModel newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent) {
+        return new TemplateRTFOutputModel(plainTextContent, markupContent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateCombinedMarkupOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateCombinedMarkupOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateCombinedMarkupOutputModel.java
new file mode 100644
index 0000000..7a02442
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateCombinedMarkupOutputModel.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+/**
+ * Stores combined markup to be printed; used with {@link 
CombinedMarkupOutputFormat}.
+ * 
+ * @since 2.3.24
+ */
+public final class TemplateCombinedMarkupOutputModel
+        extends 
CommonTemplateMarkupOutputModel<TemplateCombinedMarkupOutputModel> {
+    
+    private final CombinedMarkupOutputFormat outputFormat;
+    
+    /**
+     * See {@link 
CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, 
String)}.
+     * 
+     * @param outputFormat
+     *            The {@link CombinedMarkupOutputFormat} format this value is 
bound to. Because
+     *            {@link CombinedMarkupOutputFormat} has no singleton, we have 
to pass it in, unlike with most other
+     *            {@link CommonTemplateMarkupOutputModel}-s.
+     */
+    TemplateCombinedMarkupOutputModel(String plainTextContent, String 
markupContent,
+            CombinedMarkupOutputFormat outputFormat) {
+        super(plainTextContent, markupContent);
+        this.outputFormat = outputFormat; 
+    }
+
+    @Override
+    public CombinedMarkupOutputFormat getOutputFormat() {
+        return outputFormat;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateHTMLOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateHTMLOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateHTMLOutputModel.java
new file mode 100644
index 0000000..fbdd73f
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateHTMLOutputModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+/**
+ * Stores HTML markup to be printed; used with {@link HTMLOutputFormat}.
+ * 
+ * @since 2.3.24
+ */
+public final class TemplateHTMLOutputModel extends 
CommonTemplateMarkupOutputModel<TemplateHTMLOutputModel> {
+    
+    /**
+     * See {@link 
CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, 
String)}.
+     */
+    TemplateHTMLOutputModel(String plainTextContent, String markupContent) {
+        super(plainTextContent, markupContent);
+    }
+
+    @Override
+    public HTMLOutputFormat getOutputFormat() {
+        return HTMLOutputFormat.INSTANCE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateRTFOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateRTFOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateRTFOutputModel.java
new file mode 100644
index 0000000..906d475
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateRTFOutputModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+/**
+ * Stores RTF markup to be printed; used with {@link RTFOutputFormat}.
+ * 
+ * @since 2.3.24
+ */
+public final class TemplateRTFOutputModel extends 
CommonTemplateMarkupOutputModel<TemplateRTFOutputModel> {
+    
+    /**
+     * See {@link 
CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, 
String)}.
+     */
+    TemplateRTFOutputModel(String plainTextContent, String markupContent) {
+        super(plainTextContent, markupContent);
+    }
+
+    @Override
+    public RTFOutputFormat getOutputFormat() {
+        return RTFOutputFormat.INSTANCE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXHTMLOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXHTMLOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXHTMLOutputModel.java
new file mode 100644
index 0000000..5ed0a6e
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXHTMLOutputModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+/**
+ * Stores HTML markup to be printed; used with {@link HTMLOutputFormat}.
+ * 
+ * @since 2.3.24
+ */
+public final class TemplateXHTMLOutputModel extends 
CommonTemplateMarkupOutputModel<TemplateXHTMLOutputModel> {
+    
+    /**
+     * See {@link 
CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, 
String)}.
+     */
+    TemplateXHTMLOutputModel(String plainTextContent, String markupContent) {
+        super(plainTextContent, markupContent);
+    }
+
+    @Override
+    public XHTMLOutputFormat getOutputFormat() {
+        return XHTMLOutputFormat.INSTANCE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXMLOutputModel.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXMLOutputModel.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXMLOutputModel.java
new file mode 100644
index 0000000..4039ece
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/TemplateXMLOutputModel.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.outputformat.CommonTemplateMarkupOutputModel;
+
+/**
+ * Stores XML markup to be printed; used with {@link XMLOutputFormat}.
+ * 
+ * @since 2.3.24
+ */
+public final class TemplateXMLOutputModel extends 
CommonTemplateMarkupOutputModel<TemplateXMLOutputModel> {
+    
+    /**
+     * See {@link 
CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, 
String)}.
+     */
+    TemplateXMLOutputModel(String plainTextContent, String markupContent) {
+        super(plainTextContent, markupContent);
+    }
+
+    @Override
+    public XMLOutputFormat getOutputFormat() {
+        return XMLOutputFormat.INSTANCE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/UndefinedOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/UndefinedOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/UndefinedOutputFormat.java
new file mode 100644
index 0000000..e0132a9
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/UndefinedOutputFormat.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import org.apache.freemarker.core.Configuration;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+
+/**
+ * Represents the output format used when the template output format is 
undecided. This is the default output format if
+ * FreeMarker can't select anything more specific (see
+ * {@link 
Configuration#setTemplateConfigurations(org.apache.freemarker.core.templateresolver.TemplateConfigurationFactory)}).
 This format doesn't
+ * support auto-escaping ({@link Configuration#setAutoEscapingPolicy(int)}). 
It will print
+ * {@link TemplateMarkupOutputModel}-s as is (doesn't try to convert them).
+ * 
+ * @see PlainTextOutputFormat
+ * 
+ * @since 2.3.24
+ */
+public final class UndefinedOutputFormat extends OutputFormat {
+
+    public static final UndefinedOutputFormat INSTANCE = new 
UndefinedOutputFormat();
+    
+    private UndefinedOutputFormat() {
+        // Only to decrease visibility
+    }
+
+    @Override
+    public boolean isOutputFormatMixingAllowed() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "undefined";
+    }
+
+    @Override
+    public String getMimeType() {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/XHTMLOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/XHTMLOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/XHTMLOutputFormat.java
new file mode 100644
index 0000000..0e8199a
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/XHTMLOutputFormat.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents the XML output format (MIME type "application/xhtml+xml", name 
"XHTML"). This format escapes by default
+ * (via {@link _StringUtil#XHTMLEnc(String)}). The {@code ?xml} built-in 
silently bypasses template output values of the
+ * type produced by this output format ({@link TemplateXHTMLOutputModel}).
+ * 
+ * @since 2.3.24
+ */
+public final class XHTMLOutputFormat extends 
CommonMarkupOutputFormat<TemplateXHTMLOutputModel> {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final XHTMLOutputFormat INSTANCE = new XHTMLOutputFormat();
+    
+    private XHTMLOutputFormat() {
+        // Only to decrease visibility
+    }
+    
+    @Override
+    public String getName() {
+        return "XHTML";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/xhtml+xml";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
+        _StringUtil.XHTMLEnc(textToEsc, out);
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return _StringUtil.XHTMLEnc(plainTextContent);
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return builtInName.equals("html") || builtInName.equals("xml") || 
builtInName.equals("xhtml");
+    }
+
+    @Override
+    protected TemplateXHTMLOutputModel newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent) {
+        return new TemplateXHTMLOutputModel(plainTextContent, markupContent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/outputformat/impl/XMLOutputFormat.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/freemarker/core/outputformat/impl/XMLOutputFormat.java
 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/XMLOutputFormat.java
new file mode 100644
index 0000000..c365dbb
--- /dev/null
+++ 
b/src/main/java/org/apache/freemarker/core/outputformat/impl/XMLOutputFormat.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.freemarker.core.outputformat.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.outputformat.CommonMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.util._StringUtil;
+
+/**
+ * Represents the XML output format (MIME type "application/xml", name "XML"). 
This format escapes by default (via
+ * {@link _StringUtil#XMLEnc(String)}). The {@code ?html}, {@code ?xhtml} and 
{@code ?xml} built-ins silently bypass
+ * template output values of the type produced by this output format ({@link 
TemplateXHTMLOutputModel}).
+ * 
+ * @since 2.3.24
+ */
+public final class XMLOutputFormat extends 
CommonMarkupOutputFormat<TemplateXMLOutputModel> {
+
+    /**
+     * The only instance (singleton) of this {@link OutputFormat}.
+     */
+    public static final XMLOutputFormat INSTANCE = new XMLOutputFormat();
+
+    private XMLOutputFormat() {
+        // Only to decrease visibility
+    }
+
+    @Override
+    public String getName() {
+        return "XML";
+    }
+
+    @Override
+    public String getMimeType() {
+        return "application/xml";
+    }
+
+    @Override
+    public void output(String textToEsc, Writer out) throws IOException, 
TemplateModelException {
+        _StringUtil.XMLEnc(textToEsc, out);
+    }
+
+    @Override
+    public String escapePlainText(String plainTextContent) {
+        return _StringUtil.XMLEnc(plainTextContent);
+    }
+
+    @Override
+    public boolean isLegacyBuiltInBypassed(String builtInName) {
+        return builtInName.equals("xml");
+    }
+
+    @Override
+    protected TemplateXMLOutputModel newTemplateMarkupOutputModel(String 
plainTextContent, String markupContent) {
+        return new TemplateXMLOutputModel(plainTextContent, markupContent);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/util/FTLUtil.java 
b/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
index fd5a1b2..9f0cca7 100644
--- a/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
+++ b/src/main/java/org/apache/freemarker/core/util/FTLUtil.java
@@ -22,7 +22,6 @@ import java.util.HashSet;
 import java.util.Set;
 
 import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.TemplateMarkupOutputModel;
 import org.apache.freemarker.core._CoreAPI;
 import org.apache.freemarker.core.model.AdapterTemplateModel;
 import org.apache.freemarker.core.model.TemplateBooleanModel;
@@ -32,6 +31,7 @@ import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateDirectiveModel;
 import org.apache.freemarker.core.model.TemplateHashModel;
 import org.apache.freemarker.core.model.TemplateHashModelEx;
+import org.apache.freemarker.core.model.TemplateMarkupOutputModel;
 import org.apache.freemarker.core.model.TemplateMethodModel;
 import org.apache.freemarker.core.model.TemplateMethodModelEx;
 import org.apache.freemarker.core.model.TemplateModel;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java 
b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
index e510aad..31ad038 100644
--- a/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
+++ b/src/main/java/org/apache/freemarker/servlet/FreemarkerServlet.java
@@ -45,12 +45,12 @@ import org.apache.freemarker.core.Configurable;
 import org.apache.freemarker.core.Configuration;
 import org.apache.freemarker.core.ConfigurationException;
 import org.apache.freemarker.core.Environment;
-import org.apache.freemarker.core.OutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
 import org.apache.freemarker.core.Template;
 import org.apache.freemarker.core.TemplateException;
 import org.apache.freemarker.core.TemplateExceptionHandler;
 import org.apache.freemarker.core.TemplateNotFoundException;
-import org.apache.freemarker.core.UndefinedOutputFormat;
 import org.apache.freemarker.core._CoreLogs;
 import org.apache.freemarker.core.model.ObjectWrapper;
 import org.apache.freemarker.core.model.TemplateModel;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/main/javacc/FTL.jj
----------------------------------------------------------------------
diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index 5ad8488..db28a0e 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -30,6 +30,8 @@ PARSER_BEGIN(FMParser)
 package org.apache.freemarker.core;
 
 import org.apache.freemarker.core.*;
+import org.apache.freemarker.core.outputformat.*;
+import org.apache.freemarker.core.outputformat.impl.*;
 import org.apache.freemarker.core.model.*;
 import org.apache.freemarker.core.model.impl.*;
 import org.apache.freemarker.core.util.*;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/manual/en_US/FM3-CHANGE-LOG.txt
----------------------------------------------------------------------
diff --git a/src/manual/en_US/FM3-CHANGE-LOG.txt 
b/src/manual/en_US/FM3-CHANGE-LOG.txt
index b32149f..a471514 100644
--- a/src/manual/en_US/FM3-CHANGE-LOG.txt
+++ b/src/manual/en_US/FM3-CHANGE-LOG.txt
@@ -70,6 +70,7 @@ the FreeMarer 3 changelog here:
   were moved to org.apache.freemarker.core.model, and template loading and 
caching related classes
   to org.apache.freemarker.core.templateresolver (because later we will have a 
class called
   TemplateResolver, which is the central class of loading and caching and 
template name rules).
+  OutputFormat realted classes were moved to 
org.apache.freemarker.core.outputformat.
   freemarker.ext.beans were moved under 
org.apache.freemarker.core.model.impl.beans for now (but later
   we only want a DefaultObject wrapper, no BeansWrapper, so this will change) 
and freemarker.ext.dom
   was moved to org.apache.freemarker.core.model.impl.dom.

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/CamelCaseTest.java 
b/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
index 859442c..bf52222 100644
--- a/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
+++ b/src/test/java/org/apache/freemarker/core/CamelCaseTest.java
@@ -27,12 +27,8 @@ import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 
-import org.apache.freemarker.core.ASTExpBuiltIn;
-import org.apache.freemarker.core.ASTExpBuiltInVariable;
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.HTMLOutputFormat;
-import org.apache.freemarker.core.TemplateException;
-import org.apache.freemarker.core.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
 import org.apache.freemarker.core.util._StringUtil;
 import org.apache.freemarker.test.TemplateTest;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java 
b/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
index fe8da82..3cc052d 100644
--- a/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
+++ b/src/test/java/org/apache/freemarker/core/CoercionToTextualTest.java
@@ -22,9 +22,7 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.Date;
 
-import org.apache.freemarker.core.Configuration;
-import org.apache.freemarker.core.HTMLOutputFormat;
-import org.apache.freemarker.core.TemplateException;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
 import org.apache.freemarker.core.model.TemplateDateModel;
 import org.apache.freemarker.core.model.TemplateModelException;
 import org.apache.freemarker.core.model.impl.SimpleDate;

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/test/java/org/apache/freemarker/core/CombinedMarkupOutputFormatTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/core/CombinedMarkupOutputFormatTest.java 
b/src/test/java/org/apache/freemarker/core/CombinedMarkupOutputFormatTest.java
deleted file mode 100644
index 783c437..0000000
--- 
a/src/test/java/org/apache/freemarker/core/CombinedMarkupOutputFormatTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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.
- */
-package org.apache.freemarker.core;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.StringWriter;
-
-import org.apache.freemarker.core.CombinedMarkupOutputFormat;
-import org.apache.freemarker.core.HTMLOutputFormat;
-import org.apache.freemarker.core.MarkupOutputFormat;
-import org.apache.freemarker.core.RTFOutputFormat;
-import org.apache.freemarker.core.TemplateCombinedMarkupOutputModel;
-import org.apache.freemarker.core.XMLOutputFormat;
-import org.apache.freemarker.core.model.TemplateModelException;
-import org.junit.Test; 
-
-public class CombinedMarkupOutputFormatTest {
-    
-    private static final CombinedMarkupOutputFormat HTML_RTF = new 
CombinedMarkupOutputFormat(
-            HTMLOutputFormat.INSTANCE, RTFOutputFormat.INSTANCE);
-    private static final CombinedMarkupOutputFormat XML_XML = new 
CombinedMarkupOutputFormat(
-            XMLOutputFormat.INSTANCE, XMLOutputFormat.INSTANCE);
-
-    @Test
-    public void testName() {
-        assertEquals("HTML{RTF}", HTML_RTF.getName());
-        assertEquals("XML{XML}", XML_XML.getName());
-    }
-    
-    @Test
-    public void testOutputMO() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       HTML_RTF.output(HTML_RTF.fromMarkup("<pre>\\par Test "), out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("foo { bar } \\ "), 
out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("& baaz "), out);
-       HTML_RTF.output(HTML_RTF.fromPlainTextByEscaping("\\par & qwe"), out);
-       HTML_RTF.output(HTML_RTF.fromMarkup("\\par{0} End</pre>"), out);
-       
-       assertEquals(
-               "<pre>\\par Test "
-               + "foo \\{ bar \\} \\\\ "
-               + "&amp; baaz "
-               + "\\\\par &amp; qwe"
-               + "\\par{0} End</pre>",
-               out.toString());
-    }
-
-    @Test
-    public void testOutputMO2() throws TemplateModelException, IOException {
-       StringWriter out = new StringWriter();
-       
-       XML_XML.output(XML_XML.fromMarkup("<pre>&lt;p&gt; Test "), out);
-       XML_XML.output(XML_XML.fromPlainTextByEscaping("a & b < c"), out);
-       XML_XML.output(XML_XML.fromMarkup(" End</pre>"), out);
-       
-       assertEquals(
-               "<pre>&lt;p&gt; Test "
-               + "a &amp;amp; b &amp;lt; c"
-               + " End</pre>",
-               out.toString());
-    }
-
-    @Test
-    public void testOutputMO3() throws TemplateModelException, IOException {
-        MarkupOutputFormat outputFormat = new CombinedMarkupOutputFormat(
-                RTFOutputFormat.INSTANCE,
-                new CombinedMarkupOutputFormat(RTFOutputFormat.INSTANCE, 
RTFOutputFormat.INSTANCE));
-        StringWriter out = new StringWriter();
-        
-        outputFormat.output(outputFormat.fromPlainTextByEscaping("b{}"), out);
-        outputFormat.output(outputFormat.fromMarkup("a{}"), out);
-        
-        assertEquals(
-                "b\\\\\\\\\\\\\\{\\\\\\\\\\\\\\}"
-                + "a{}",
-                out.toString());
-    }
-    
-    @Test
-    public void testOutputString() throws TemplateModelException, IOException {
-        StringWriter out = new StringWriter();
-        
-        HTML_RTF.output("a", out);
-        HTML_RTF.output("{", out);
-        HTML_RTF.output("<b>}c", out);
-        
-        assertEquals("a\\{&lt;b&gt;\\}c", out.toString());
-    }
-    
-    @Test
-    public void testOutputString2() throws TemplateModelException, IOException 
{
-        StringWriter out = new StringWriter();
-        
-        XML_XML.output("a", out);
-        XML_XML.output("&", out);
-        XML_XML.output("<b>", out);
-        
-        assertEquals("a&amp;amp;&amp;lt;b&amp;gt;", out.toString());
-    }
-    
-    @Test
-    public void testFromPlainTextByEscaping() throws TemplateModelException {
-        String plainText = "a\\b&c";
-        TemplateCombinedMarkupOutputModel mo = 
HTML_RTF.fromPlainTextByEscaping(plainText);
-        assertSame(plainText, mo.getPlainTextContent());
-        assertNull(mo.getMarkupContent()); // Not the MO's duty to calculate 
it!
-    }
-
-    @Test
-    public void testFromMarkup() throws TemplateModelException {
-        String markup = "a \\par <b>";
-        TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
-        assertSame(markup, mo.getMarkupContent());
-        assertNull(mo.getPlainTextContent()); // Not the MO's duty to 
calculate it!
-    }
-    
-    @Test
-    public void testGetMarkup() throws TemplateModelException {
-        {
-            String markup = "a \\par <b>";
-            TemplateCombinedMarkupOutputModel mo = HTML_RTF.fromMarkup(markup);
-            assertSame(markup, HTML_RTF.getMarkupString(mo));
-        }
-        
-        {
-            String safe = "abc";
-            TemplateCombinedMarkupOutputModel mo = 
HTML_RTF.fromPlainTextByEscaping(safe);
-            assertSame(safe, HTML_RTF.getMarkupString(mo));
-        }
-    }
-    
-    @Test
-    public void testConcat() throws Exception {
-        assertMO(
-                "ab", null,
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel("a", null, 
HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel("b", null, 
HTML_RTF)));
-        assertMO(
-                null, "ab",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel(null, "a", 
HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel(null, "b", 
HTML_RTF)));
-        assertMO(
-                null, "{<a>}\\{&lt;b&gt;\\}",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel(null, "{<a>}", 
HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel("{<b>}", null, 
HTML_RTF)));
-        assertMO(
-                null, "\\{&lt;a&gt;\\}{<b>}",
-                HTML_RTF.concat(
-                        new TemplateCombinedMarkupOutputModel("{<a>}", null, 
HTML_RTF),
-                        new TemplateCombinedMarkupOutputModel(null, "{<b>}", 
HTML_RTF)));
-    }
-    
-    @Test
-    public void testEscaplePlainText() throws TemplateModelException {
-        assertEquals("", HTML_RTF.escapePlainText(""));
-        assertEquals("a", HTML_RTF.escapePlainText("a"));
-        assertEquals("\\{a\\\\b&amp;\\}", HTML_RTF.escapePlainText("{a\\b&}"));
-        assertEquals("a\\\\b&amp;", HTML_RTF.escapePlainText("a\\b&"));
-        assertEquals("\\{\\}&amp;", HTML_RTF.escapePlainText("{}&"));
-        
-        assertEquals("a", XML_XML.escapePlainText("a"));
-        assertEquals("a&amp;apos;b", XML_XML.escapePlainText("a'b"));
-    }
-    
-    private void assertMO(String pc, String mc, 
TemplateCombinedMarkupOutputModel mo) {
-        assertEquals(pc, mo.getPlainTextContent());
-        assertEquals(mc, mo.getMarkupContent());
-    }
-    
-    @Test
-    public void testGetMimeType() {
-        assertEquals("text/html", HTML_RTF.getMimeType());
-        assertEquals("application/xml", XML_XML.getMimeType());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/db77001f/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java 
b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
index 08132ad..7930632 100644
--- a/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
+++ b/src/test/java/org/apache/freemarker/core/ConfigurationTest.java
@@ -54,6 +54,14 @@ import org.apache.freemarker.core.model.impl.SimpleScalar;
 import org.apache.freemarker.core.model.impl._StaticObjectWrappers;
 import org.apache.freemarker.core.model.impl.beans.BeansWrapperBuilder;
 import org.apache.freemarker.core.model.impl.beans.StringModel;
+import org.apache.freemarker.core.outputformat.MarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.OutputFormat;
+import 
org.apache.freemarker.core.outputformat.UnregisteredOutputFormatException;
+import org.apache.freemarker.core.outputformat.impl.CombinedMarkupOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.HTMLOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.RTFOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat;
+import org.apache.freemarker.core.outputformat.impl.XMLOutputFormat;
 import org.apache.freemarker.core.templateresolver.CacheStorageWithGetSize;
 import org.apache.freemarker.core.templateresolver.TemplateLookupContext;
 import org.apache.freemarker.core.templateresolver.TemplateLookupResult;
@@ -67,6 +75,8 @@ import 
org.apache.freemarker.core.templateresolver.impl.NullCacheStorage;
 import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage;
 import org.apache.freemarker.core.templateresolver.impl.StringTemplateLoader;
 import org.apache.freemarker.core.templateresolver.impl.StrongCacheStorage;
+import org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat;
+import org.apache.freemarker.core.userpkg.DummyOutputFormat;
 import org.apache.freemarker.core.util._DateUtil;
 import org.apache.freemarker.core.util._NullArgumentException;
 import org.apache.freemarker.core.util._NullWriter;
@@ -891,7 +901,8 @@ public class ConfigurationTest extends TestCase {
         assertTrue(cfg.getRegisteredCustomOutputFormats().isEmpty());
         
         
cfg.setSetting(Configuration.REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_CAMEL_CASE,
-                "[org.apache.freemarker.core.CustomHTMLOutputFormat(), 
org.apache.freemarker.core.DummyOutputFormat()]");
+                "[org.apache.freemarker.core.userpkg.CustomHTMLOutputFormat(), 
"
+                + "org.apache.freemarker.core.userpkg.DummyOutputFormat()]");
         assertEquals(
                 ImmutableList.of(CustomHTMLOutputFormat.INSTANCE, 
DummyOutputFormat.INSTANCE),
                 new ArrayList(cfg.getRegisteredCustomOutputFormats()));


Reply via email to