function RenderManager() {

		var that = this,
			aBuffer,
			aRenderedControls,
			aStyleStack,
			bLocked,
			sOpenTag = "",                 // stores the last open tag that is used for the validation
			bVoidOpen = false,             // specifies whether the last open tag is a void tag or not
			bDomInterface,                 // specifies the rendering interface that is used by the control renderers
			sLegacyRendererControlId = "", // stores the id of the control that has a legacy renderer while its parent has the new semantic renderer
			oStringInterface = {},         // holds old string based rendering API and the string implementation of the new semantic rendering API
			oDomInterface = {},            // semantic rendering API for the controls whose renderer provides apiVersion=2 marker
			aRenderingStyles = [],         // during string-based rendering, stores the styles that couldn't be set via style attribute due to CSP restrictions
			oPatcher = new Patcher(),      // the Patcher instance to handle in-place DOM patching
			iOpenTagCount = 0,             // the number of open tags, this is used to detect missing tags
			sLastStyleMethod,
			sLastClassMethod;

		/**
		 * Reset all rendering related buffers.
		 */
		function reset() {
			assert(!(sLastStyleMethod = sLastClassMethod = ""));
			aBuffer = that.aBuffer = [];
			aRenderedControls = that.aRenderedControls = [];
			aStyleStack = that.aStyleStack = [{}];
			bDomInterface = undefined;
			bVoidOpen = false;
			iOpenTagCount = 0;
			sOpenTag = "";
		}

		function writeAttribute(sName, vValue) {
			aBuffer.push(" ", sName, "=\"", vValue, "\"");
		}

		function writeClasses(oElement) {
			var oStyle = aStyleStack[aStyleStack.length - 1];

			// Custom classes are added by default from the currently rendered control. If an oElement is given, this Element's custom style
			// classes are added instead. If oElement === false, no custom style classes are added.
			var aCustomClasses;
			if (oElement) {
				aCustomClasses = oElement.aCustomStyleClasses;
			} else if (oElement === false) {
				aCustomClasses = [];
			} else {
				aCustomClasses = oStyle.aCustomStyleClasses;
			}

			if (oStyle.aClasses || aCustomClasses) {
				var aClasses = [].concat(oStyle.aClasses || [], aCustomClasses || []);
				if (aClasses.length) {
					writeAttribute("class", aClasses.join(" "));
				}
			}

			if (!oElement) {
				oStyle.aCustomStyleClasses = null;
			}
			oStyle.aClasses = null;
		}

		/**
		 * Used by the string rendering APIs to write out the collected styles during writeStyles/openEnd/voidEnd
		 * @param {sap.ui.core.RenderManager} oRm The <code>RenderManager</code> instance
		 * @private
		 */
		function writeStyles() {
			var oStyle = aStyleStack[aStyleStack.length - 1];
			if (oStyle.aStyle && oStyle.aStyle.length) {
				// Due to possible CSP restrictions we do not write styles into the HTML buffer. Instead, we store the styles in the aRenderingStyles array
				// and add a ATTR_STYLE_KEY_MARKER attribute marker for which the value references the original style index in the aRenderingStyles array.
				writeAttribute(ATTR_STYLE_KEY_MARKER, aRenderingStyles.push(oStyle.aStyle.join(" ")) - 1);
			}
			oStyle.aStyle = null;
		}

		//#################################################################################################
		// Assertion methods for validating Semantic Rendering API calls
		// These methods will be converted to inline asserts when assertion removal is supported
		//#################################################################################################

		function assertValidName(sName, sField) {
			assert(sName && typeof sName == "string" && /^[a-z_][a-zA-Z0-9_\-]*$/.test(sName), "The " + sField + " name provided '" + sName + "' is not valid; it must contain alphanumeric characters, hyphens or underscores");
		}

		function assertOpenTagHasStarted(sMethod) {
			assert(sOpenTag, "There is no open tag; '" + sMethod + "' must not be called without an open tag");
		}

		function assertOpenTagHasEnded(bCustomAssertion) {
			var bAssertion = (bCustomAssertion === undefined) ? !sOpenTag : bCustomAssertion;
			assert(bAssertion, "There is an open tag; '" + sOpenTag + "' tag has not yet ended with '" + (bVoidOpen ? "voidEnd" : "openEnd") + "'");
		}

		function assertValidAttr(sAttr) {
			assertValidName(sAttr, "attr");
			assert((sAttr != "class" || sLastClassMethod != "class" && (sLastClassMethod = "attr"))
				&& (sAttr != "style" || sLastStyleMethod != "style" && (sLastStyleMethod = "attr")),
				"Attributes 'class' and 'style' must not be written when the methods with the same name"
				+ " have been called for the same element already");
		}

		function assertValidClass(sClass) {
			assert(sLastClassMethod != "attr" && (sLastClassMethod = "class"),
				"Method class() must not be called after the 'class' attribute has been written for the same element");
			assert(typeof sClass == "string" && !/\s/.test(sClass) && arguments.length === 1, "Method 'class' must be called with exactly one class name");
		}

		function assertValidStyle(sStyle) {
			assert(sLastStyleMethod != "attr" && (sLastStyleMethod = "style"),
				"Method style() must not be called after the 'style' attribute has been written for the same element");
			assert(sStyle && typeof sStyle == "string" && !/\s/.test(sStyle), "Method 'style' must be called with a non-empty string name");
		}

		//#################################################################################################
		// Methods for 'Buffered writer' functionality... (all public)
		// i.e. used methods in render-method of Renderers
		//#################################################################################################

		/**
		 * Write the given texts to the buffer.
		 * @param {...string|number} sText (can be a number too)
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead, use the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 *   There is no 1:1 replacement for <code>write</code>. Typically, <code>write</code> is used to create
		 *   a longer sequence of HTML markup (e.g. an element with attributes and children) in a single call.
		 *   Such a markup sequence has to be split into the individual calls of the Semantic Rendering API.
		 *
		 *   <br><br>Example:<br>
		 *     oRm.write("&lt;span id=\"" + oCtrl.getId() + "-outer\" class=\"myCtrlOuter\"&gt;"
		 *        + "&amp;nbsp;" + oResourceBundle.getText("TEXT_KEY") + "&amp;nbsp;&lt;/span&gt;");
		 *   <br><br>
		 *   has to be transformed to
		 *   <br><br>
		 *   oRm.openStart("span", oCtrl.getId() + "-outer").class("myCtrlOuter").openEnd().text("\u00a0" + oResourceBundle.getText("TEXT_KEY") + "\u00a0").close("span");
		 *   <br><br>
		 *   Note that "&amp;nbsp;" was replaced with "\u00a0" (no-break-space). In general, HTML entities
		 *   have to be replaced by the corresponding Unicode character escapes. A mapping table can be found
		 *   at {@link https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references}.
		 *
		 * @SecSink {*|XSS}
		 */
		this.write = function(/** string|number */ sText /* ... */) {
			assert(( typeof sText === "string") || ( typeof sText === "number"), "sText must be a string or number");
			aBuffer.push.apply(aBuffer, arguments);
			return this;
		};

		/**
		 * Escape text for HTML and write it to the buffer.
		 *
		 * For details about the escaping refer to {@link sap/base/security/encodeXML}.
		 *
		 * @param {any} sText the text to escape
		 * @param {boolean} [bLineBreaks=false] Whether to convert line breaks into <br> tags
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead use {@link sap.ui.core.RenderManager#text} of the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 */
		this.writeEscaped = function(sText, bLineBreaks) {
			if ( sText != null ) {
				sText = encodeXML( String(sText) );
				if (bLineBreaks) {
					sText = sText.replace(/&#xa;/g, "<br>");
				}
				aBuffer.push(sText);
			}
			return this;
		};

		/**
		 * Writes the attribute and its value into the HTML.
		 *
		 * For details about the escaping refer to {@link sap/base/security/encodeXML}.
		 *
		 * @param {string} sName Name of the attribute
		 * @param {string | number | boolean} vValue Value of the attribute
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead use {@link sap.ui.core.RenderManager#attr} of the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 * @SecSink {0 1|XSS} Attributes are written to HTML without validation
		 */
		this.writeAttribute = function(sName, vValue) {
			assert(typeof sName === "string", "sName must be a string");
			assert(typeof vValue === "string" || typeof vValue === "number" || typeof vValue === "boolean", "value must be a string, number or boolean");
			aBuffer.push(" ", sName, "=\"", vValue, "\"");
			return this;
		};

		/**
		 * Writes the attribute and a value into the HTML, the value will be encoded.
		 *
		 * The value is properly encoded to avoid XSS attacks.
		 *
		 * @param {string} sName Name of the attribute
		 * @param {any} vValue Value of the attribute
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead use {@link sap.ui.core.RenderManager#attr} of the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 * @SecSink {0|XSS}
		 */
		this.writeAttributeEscaped = function(sName, vValue) {
			assert(typeof sName === "string", "sName must be a string");
			aBuffer.push(" ", sName, "=\"", encodeXML(String(vValue)), "\"");
			return this;
		};

		/**
		 * Adds a style property to the style collection if the value is not empty or null
		 * The style collection is flushed if it is written to the buffer using {@link #writeStyle}
		 *
		 * @param {string} sName Name of the CSS property to write
		 * @param {string|float|int} vValue Value to write
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead use {@link sap.ui.core.RenderManager#style} of the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 * @SecSink {0 1|XSS} Styles are written to HTML without validation
		 */
		this.addStyle = function(sName, vValue) {
			assert(typeof sName === "string", "sName must be a string");
			if (vValue != null && vValue != "") {
				assert((typeof vValue === "string" || typeof vValue === "number"), "value must be a string or number");
				var oStyle = aStyleStack[aStyleStack.length - 1];
				if (!oStyle.aStyle) {
					oStyle.aStyle = [];
				}
				oStyle.aStyle.push(sName + ": " + vValue + ";");
			}
			return this;
		};

		/**
		 * Writes and flushes the style collection
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Not longer needed, when using the {@link sap.ui.core.RenderManager Semantic Rendering API}
		 *  the actual writing of styles happens when {@link sap.ui.core.RenderManager#openEnd} or {@link sap.ui.core.RenderManager#voidEnd} are used.
		 */
		this.writeStyles = function() {
			writeStyles();
			return this;
		};

		/**
		 * Adds a class to the class collection if the name is not empty or null.
		 * The class collection is flushed if it is written to the buffer using {@link #writeClasses}
		 *
		 * @param {string} sName name of the class to be added; null values are ignored
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Instead use {@link sap.ui.core.RenderManager#class} of the {@link sap.ui.core.RenderManager Semantic Rendering API}.
		 * @SecSink {0|XSS} Classes are written to HTML without validation
		 */
		this.addClass = function(sName) {
			if (sName) {
				assert(typeof sName === "string", "sName must be a string");
				var oStyle = aStyleStack[aStyleStack.length - 1];
				if (!oStyle.aClasses) {
					oStyle.aClasses = [];
				}
				oStyle.aClasses.push(sName);
			}
			return this;
		};

		/**
		 * Writes and flushes the class collection (all CSS classes added by "addClass()" since the last flush).
		 * Also writes the custom style classes added by the application with "addStyleClass(...)". Custom classes are
		 * added by default from the currently rendered control. If an oElement is given, this Element's custom style
		 * classes are added instead. If oElement === false, no custom style classes are added.
		 *
		 * @param {sap.ui.core.Element | boolean} [oElement] an Element from which to add custom style classes (instead of adding from the control itself)
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @deprecated Since 1.92. Not longer needed, when using the {@link sap.ui.core.RenderManager Semantic Rendering API}
		 *  the actual writing of classes happens when {@link sap.ui.core.RenderManager#openEnd} or {@link sap.ui.core.RenderManager#voidEnd} are used.
		 */
		this.writeClasses = function(oElement) {
			assert(!oElement || typeof oElement === "boolean" || BaseObject.isObjectA(oElement, 'sap.ui.core.Element'), "oElement must be empty, a boolean, or an sap.ui.core.Element");
			writeClasses(oElement);
			return this;
		};

		//#################################################################################################
		// Semantic Rendering Interface for String Based Rendering
		//#################################################################################################

		/**
		 * Opens the start tag of an HTML element.
		 *
		 * This must be followed by <code>openEnd</code> and concluded with <code>close</code>.
		 * To allow a more efficient DOM update, all tag names have to be used in their canonical form.
		 * For HTML elements, {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element tag names} must all be set in lowercase.
		 * For foreign elements, such as SVG, {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Element tag names} can be set in upper camel case (e.g. linearGradient).
		 *
		 * @param {string} sTagName Tag name of the HTML element
	 	 * @param {sap.ui.core.Element|sap.ui.core.ID} [vControlOrId] Control instance or ID to identify the element
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 *
		 * @public
		 * @since 1.67
		 */
		this.openStart = function(sTagName, vControlOrId) {
			assertValidName(sTagName, "tag");
			assertOpenTagHasEnded();
			assert(!(sLastStyleMethod = sLastClassMethod = ""));
			sOpenTag = sTagName;
			iOpenTagCount++;

			aBuffer.push("<" + sTagName);
			if (vControlOrId) {
				if (typeof vControlOrId == "string") {
					this.attr("id", vControlOrId);
				} else {
					assert(vControlOrId && BaseObject.isObjectA(vControlOrId, 'sap.ui.core.Element'), "vControlOrId must be an sap.ui.core.Element");

					this.attr("id", vControlOrId.getId());
					renderElementData(this, vControlOrId);
				}
			}

			return this;
		};

		/**
		 * Ends an open tag started with <code>openStart</code>.
		 *
		 * This indicates that there are no more attributes to set to the open tag.
		 *
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.openEnd = function(bExludeStyleClasses /* private */) {
			assertOpenTagHasStarted("openEnd");
			assertOpenTagHasEnded(!bVoidOpen);
			assert(bExludeStyleClasses === undefined || bExludeStyleClasses === true, "The private parameter bExludeStyleClasses must be true or omitted!");
			sOpenTag = "";

			writeClasses(bExludeStyleClasses === true ? false : undefined);
			writeStyles();
			aBuffer.push(">");
			return this;
		};

		/**
		 * Closes an open tag started with <code>openStart</code> and ended with <code>openEnd</code>.
		 *
		 * This indicates that there are no more children to append to the open tag.
		 *
		 * @param {string} sTagName Tag name of the HTML element
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.close = function(sTagName) {
			assertValidName(sTagName, "tag");
			assertOpenTagHasEnded();
			iOpenTagCount--;

			aBuffer.push("</" + sTagName + ">");
			return this;
		};

		/**
		 * Starts a self-closing tag, such as <code>img</code> or <code>input</code>.
		 *
		 * This must be followed by <code>voidEnd</code>. For self-closing tags, the <code>close</code> method must not be called.
		 * To allow a more efficient DOM update, void tag names have to be set in lowercase.
		 * This API is specific for void elements and must not be used for foreign elements.
		 * For more information, see {@link https://www.w3.org/TR/html5/syntax.html#void-elements}.
		 *
		 * @param {string} sTagName Tag name of the HTML element
		 * @param {sap.ui.core.Element|sap.ui.core.ID} [vControlOrId] Control instance or ID to identify the element
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.voidStart = function (sTagName, vControlOrId) {
			this.openStart(sTagName, vControlOrId);

			bVoidOpen = true;
			return this;
		};

		/**
		 * Ends an open self-closing tag started with <code>voidStart</code>.
		 *
		 * This indicates that there are no more attributes to set to the open tag.
		 * For self-closing tags <code>close</code> must not be called.
		 *
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.voidEnd = function (bExludeStyleClasses /* private */) {
			assertOpenTagHasStarted("voidEnd");
			assertOpenTagHasEnded(bVoidOpen || !sOpenTag);
			bVoidOpen = false;
			iOpenTagCount--;
			sOpenTag = "";

			writeClasses(bExludeStyleClasses ? false : undefined);
			writeStyles();
			aBuffer.push(">");
			return this;
		};

		/**
		 * Sets the given HTML markup without any encoding or sanitizing.
		 *
		 * This must not be used for plain texts; use the <code>text</code> method instead.
		 *
		 * @param {string} sHtml Well-formed, valid HTML markup
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 * @SecSink {*|XSS}
		 */
		this.unsafeHtml = function(sHtml) {
			assertOpenTagHasEnded();

			aBuffer.push(sHtml);
			return this;
		};

		/**
		 * Sets the text content with the given text.
		 *
		 * Line breaks are not supported by this method, use CSS
		 * {@link https://www.w3.org/TR/CSS2/text.html#white-space-prop white-space: pre-line}
		 * option to implement line breaks.
		 *
		 * HTML entities are not supported by this method,
		 * use unicode escaping or the unicode character to implement HTML entities.
		 * For further information see
		 * {@link https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references}.
		 *
		 * @param {string} sText The text to be written
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.text = function(sText) {
			assertOpenTagHasEnded();
			if ( sText != null ) {
				sText = encodeXML( String(sText) );
				aBuffer.push(sText);
			}
			return this;
		};

		/**
		 * Adds an attribute name-value pair to the last open HTML element.
		 *
		 * This is only valid when called between <code>openStart/voidStart</code> and <code>openEnd/voidEnd</code>.
		 * The attribute name must not be equal to <code>style</code> or <code>class</code>.
		 * Styles and classes must be set via dedicated <code>class</code> or <code>style</code> methods.
		 * To update the DOM correctly, all attribute names have to be used in their canonical form.
		 * For HTML elements, {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes attribute names} must all be set in lowercase.
		 * For foreign elements, such as SVG, {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute attribute names} can be set in upper camel case (e.g. viewBox).
		 *
		 * HTML entities are not supported by this method,
		 * use unicode escaping or the unicode character to implement HTML entities.
		 * For further information see
		 * {@link https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references}.
		 *
		 * @param {string} sName Name of the attribute
		 * @param {*} vValue Value of the attribute
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.attr = function(sName, vValue) {
			assertValidAttr(sName);

			if (sName == "style") {
				aStyleStack[aStyleStack.length - 1].aStyle = [vValue];
			} else {
				aBuffer.push(" ", sName, "=\"", encodeXML(String(vValue)), "\"");
			}
			return this;
		};

		/**
		 * Adds a class name to the class collection of the last open HTML element.
		 *
		 * This is only valid when called between <code>openStart/voidStart</code> and <code>openEnd/voidEnd</code>.
		 * Class name must not contain any whitespace.
		 *
		 * @param {string} sClass Class name to be written
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.class = function(sClass) {
			if (sClass) {
				assertValidClass.apply(this, arguments);
				var oStyle = aStyleStack[aStyleStack.length - 1];
				if (!oStyle.aClasses) {
					oStyle.aClasses = [];
				}
				oStyle.aClasses.push(encodeXML(sClass));
			}
			return this;
		};

		/**
		 * Adds a style name-value pair to the style collection of the last open HTML element.
		 *
		 * This is only valid when called between <code>openStart/voidStart</code> and <code>openEnd/voidEnd</code>.
		 * To allow a more efficient DOM update, the CSS property names and values have to be used in their canonical form.
		 * In general, CSS properties are lower-cased in their canonical form, except for parts that are not under the control of CSS.
		 * For more information, see {@link https://www.w3.org/TR/CSS/#indices}.
		 *
		 * @param {string} sName Name of the style property
		 * @param {string|float|int} vValue Value of the style property
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 * @since 1.67
		 */
		this.style = function(sName, vValue) {
			assertValidStyle(sName);

			if (vValue != null && vValue != "") {
				assert((typeof vValue === "string" || typeof vValue === "number"), "value must be a string or number");
				var oStyle = aStyleStack[aStyleStack.length - 1];
				if (!oStyle.aStyle) {
					oStyle.aStyle = [];
				}
				oStyle.aStyle.push(sName + ": " + vValue + ";");
			}
			return this;
		};

		//#################################################################################################
		// Semantic Rendering Interface for DOM Based Rendering
		//#################################################################################################

		// @see sap.ui.core.RenderManager#openStart
		oDomInterface.openStart = function(sTagName, vControlOrId) {
			assertValidName(sTagName, "tag");
			assertOpenTagHasEnded();
			assert(!(sLastStyleMethod = sLastClassMethod = ""));
			sOpenTag = sTagName;
			iOpenTagCount++;

			if (!vControlOrId) {
				oPatcher.openStart(sTagName);
			} else if (typeof vControlOrId == "string") {
				oPatcher.openStart(sTagName, vControlOrId);
			} else {
				oPatcher.openStart(sTagName, vControlOrId.getId());
				renderElementData(this, vControlOrId);
			}

			return this;
		};

		// @see sap.ui.core.RenderManager#voidStart
		oDomInterface.voidStart = function(sTagName, vControlOrId) {
			this.openStart(sTagName, vControlOrId);

			bVoidOpen = true;
			return this;
		};

		// @see sap.ui.core.RenderManager#attr
		oDomInterface.attr = function(sName, vValue) {
			assertValidAttr(sName);
			assertOpenTagHasStarted("attr");

			oPatcher.attr(sName, vValue);
			return this;
		};

		// @see sap.ui.core.RenderManager#class
		oDomInterface.class = function(sClass) {
			if (sClass) {
				assertValidClass.apply(this, arguments);
				assertOpenTagHasStarted("class");

				oPatcher.class(sClass);
			}

			return this;
		};

		// @see sap.ui.core.RenderManager#style
		oDomInterface.style = function(sName, vValue) {
			assertValidStyle(sName);
			assertOpenTagHasStarted("style");

			oPatcher.style(sName, vValue);
			return this;
		};

		// @see sap.ui.core.RenderManager#openEnd
		oDomInterface.openEnd = function(bExludeStyleClasses /* private */) {
			if (bExludeStyleClasses !== true) {
				var oStyle = aStyleStack[aStyleStack.length - 1];
				var aStyleClasses = oStyle.aCustomStyleClasses;
				if (aStyleClasses) {
					aStyleClasses.forEach(oPatcher.class, oPatcher);
					oStyle.aCustomStyleClasses = null;
				}
			}

			assertOpenTagHasStarted("openEnd");
			assertOpenTagHasEnded(!bVoidOpen);
			assert(bExludeStyleClasses === undefined || bExludeStyleClasses === true, "The private parameter bExludeStyleClasses must be true or omitted!");
			sOpenTag = "";

			oPatcher.openEnd();
			return this;
		};

		// @see sap.ui.core.RenderManager#voidEnd
		oDomInterface.voidEnd = function(bExludeStyleClasses /* private */) {
			if (!bExludeStyleClasses) {
				var oStyle = aStyleStack[aStyleStack.length - 1];
				var aStyleClasses = oStyle.aCustomStyleClasses;
				if (aStyleClasses) {
					aStyleClasses.forEach(oPatcher.class, oPatcher);
					oStyle.aCustomStyleClasses = null;
				}
			}

			assertOpenTagHasStarted("voidEnd");
			assertOpenTagHasEnded(bVoidOpen || !sOpenTag);
			bVoidOpen = false;
			iOpenTagCount--;
			sOpenTag = "";

			oPatcher.voidEnd();
			return this;
		};

		// @see sap.ui.core.RenderManager#text
		oDomInterface.text = function(sText) {
			assertOpenTagHasEnded();

			if (sText != null) {
				oPatcher.text(sText);
			}

			return this;
		};

		// @see sap.ui.core.RenderManager#unsafeHtml
		oDomInterface.unsafeHtml = function(sHtml) {
			assertOpenTagHasEnded();

			oPatcher.unsafeHtml(sHtml);
			return this;
		};

		// @see sap.ui.core.RenderManager#close
		oDomInterface.close = function(sTagName) {
			assertValidName(sTagName, "tag");
			assertOpenTagHasEnded();
			iOpenTagCount--;

			oPatcher.close(sTagName);
			return this;
		};


		//Triggers the BeforeRendering event on the given Control
		function triggerBeforeRendering(oControl){
			bLocked = true;
			try {
				var oEvent = new jQuery.Event("BeforeRendering");
				// store the element on the event (aligned with jQuery syntax)
				oEvent.srcControl = oControl;
				oControl._bOnBeforeRenderingPhase = true;
				oControl._handleEvent(oEvent);
			} finally {
				oControl._bOnBeforeRenderingPhase = false;
				bLocked = false;
			}
		}

		/**
		 * Cleans up the rendering state of the given control without rendering it.
		 *
		 * A control is responsible for the rendering of all its child controls.
		 * But in some cases it makes sense that a control only renders a subset of its children
		 * based on some criterion. For example, a typical carousel control might, for performance
		 * reasons, only render the currently visible children (and maybe some child before and
		 * after the visible area to facilitate slide-in / slide-out animations), but not all children.
		 * This leads to situations where a child had been rendered before, but shouldn't be rendered
		 * anymore after an update of the carousel's position. The DOM related state of that child then
		 * must be cleaned up correctly, e.g. by de-registering resize handlers or native event handlers.
		 * <code>cleanupControlWithoutRendering</code> helps with that task by triggering the same
		 * activities that the normal rendering triggers before the rendering of a control
		 * (e.g. it fires the <code>BeforeRendering</code> event). It just doesn't call the renderer
		 * and the control will not receive an <code>AfterRendering</code> event.
		 *
		 * The following example shows how <code>renderControl</code> and <code>cleanupControlWithoutRendering</code>
		 * should be used:
		 *
		 * <pre>
		 *   CarouselRenderer.render = function(rm, oCarousel){
		 *
		 *     ...
		 *
		 *     oCarousel.getPages().forEach( function( oPage ) {
		 *        if ( oCarousel.isPageToBeRendered( oPage ) ) {
		 *           rm.renderControl( oPage ); // onBeforeRendering, render, later onAfterRendering
		 *        } else {
		 *           rm.cleanupControlWithoutRendering( oPage ); // onBeforeRendering
		 *        }
		 *     });
		 *
		 *     ...
		 *
		 *   };
		 * </pre>
		 *
		 * <h3>DOM Removal</h3>
		 * The method does not remove the DOM of the given control. The caller of this method has
		 * to take care to remove it at some later point in time. It should indeed be <i>later</i>,
		 * not <i>before</i> as the <code>onBeforeRendering</code> hook of the control might need
		 * access to the old DOM for a proper cleanup.
		 *
		 * For parents which are rendered with the normal mechanism as shown in the example above,
		 * the removal of the old child DOM is guaranteed. The whole DOM of the parent control
		 * (including the DOM of the no longer rendered child) will be replaced with new DOM (no
		 * longer containing the child) when the rendering cycle finishes.
		 *
		 * <b>Note:</b>: the functionality of this method is different from the default handling for
		 * invisible controls (controls with <code>visible == false</code>). The standard rendering
		 * for invisible controls still renders a placeholder DOM. This allows rerendering of the
		 * invisible control once it becomes visible again without a need to render its parent, too.
		 * Children that are cleaned up with this method here, are supposed to have no more DOM at all.
		 * Rendering them later on therefore requires an involvement (typically: a rendering) of
		 * their parent.
		 *
		 * @param {sap.ui.core.Control} oControl Control that should be cleaned up
		 * @public
		 * @since 1.22.9
		 */
		this.cleanupControlWithoutRendering = function(oControl) {
			assert(!oControl || BaseObject.isObjectA(oControl, 'sap.ui.core.Control'), "oControl must be an sap.ui.core.Control or empty");
			if (!oControl) {
				return;
			}

			var oDomRef = oControl.getDomRef();
			if (oDomRef) {

				// Call beforeRendering to allow cleanup
				triggerBeforeRendering(oControl);

				// as children are not visited during rendering, their DOM has to be preserved here
				RenderManager.preserveContent(oDomRef, /* bPreserveRoot */ false, /* bPreserveNodesWithId */ false);

				// Preserved controls still need to be alive
				if (!oDomRef.hasAttribute(ATTR_PRESERVE_MARKER)) {
					oControl._bNeedsRendering = false;
					oControl.bOutput = false;
				}
			}
		};

		/**
		 * Executes the control renderer with the valid rendering interface.
		 *
		 * @param {sap.ui.core.Control} oControl The control that should be rendered
		 * @param {boolean} bTriggerEvent Whether onBeforeRendering event should be triggered or not
		 * @private
		 */
		function executeRenderer(oControl, bTriggerEvent) {
			// trigger onBeforeRendering hook of the control if needed
			if (bTriggerEvent) {
				triggerBeforeRendering(oControl);
			}

			// unbind any generically bound browser event handlers
			if (oControl.bOutput == true) {
				var aBindings = oControl.aBindParameters;
				if (aBindings && aBindings.length > 0) {
					var $Control = oControl.$();
					aBindings.forEach(function(mParams) {
						$Control.off(mParams.sEventType, mParams.fnProxy);
					});
				}
			}

			// if the control uses default visible property then use the InvisibleRenderer, otherwise the renderer of the control
			var oRenderer = getCurrentRenderer(oControl);
			if (oRenderer == InvisibleRenderer) {

				// invoke the InvisibleRenderer in case the control uses the default visible property
				InvisibleRenderer.render(bDomInterface ? oDomInterface : oStringInterface, oControl);

				// if an invisible placeholder was rendered, mark with invisible marker
				oControl.bOutput = "invisible";

			} else if (oRenderer && typeof oRenderer.render === "function") {

				// before the control rendering get custom style classes of the control
				var oControlStyles = {};
				if (oControl.aCustomStyleClasses && oControl.aCustomStyleClasses.length > 0) {
					oControlStyles.aCustomStyleClasses = oControl.aCustomStyleClasses;
				}

				// push them to the style stack that will be read by the first writeClasses/openEnd/voidEnd call to append additional classes
				aStyleStack.push(oControlStyles);

				// mark that the rendering phase has been started
				oControl._bRenderingPhase = true;

				// execute the control renderer according to rendering interface
				if (bDomInterface) {

					// remember the cursor of the Patcher before the control renderer is executed
					var oCurrentNode = oPatcher.getCurrentNode();

					// let the rendering happen with DOM rendering interface
					oRenderer.render(oDomInterface, oControl);

					// determine whether an output is produced
					if (oPatcher.getCurrentNode() == oCurrentNode) {

						// during the rendering the cursor of the Patcher should move to the next element when openStart or voidStart is called
						// compare after rendering cursor with before rendering cursor to determine whether the control produced any output
						// we need to remove the control DOM if there is no output produced
						oPatcher.unsafeHtml("", oControl.getId());
						oControl.bOutput = false;

					} else {

						// the cursor of the patcher is moved so the output is produced
						oControl.bOutput = true;
					}

				} else {

					// remember the buffer size before the control renderer is executed
					var iBufferLength = aBuffer.length;

					// let the rendering happen with DOM rendering interface
					oRenderer.render(oStringInterface, oControl);

					// compare after rendering buffer size with the before rendering buffer size to determine whether the control produced any output
					oControl.bOutput = (aBuffer.length != iBufferLength);
				}

				// mark that the rendering phase is over
				oControl._bRenderingPhase = false;

				// pop from the style stack after rendering for the next control
				aStyleStack.pop();

			} else {
				Log.error("The renderer for class " + oControl.getMetadata().getName() + " is not defined or does not define a render function! Rendering of " + oControl.getId() + " will be skipped!");
			}

			// store the rendered control
			aRenderedControls.push(oControl);

			// clear the controls dirty marker
			oControl._bNeedsRendering = false;

			// let the UIArea know that this control has been rendered
			var oUIArea = oControl.getUIArea();
			if (oUIArea) {
				oUIArea._onControlRendered(oControl);
			}
		}

		/**
		 * Turns the given control into its HTML representation and appends it to the
		 * rendering buffer.
		 *
		 * If the given control is undefined or null, then nothing is rendered.
		 *
		 * @param {sap.ui.core.Control} oControl the control that should be rendered
		 * @returns {this} Reference to <code>this</code> in order to allow method chaining
		 * @public
		 */
		this.renderControl = function(oControl) {
			assert(!oControl || BaseObject.isObjectA(oControl, 'sap.ui.core.Control'), "oControl must be an sap.ui.core.Control or empty");
			if (!oControl) {
				return this;
			}

			var oDomRef, oRenderer;
			var bTriggerBeforeRendering = true;

			// determine the rendering interface
			if (aBuffer.length) {

				// string rendering has been already started therefore we cannot use DOM rendering interface anymore
				bDomInterface = false;

			} else if (bDomInterface === undefined) {

				// trigger onBeforeRendering before checking the visibility, since the visible property might change in the event handler
				triggerBeforeRendering(oControl);

				// mark that onBeforeRendering event has been already triggered and yet another onBeforeRendering event is not necessary
				bTriggerBeforeRendering = false;

				// if the control uses the default visible property then use the InvisibleRenderer, otherwise the renderer of the control
				oRenderer = getCurrentRenderer(oControl);

				// rendering interface must be determined for the root control once per rendering
				if (RenderManager.getApiVersion(oRenderer) != 1) {

					// get the visible or invisible DOM element of the control
					oDomRef = oControl.getDomRef() || InvisibleRenderer.getDomRef(oControl);

					// If the control is in the preserved area then we should not use the DOM-based rendering to avoid patching of preserved nodes
					if (RenderManager.isPreservedContent(oDomRef)) {
						bDomInterface = false;
					} else {
						// patching will happen during the control renderer calls therefore we need to get the focus info before the patching
						oDomRef && FocusHandler.storePatchingControlFocusInfo(oDomRef);

						// set the starting point of the Patcher
						oPatcher.setRootNode(oDomRef);

						// remember that we are using DOM based rendering interface
						bDomInterface = true;
					}

				} else {

					// DOM rendering is not possible we fall back to string rendering interface
					bDomInterface = false;
				}

			} else if (!sLegacyRendererControlId && bDomInterface) {

				// if the control uses the default visible property then use the InvisibleRenderer, otherwise the renderer of the control
				oRenderer = getCurrentRenderer(oControl);

				// for every subsequent renderControl call we need to check whether we can continue with the DOM based rendering
				if (RenderManager.getApiVersion(oRenderer) == 1) {

					// remember the control id that we have to provide string rendering interface
					sLegacyRendererControlId = oControl.getId();
					bDomInterface = false;
				}
			}

			// execute the renderer of the control through the valid rendering interface
			if (bDomInterface) {

				// determine whether we should execute the control renderer with DOM rendering interface or whether we can skip the rendering of the control if it does not need rendering
				if (oControl._bNeedsRendering || !oControl.getParent() || oPatcher.isCreating() || !RenderManager.canSkipRendering(oControl)
					|| !(oDomRef = oDomRef || oControl.getDomRef() || InvisibleRenderer.getDomRef(oControl))
					|| oDomRef.hasAttribute(ATTR_DO_NOT_SKIP_RENDERING_MARKER) || oDomRef.querySelector("[" + ATTR_DO_NOT_SKIP_RENDERING_MARKER + "]")) {

					// let the rendering happen with DOM rendering interface
					executeRenderer(oControl, bTriggerBeforeRendering);

				} else {

					// skip the control rendering and re-arrange the cursor of the Patcher
					oPatcher.alignWithDom(oDomRef);
				}

			} else {

				// let the rendering happen with string rendering interface
				executeRenderer(oControl, bTriggerBeforeRendering);

				// at the end of the rendering apply the rendering buffer of the control that is forced to render string interface
				if (sLegacyRendererControlId && sLegacyRendererControlId === oControl.getId()) {
					oPatcher.unsafeHtml(aBuffer.join(""), sLegacyRendererControlId, restoreStyles);
					sLegacyRendererControlId = "";
					bDomInterface = true;
					aBuffer = [];
				}
			}

			return this;
		};

		/**
		 * Renders the given {@link sap.ui.core.Control} and finally returns
		 * the content of the rendering buffer.
		 * Ensures the buffer is restored to the state before calling this method.
		 *
		 * @param {sap.ui.core.Control}
		 *            oControl the Control whose HTML should be returned.
		 * @returns {string} the resulting HTML of the provided control
		 * @deprecated Since version 0.15.0. Use <code>flush()</code> instead render content outside the rendering phase.
		 * @public
		 */
		this.getHTML = function(oControl) {
			assert(oControl && BaseObject.isObjectA(oControl, 'sap.ui.core.Control'), "oControl must be an sap.ui.core.Control");

			var tmp = aBuffer;
			var aResult = aBuffer = this.aBuffer = [];
			this.renderControl(oControl);
			aBuffer = this.aBuffer = tmp;
			return aResult.join("");
		};

		//Does everything needed after the rendering (restore focus, calling "onAfterRendering", initialize event binding)
		function finalizeRendering(oStoredFocusInfo){

			assert(!iOpenTagCount, "RenderManager: Mismatched opening and closing tags. Verify renderers!");

			var i, size = aRenderedControls.length;

			for (i = 0; i < size; i++) {
				aRenderedControls[i]._sapui_bInAfterRenderingPhase = true;
			}
			bLocked = true;

			try {

				// Notify the behavior object that the controls will be attached to DOM
				for (i = 0; i < size; i++) {
					var oControl = aRenderedControls[i];
					if (oControl.bOutput && oControl.bOutput !== "invisible") {
						var oEvent = new jQuery.Event("AfterRendering");
						// store the element on the event (aligned with jQuery syntax)
						oEvent.srcControl = oControl;
						// start performance measurement
						Measurement.start(oControl.getId() + "---AfterRendering","AfterRendering of " + oControl.getMetadata().getName(), ["rendering","after"]);
						oControl._handleEvent(oEvent);
						// end performance measurement
						Measurement.end(oControl.getId() + "---AfterRendering");
					}
				}

			} finally {
				for (i = 0; i < size; i++) {
					delete aRenderedControls[i]._sapui_bInAfterRenderingPhase;
				}
				bLocked = false;
			}

			//finally restore focus
			try {
				FocusHandler.restoreFocus(oStoredFocusInfo);
			} catch (e) {
				Log.warning("Problems while restoring the focus after rendering: " + e, null);
			}

			// Re-bind any generically bound browser event handlers (must happen after restoring focus to avoid focus event)
			for (i = 0; i < size; i++) {
				var oControl = aRenderedControls[i],
					aBindings = oControl.aBindParameters,
					oDomRef;

				// if we have stored bind calls and we have a DomRef
				if (aBindings && aBindings.length > 0 && (oDomRef = oControl.getDomRef())) {
					var $DomRef = jQuery(oDomRef);
					for (var j = 0; j < aBindings.length; j++) {
						var oParams = aBindings[j];
						$DomRef.on(oParams.sEventType, oParams.fnProxy);
					}
				}
			}
		}

		function flushInternal(fnPutIntoDom, fnDone, oTargetDomNode) {

			var oStoredFocusInfo;
			if (!bDomInterface) {
				// DOM-based rendering was not possible we are in the string-based initial rendering or re-rendering phase
				oStoredFocusInfo = FocusHandler.getControlFocusInfo();
				var sHtml = aBuffer.join("");
				if (sHtml && aRenderingStyles.length) {
					// During the string-based rendering, RM#writeStyles method is not writing the styles into the HTML buffer due to possible CSP restrictions.
					// Instead, we store the styles in the aRenderingStyles array and add an ATTR_STYLE_KEY_MARKER attribute marker for which the value
					// references the original style index in this array.
					// Not to violate the CSP, we need to bring the original styles via HTMLElement.style API. Here we are converting the HTML buffer of
					// string-based rendering to DOM nodes so that we can restore the orginal styles before we inject the rendering output to the DOM tree.
					if (oTargetDomNode instanceof SVGElement && oTargetDomNode.localName != "foreignObject") {
						oTemplate.innerHTML = "<svg>" + sHtml + "</svg>";
						oTemplate.replaceWith.apply(oTemplate.content.firstChild, oTemplate.content.firstChild.childNodes);
					} else {
						oTemplate.innerHTML = sHtml;
					}

					restoreStyles(oTemplate.content.childNodes);
					fnPutIntoDom(oTemplate.content);
				} else {
					fnPutIntoDom(sHtml);
				}
			} else {
				// get the root node of the Patcher to determine whether we are in the initial rendering or the re-rendering phase
				var oRootNode = oPatcher.getRootNode();

				// in case of DOM-based initial rendering, the Patcher creates a DocumentFragment to assemble all created control DOM nodes within it
				if (oRootNode.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) {
					// even though we are in the initial rendering phase a control within the control tree might has been already rendered before
					// therefore we need to store the currectly focused control info before we inject the DocumentFragment into the real DOM tree
					oStoredFocusInfo = FocusHandler.getControlFocusInfo();

					// controls are not necessarily need to produce output during their rendering
					// in case of output is produced, let the callback injects the DocumentFragment
					fnPutIntoDom(oRootNode.lastChild ? oRootNode : "");
				} else {
					// in case of DOM-based re-rendering, the root node of the Patcher must be an existing HTMLElement
					// since the re-rendering happens during the control renderer APIs are executed here we get the stored focus info before the patching
					oStoredFocusInfo = FocusHandler.getPatchingControlFocusInfo();
				}

				// make the Patcher ready for the next patching
				oPatcher.reset();
			}

			finalizeRendering(oStoredFocusInfo);

			reset();

			ActivityDetection.refresh();

			if (fnDone) {
				fnDone();
			}
		}

		function restoreStyle(oElement, iDomIndex) {
			var sStyleIndex = oElement.getAttribute(ATTR_STYLE_KEY_MARKER);
			if (sStyleIndex != iDomIndex) {
				return 0;
			}

			oElement.style = aRenderingStyles[iDomIndex];
			oElement.removeAttribute(ATTR_STYLE_KEY_MARKER);
			return 1;
		}

		function restoreStyles(aDomNodes) {
			if (!aRenderingStyles.length) {
				return;
			}

			var iDomIndex = 0;
			aDomNodes.forEach(function(oDomNode) {
				if (oDomNode.nodeType == 1 /* Node.ELEMENT_NODE */) {
					iDomIndex += restoreStyle(oDomNode, iDomIndex);
					oDomNode.querySelectorAll("[" + ATTR_STYLE_KEY_MARKER + "]").forEach(function(oElement) {
						iDomIndex += restoreStyle(oElement, iDomIndex);
					});
				}
			});
			aRenderingStyles = [];
		}

		/**
		 * Renders the content of the rendering buffer into the provided DOM node.
		 *
		 * This function must not be called within control renderers.
		 *
		 * Usage:
		 * <pre>
		 *
		 *   // Create a new instance of the RenderManager
		 *   var rm = sap.ui.getCore().createRenderManager();
		 *
		 *   // Use the writer API to fill the buffers
		 *   rm.write(...);
		 *   rm.renderControl(oControl);
		 *   rm.write(...);
		 *   ...
		 *
		 *   // Finally flush the buffer into the provided DOM node (The current content is removed)
		 *   rm.flush(oDomNode);
		 *
		 *   // If the instance is not needed anymore, destroy it
		 *   rm.destroy();
		 *
		 * </pre>
		 *
		 * @param {Element} oTargetDomNode Node in the DOM where the buffer should be flushed into
		 * @param {boolean} bDoNotPreserve Determines whether the content is preserved (<code>false</code>) or not (<code>true</code>)
		 * @param {boolean|int} vInsert Determines whether the buffer of the target DOM node is expanded (<code>true</code>) or
		 *                  replaced (<code>false</code>), or the new entry is inserted at a specific position
		 *                  (value of type <code>int</code>)
		 * @public
		 */
		this.flush = function(oTargetDomNode, bDoNotPreserve, vInsert) {
			assert((typeof oTargetDomNode === "object") && (oTargetDomNode.ownerDocument == document), "oTargetDomNode must be a DOM element");

			var fnDone = Interaction.notifyAsyncStep();

			// preserve HTML content before flushing HTML into target DOM node
			if (!bDoNotPreserve && (typeof vInsert !== "number") && !vInsert) { // expression mimics the conditions used below
				RenderManager.preserveContent(oTargetDomNode);
			}

			flushInternal(function(vHTML) {

				for (var i = 0; i < aRenderedControls.length; i++) {
					//TODO It would be enough to loop over the controls for which renderControl was initially called but for this
					//we have to manage an additional array. Rethink about later.
					var oldDomNode = aRenderedControls[i].getDomRef();
					if (oldDomNode && !RenderManager.isPreservedContent(oldDomNode)) {
						if (RenderManager.isInlineTemplate(oldDomNode)) {
							jQuery(oldDomNode).empty();
						} else {
							jQuery(oldDomNode).remove();
						}
					}
				}
				if (typeof vInsert === "number") {
					if (vInsert <= 0) { // new HTML should be inserted at the beginning
						insertAdjacent(oTargetDomNode, "prepend", vHTML);
					} else { // new element should be inserted at a certain position > 0
						var oPredecessor = oTargetDomNode.children[vInsert - 1]; // find the element which should be directly before the new one
						if (oPredecessor) {
							// element found - put the HTML in after this element
							insertAdjacent(oPredecessor, "after", vHTML);
						} else {
							// element not found (this should not happen when properly used), append the new HTML
							insertAdjacent(oTargetDomNode, "append", vHTML);
						}
					}
				} else if (!vInsert) {
					jQuery(oTargetDomNode).html(vHTML); // Put the HTML into the given DOM Node
				} else {
					insertAdjacent(oTargetDomNode, "append", vHTML); // Append the HTML into the given DOM Node
				}

			}, fnDone, oTargetDomNode);

		};

		/**
		 * Renders the given control to the provided DOMNode.
		 *
		 * If the control is already rendered in the provided DOMNode the DOM of the control is replaced. If the control
		 * is already rendered somewhere else the current DOM of the control is removed and the new DOM is appended
		 * to the provided DOMNode.
		 *
		 * This function must not be called within control renderers.
		 *
		 * @param {sap.ui.core.Control} oControl the Control that should be rendered.
		 * @param {Element} oTargetDomNode The node in the DOM where the result of the rendering should be inserted.
		 * @public
		 */
		this.render = function(oControl, oTargetDomNode) {
			assert(oControl && BaseObject.isObjectA(oControl, 'sap.ui.core.Control'), "oControl must be a control");
			assert(typeof oTargetDomNode === "object" && oTargetDomNode.ownerDocument == document, "oTargetDomNode must be a DOM element");
			if ( bLocked ) {
				Log.error("Render must not be called within Before or After Rendering Phase. Call ignored.", null, this);
				return;
			}

			var fnDone = Interaction.notifyAsyncStep();

			// Reset internal state before rendering
			reset();

			// Retrieve the markup (the rendering phase)
			this.renderControl(oControl);

			// FIXME: MULTIPLE ROOTS
			// The implementation of this method doesn't support multiple roots for a control.
			// Affects all places where 'oldDomNode' is used
			flushInternal(function(vHTML) {

				if (oControl && oTargetDomNode) {

					var oldDomNode = oControl.getDomRef();
					if ( !oldDomNode || RenderManager.isPreservedContent(oldDomNode) ) {
						// In case no old DOM node was found or only preserved DOM, search for a placeholder (invisible or preserved DOM placeholder)
						oldDomNode = InvisibleRenderer.getDomRef(oControl) || document.getElementById(RenderPrefixes.Dummy + oControl.getId());
					}

					var bNewTarget = oldDomNode && oldDomNode.parentNode != oTargetDomNode;

					if (bNewTarget) { //Control was rendered already and is now moved to different location

						if (!RenderManager.isPreservedContent(oldDomNode)) {
							if (RenderManager.isInlineTemplate(oldDomNode)) {
								jQuery(oldDomNode).empty();
							} else {
								jQuery(oldDomNode).remove();
							}
						}

						if (vHTML) {
							insertAdjacent(oTargetDomNode, "append", vHTML);
						}

					} else { //Control either rendered initially or rerendered at the same location

						if (vHTML) {
							if (oldDomNode) {
								if (RenderManager.isInlineTemplate(oldDomNode)) {
									jQuery(oldDomNode).html(vHTML);
								} else {
									insertAdjacent(oldDomNode, "after", vHTML);
									jQuery(oldDomNode).remove();
								}
							} else {
								insertAdjacent(oTargetDomNode, "append", vHTML);
							}
						} else {
							if (RenderManager.isInlineTemplate(oldDomNode)) {
								jQuery(oldDomNode).empty();
							} else {
								// give parent control a chance to handle emptied children properly (e.g. XMLView)
								if ( !oControl.getParent()
										 || !oControl.getParent()._onChildRerenderedEmpty
										 || !oControl.getParent()._onChildRerenderedEmpty(oControl, oldDomNode) ) {
									jQuery(oldDomNode).remove();
								}
							}

						}

					}

				}
			}, fnDone, oTargetDomNode);
		};

		/**
		 * Cleans up the resources associated with this instance.
		 *
		 * After the instance has been destroyed, it must not be used anymore.
		 * Applications should call this function if they don't need the instance any longer.
		 *
		 * @public
		 */
		this.destroy = function() {
			reset();
		};

		//#################################################################################################
		// Build up interfaces that can be used by Renderers
		//#################################################################################################

		var oInterface = {};
		aCommonMethods.forEach(function (sMethod) {
			oStringInterface[sMethod] = oDomInterface[sMethod] = oInterface[sMethod] = this[sMethod];
		}, this);
		aDomInterfaceMethods.forEach(function (sMethod) {
			oStringInterface[sMethod] = oInterface[sMethod] = this[sMethod];
		}, this);
		/**
		 * @deprecated As of version 1.92, the string rendering methods are deprecated
		 */
		aStrInterfaceMethods.forEach(function (sMethod) {
			oStringInterface[sMethod] = oInterface[sMethod] = this[sMethod];
		}, this);
		aNonRendererMethods.forEach(function (sMethod) {
			oInterface[sMethod] = this[sMethod];
		}, this);

		/**
		 * Returns the public interface of the RenderManager which can be used by Renderers.
		 *
		 * @returns {sap.ui.base.Interface} the interface
		 * @private
		 */
		this.getRendererInterface = function() {
			return oStringInterface;
		};

		this.getInterface = function() {
			return oInterface;
		};

		reset();
	}
