Index: src/main/java/com/xpn/xwiki/render/XWikiVelocityRenderer.java =================================================================== --- src/main/java/com/xpn/xwiki/render/XWikiVelocityRenderer.java (revision 25396) +++ src/main/java/com/xpn/xwiki/render/XWikiVelocityRenderer.java (working copy) @@ -59,6 +59,10 @@ */ public String render(String content, XWikiDocument contentdoc, XWikiDocument contextdoc, XWikiContext context) { + if (!mayRequireEvaluation(content)) { + return content; + } + VelocityManager velocityManager = (VelocityManager) Utils.getComponent(VelocityManager.class); VelocityContext vcontext = velocityManager.getVelocityContext(); Document previousdoc = (Document) vcontext.get("doc"); @@ -89,6 +93,17 @@ } } } + + /** + * A string may require evalution only if it contains '$' or '#', + * otherwise it's just a plain text + * + * @param content string to analyze + * @return true if content may require evalution, false otherwise + */ + private boolean mayRequireEvaluation(String content) { + return StringUtils.containsAny(content, "$#"); + } /** * {@inheritDoc} Index: src/main/java/com/xpn/xwiki/render/XWikiMacrosMappingRenderer.java =================================================================== --- src/main/java/com/xpn/xwiki/render/XWikiMacrosMappingRenderer.java (revision 25396) +++ src/main/java/com/xpn/xwiki/render/XWikiMacrosMappingRenderer.java (working copy) @@ -149,6 +149,10 @@ */ public String render(String content, XWikiDocument contentdoc, XWikiDocument doc, XWikiContext context) { + if (!mayContainMacros(content)) { + return content; + } + if (this.macros_libraries == null) { loadPreferences(context.getWiki(), context); } @@ -159,6 +163,39 @@ return content; } + /** + * A string may contain macros only if it contains + * '{' that is not preceded by '$', '#' or "$!" + * + * @param content string to analyze + * @return true if content may contain macros, false otherwise + */ + private boolean mayContainMacros(String content) { + if (StringUtils.isEmpty(content)) { + return false; + } + // content not empty --> it has at least one character + if (content.charAt(0) == '{') { + return true; + } + + int idx = 0; + // find next '{' + while ((idx=content.indexOf('{', idx+1)) != -1) { + // is '$' or '#' before '{' ? + if (content.charAt(idx-1) != '$' && content.charAt(idx-1) != '#') { + // no, is "$!" before "{" ? + if (idx >= 2) { + if (content.charAt(idx-2) != '$' || content.charAt(idx-1) != '!') { + // no + return true; // otherwise continue while + } + } + } + } + return false; + } + private String convertSingleLines(String content, XWikiContext context) { StringBuffer result = new StringBuffer(); Index: src/main/java/com/xpn/xwiki/render/DefaultXWikiRenderingEngine.java =================================================================== --- src/main/java/com/xpn/xwiki/render/DefaultXWikiRenderingEngine.java (revision 25396) +++ src/main/java/com/xpn/xwiki/render/DefaultXWikiRenderingEngine.java (working copy) @@ -28,6 +28,7 @@ import java.util.LinkedList; import java.util.List; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xwiki.cache.Cache; @@ -205,6 +206,12 @@ private String renderText(String text, boolean onlyInterpret, XWikiDocument contentdoc, XWikiDocument includingdoc, XWikiContext context) { + // performance optimization: if text doesn't contain special characters + // then it's just a plain text --> no processing required + if (StringUtils.containsNone(text, "#${")) { + return text; + } + String key = getKey(text, contentdoc, includingdoc, context); int currentCacheDuration = context.getCacheDuration(); Index: src/main/java/com/xpn/xwiki/doc/XWikiDocument.java =================================================================== --- src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (revision 25396) +++ src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (working copy) @@ -147,6 +147,8 @@ /** The default wiki name to use when one isn't specified. */ private static final String DEFAULT_WIKI_NAME = "xwiki"; + private static final String HTML_SPECIAL_CHARS = "<>&'\""; + /** * Regex Pattern to recognize if there's HTML code in a XWiki page. */ @@ -839,6 +841,11 @@ if (!StringUtils.isEmpty(title)) { title = context.getWiki().getRenderingEngine().interpretText(title, this, context); + if (Syntax.PLAIN_1_0.equals(outputSyntax) && StringUtils.containsNone(title, HTML_SPECIAL_CHARS)) { + // title is already in plain text --> no syntax conversion required + return title; + } + if (!outputSyntax.equals(Syntax.HTML_4_01) && !outputSyntax.equals(Syntax.XHTML_1_0)) { XDOM xdom = parseContent(Syntax.HTML_4_01.toIdString(), title); this.parserUtils.removeTopLevelParagraph(xdom.getChildren());