Creates an instance of the RenderManager.

Applications or controls must not call the <code>RenderManager</code> constructor on their own
but should rely on the re-rendering initiated by the framework lifecycle based on invalidation.
See {@link module:sap/ui/core/Element#invalidate} and {@link module:sap/ui/core/Control#invalidate}.

@class A class that handles the rendering of controls.

For the default rendering task of UI5, a shared RenderManager is created and owned by <code>sap.ui.core.Core</code>.
Controls or other code that want to render controls outside the default rendering task
can create a private instance of RenderManager by calling the
{@link sap.ui.core.Core#createRenderManager sap.ui.getCore().createRenderManager()} method.
When such a private instance is no longer needed, it should be {@link #destroy destroyed}.

Control renderers only have access to a subset of the public and protected instance methods of
this class. The instance methods {@link #flush}, {@link #render} and {@link #destroy} are not part
of that subset and are reserved to the owner of the corresponding RenderManager instance.
Renderers will use the provided methods to create their HTML output. The RenderManager will
collect the HTML output and inject the final HTML DOM at the desired location.


<h3>Renderers</h3>
When the {@link #renderControl} method of the RenderManager is invoked, it will retrieve
the default renderer for that control. By convention, the default renderer is implemented in its
own namespace (static class) which matches the name of the control's class with the additional
suffix 'Renderer'. So for a control <code>sap.m.Input</code> the default renderer will be searched
for under the global name <code>sap.m.Input<i>Renderer</i></code>.

<h3>Semantic Rendering</h3>
As of 1.67, <code>RenderManager</code> provides a set of new APIs to describe the structure of the DOM that can be used by the control renderers.

<pre>

  myButtonRenderer.render = function(rm, oButton) {

      rm.openStart("button", oButton);
      rm.attr("tabindex", 1);
      rm.class("myButton");
      rm.style("width", oButton.getWidth());
      rm.openEnd();
          rm.text(oButton.getText());
      rm.close("button");

  };

</pre>

By default, when the control is invalidated (e.g. a property is changed, an aggregation is removed, or an
association is added), it will be registered for rerendering. During the (re)rendering, the <code>render</code>
method of the control renderer is executed via a specified <code>RenderManager</code> interface and the control
instance.

Traditional string-based rendering creates a new HTML structure of the control in every rendering cycle and removes
the existing control DOM structure from the DOM tree.

The set of new semantic <code>RenderManager</code> APIs lets us understand the structure of the DOM, walk along the
live DOM tree, and figure out changes as new APIs are called. If there is a change, then <code>RenderManager</code>
patches only the required parts of the live DOM tree. This allows control developers to remove their DOM-related
custom setters.

<b>Note:</b> To enable the new in-place rendering technology, the <code>apiVersion</code> property of the control
renderer must be set to <code>2</code>. This property is not inherited by subclass renderers. It has to be set
anew by each subclass to assure that the extended contract between framework and renderer is fulfilled (see next
paragraph).

<pre>

  var myButtonRenderer = {
      apiVersion: 2    // enable semantic rendering
  };

  myButtonRenderer.render = function(rm, oButton) {

      rm.openStart("button", oButton);
      ...
      ...
      rm.close("button");

  };

</pre>

<h3>Contract for Renderer.apiVersion 2</h3>
To allow a more efficient in-place DOM patching and to ensure the compatibility of the control, the following
prerequisites must be fulfilled for the controls using the new rendering technology:

<ul>
<li>Legacy control renderers must be migrated to the new semantic renderer API:
    {@link sap.ui.core.RenderManager#openStart openStart},
    {@link sap.ui.core.RenderManager#voidStart voidStart},
    {@link sap.ui.core.RenderManager#style style},
    {@link sap.ui.core.RenderManager#class class},
    {@link sap.ui.core.RenderManager#attr attr},
    {@link sap.ui.core.RenderManager#openEnd openEnd},
    {@link sap.ui.core.RenderManager#voidEnd voidEnd},
    {@link sap.ui.core.RenderManager#text text},
    {@link sap.ui.core.RenderManager#unsafeHtml unsafeHtml},
    {@link sap.ui.core.RenderManager#icon icon},
    {@link sap.ui.core.RenderManager#accessibilityState accessibilityState},
    {@link sap.ui.core.RenderManager#renderControl renderControl},
    {@link sap.ui.core.RenderManager#cleanupControlWithoutRendering cleanupControlWithoutRendering}
</li>
<li>During the migration, restrictions that are defined in the API documentation of those methods must be taken
    into account, e.g. tag and attribute names must be set in their canonical form.</li>
<li>Fault tolerance of HTML5 markup is not applicable for the new semantic rendering API, e.g. except void tags,
    all tags must be closed; duplicate attributes within one HTML element must not exist.</li>
<li>Existing control DOM structure will not be removed from the DOM tree; therefore all custom events, including
    the ones that are registered with jQuery, must be de-registered correctly at the <code>onBeforeRendering</code>
    and <code>exit</code> hooks.</li>
<li>Classes and attribute names must not be escaped.</li>
<li>Styles should be validated via types (e.g. <code>sap.ui.core.CSSSize</code>). But this might not be sufficient
    in all cases, e.g. validated URL values can contain harmful content; in this case
    {@link module:sap/base/security/encodeCSS encodeCSS} can be used.</li>
<li>To allow a more efficient DOM update, second parameter of the {@link sap.ui.core.RenderManager#openStart openStart}
    or {@link sap.ui.core.RenderManager#voidStart voidStart} methods must be used to identify elements, e.g. use
    <code>rm.openStart("div", oControl.getId() + "-suffix");</code> instead of
    <code>rm.openStart("div").attr("id", oControl.getId() + "-suffix");</code></li>
<li>Controls that listen to the <code>focusin</code> event must double check their focus handling. Since DOM nodes
    are not removed and only reused, the <code>focusin</code> event might not be fired during rerendering.</li>
</ul>

<h3>Contract for Renderer.apiVersion 4</h3>
The <code>apiVersion 4</code> marker of the control renderer lets the <code>RenderManager</code> know if a control's output is not affected by changes in the parent control.
By default, if a property, an aggregation, or an association of a control is changed, then the control gets invalidated, and the rerendering process for that control and all of its
children starts. That means child controls rerender together with their parent even though there is no DOM update necessary. If a control's output is only affected by its own
properties, aggregations, or associations, then the <code>apiVersion 4</code> marker can help to reuse the control's DOM output and prevent child controls from rerendering unnecessarily
while they are getting rendered by their parent. This can help to improve performance by reducing the number of re-renderings.<br>
For example: A control called "ParentControl" has a child control called "ChildControl". ChildControl has its own properties, aggregations, and associations, and its output is only affected by them.
The <code>apiVersion 4</code> marker is set in the renderer of ChildControl. Whenever a property of the ParentControl is changed during the re-rendering process, the <code>RenderManager</code>
will check the <code>apiVersion</code> marker of the ChildControl's renderer, and if it's 4, the <code>RenderManager</code> will skip rendering of the ChildControl.<br>

To allow a more efficient rerendering with an <code>apiVersion 4</code> marker, the following prerequisites must be fulfilled for the control to ensure compatibility:

<ul>
<li>All the prerequisites of the <code>apiVersion 2</code> marker must be fulfilled by the control.</li>
<li>The behavior and rendering logic of the control must not rely on the assumption that it will always be re-rendered at the same time as its parent.</li>
<li>The <code>onBeforeRendering</code> and <code>onAfterRendering</code> hooks of the control must not be used to manipulate or access any elements outside of the control's own DOM structure.</li>
<li>The control renderer must maintain a proper rendering encapsulation and render only the properties, aggregations, and associations that are specific to the control. The renderer should not reference or depend on any state of the parent control or any other external element.</li>
<li>If certain aggregations are dependent on the state of the parent control, they must always be rendered together with their parent. To accomplish this, the parent control must use the {@link sap.ui.core.Control#invalidate invalidate} method to signal to the child controls
that they need to re-render whenever the dependent state of the parent control changes. This guarantees that the child controls are always in sync with the parent control, regardless of the <code>apiVersion</code> definition of their renderer.</li>
</ul><br>

<b>Note:</b> The rendering can only be skipped if the renderer of each descendant control has the <code>apiVersion 4</code> marker, and no <code>onBeforeRendering</code> or <code>onAfterRendering</code> event delegates are registered. However, while
{@link sap.ui.core.Element#addEventDelegate adding the event delegate}, setting the <code>canSkipRendering</code> property to <code>true</code> on the event delegate object can be done to indicate that those delegate handlers are compliant with the
<code>apiVersion:4</code> prerequisites and still allows for rendering optimization.<br>
The <code>canSkipRendering</code> property can also be used for the controls that enhance the accessibility state of child controls with implementing the {@link sap.ui.core.Element#enhanceAccessibilityState enhanceAccessibilityState} method. In this case,
setting the <code>canSkipRendering</code> property to <code>true</code> lets the <code>RenderManager</code> know that the parent control's accessibility enhancement is static and does not interfere with the child control's rendering optimization.

@see sap.ui.core.Core
@see sap.ui.getCore

@extends Object
@author SAP SE
@version ${version}
@alias sap.ui.core.RenderManager
@hideconstructor
@public