← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Render.pm
StatementsExecuted 6988 statements in 31.0ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
51113.6ms50.1msFoswiki::Render::::getRenderedVersionFoswiki::Render::getRenderedVersion
35713.26ms3.40msFoswiki::Render::::_takeOutProtectedFoswiki::Render::_takeOutProtected
22111.09ms1.60msFoswiki::Render::::_escapeAutoLinksFoswiki::Render::_escapeAutoLinks
611988µs1.88msFoswiki::Render::::forEachLineFoswiki::Render::forEachLine
21831924µs924µsFoswiki::Render::::_addListItemFoswiki::Render::_addListItem
2211817µs7.51msFoswiki::Render::::_handleSquareBracketedLinkFoswiki::Render::_handleSquareBracketedLink
111807µs884µsFoswiki::Render::::BEGIN@21Foswiki::Render::BEGIN@21
511666µs666µsFoswiki::Render::::_adjustHFoswiki::Render::_adjustH
3571636µs636µsFoswiki::Render::::_putBackProtectedFoswiki::Render::_putBackProtected
1811468µs4.76msFoswiki::Render::::internalLinkFoswiki::Render::internalLink
1811429µs2.63msFoswiki::Render::::_renderExistingWikiWordFoswiki::Render::_renderExistingWikiWord
311231µs48.0msFoswiki::Render::::renderRevisionInfoFoswiki::Render::renderRevisionInfo
1811188µs4.14msFoswiki::Render::::_renderWikiWordFoswiki::Render::_renderWikiWord
3211138µs138µsFoswiki::Render::::_replaceBlockFoswiki::Render::_replaceBlock
221196µs96µsFoswiki::Render::::_isImageLinkFoswiki::Render::_isImageLink
51155µs84µsFoswiki::Render::::getAnchorNamesFoswiki::Render::getAnchorNames
41134µs34µsFoswiki::Render::::_externalLinkFoswiki::Render::_externalLink
11118µs21µsFoswiki::Render::::BEGIN@845Foswiki::Render::BEGIN@845
11114µs26µsFoswiki::Render::::BEGIN@12Foswiki::Render::BEGIN@12
11112µs15µsFoswiki::Render::::BEGIN@847Foswiki::Render::BEGIN@847
11110µs37µsFoswiki::Render::::BEGIN@14Foswiki::Render::BEGIN@14
11110µs10µsFoswiki::Render::::newFoswiki::Render::new
11110µs46µsFoswiki::Render::::BEGIN@70Foswiki::Render::BEGIN@70
1119µs13µsFoswiki::Render::::BEGIN@13Foswiki::Render::BEGIN@13
1119µs116µsFoswiki::Render::::BEGIN@15Foswiki::Render::BEGIN@15
1115µs5µsFoswiki::Render::::finishFoswiki::Render::finish
1114µs4µsFoswiki::Render::::BEGIN@23Foswiki::Render::BEGIN@23
1114µs4µsFoswiki::Render::::BEGIN@20Foswiki::Render::BEGIN@20
1114µs4µsFoswiki::Render::::BEGIN@16Foswiki::Render::BEGIN@16
1113µs3µsFoswiki::Render::::BEGIN@18Foswiki::Render::BEGIN@18
1113µs3µsFoswiki::Render::::BEGIN@19Foswiki::Render::BEGIN@19
0000s0sFoswiki::Render::::TML2PlainTextFoswiki::Render::TML2PlainText
0000s0sFoswiki::Render::::_addTHEADandTFOOTFoswiki::Render::_addTHEADandTFOOT
0000s0sFoswiki::Render::::_capFoswiki::Render::_cap
0000s0sFoswiki::Render::::_emitTRFoswiki::Render::_emitTR
0000s0sFoswiki::Render::::_escapeMailAddressFoswiki::Render::_escapeMailAddress
0000s0sFoswiki::Render::::_fixedFontTextFoswiki::Render::_fixedFontText
0000s0sFoswiki::Render::::_handleWikiWordFoswiki::Render::_handleWikiWord
0000s0sFoswiki::Render::::_mailLinkFoswiki::Render::_mailLink
0000s0sFoswiki::Render::::_makeAnchorHeadingFoswiki::Render::_makeAnchorHeading
0000s0sFoswiki::Render::::_newLinkFormatFoswiki::Render::_newLinkFormat
0000s0sFoswiki::Render::::_renderNonExistingWikiWordFoswiki::Render::_renderNonExistingWikiWord
0000s0sFoswiki::Render::::breakNameFoswiki::Render::breakName
0000s0sFoswiki::Render::::htmlFoswiki::Render::html
0000s0sFoswiki::Render::::makeTopicSummaryFoswiki::Render::makeTopicSummary
0000s0sFoswiki::Render::::protectFormFieldValueFoswiki::Render::protectFormFieldValue
0000s0sFoswiki::Render::::protectPlainTextFoswiki::Render::protectPlainText
0000s0sFoswiki::Render::::verbatimCallBackFoswiki::Render::verbatimCallBack
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2package Foswiki::Render;
3
4=begin TML
5
6---+ package Foswiki::Render
7
8This module provides most of the actual HTML rendering code in Foswiki.
9
10=cut
11
12228µs239µs
# spent 26µs (14+13) within Foswiki::Render::BEGIN@12 which was called: # once (14µs+13µs) by Foswiki::renderer at line 12
use strict;
# spent 26µs making 1 call to Foswiki::Render::BEGIN@12 # spent 13µs making 1 call to strict::import
13225µs218µs
# spent 13µs (9+4) within Foswiki::Render::BEGIN@13 which was called: # once (9µs+4µs) by Foswiki::renderer at line 13
use warnings;
# spent 13µs making 1 call to Foswiki::Render::BEGIN@13 # spent 4µs making 1 call to warnings::import
14228µs264µs
# spent 37µs (10+27) within Foswiki::Render::BEGIN@14 which was called: # once (10µs+27µs) by Foswiki::renderer at line 14
use Assert;
# spent 37µs making 1 call to Foswiki::Render::BEGIN@14 # spent 27µs making 1 call to Exporter::import
15228µs2224µs
# spent 116µs (9+108) within Foswiki::Render::BEGIN@15 which was called: # once (9µs+108µs) by Foswiki::renderer at line 15
use Error qw(:try);
# spent 116µs making 1 call to Foswiki::Render::BEGIN@15 # spent 108µs making 1 call to Error::import
16219µs14µs
# spent 4µs within Foswiki::Render::BEGIN@16 which was called: # once (4µs+0s) by Foswiki::renderer at line 16
use CGI ();
# spent 4µs making 1 call to Foswiki::Render::BEGIN@16
17
18218µs13µs
# spent 3µs within Foswiki::Render::BEGIN@18 which was called: # once (3µs+0s) by Foswiki::renderer at line 18
use Foswiki ();
# spent 3µs making 1 call to Foswiki::Render::BEGIN@18
19218µs13µs
# spent 3µs within Foswiki::Render::BEGIN@19 which was called: # once (3µs+0s) by Foswiki::renderer at line 19
use Foswiki::Time ();
# spent 3µs making 1 call to Foswiki::Render::BEGIN@19
20218µs14µs
# spent 4µs within Foswiki::Render::BEGIN@20 which was called: # once (4µs+0s) by Foswiki::renderer at line 20
use Foswiki::Sandbox ();
# spent 4µs making 1 call to Foswiki::Render::BEGIN@20
212123µs1884µs
# spent 884µs (807+77) within Foswiki::Render::BEGIN@21 which was called: # once (807µs+77µs) by Foswiki::renderer at line 21
use Foswiki::Render::Anchors ();
# spent 884µs making 1 call to Foswiki::Render::BEGIN@21
22
23
# spent 4µs within Foswiki::Render::BEGIN@23 which was called: # once (4µs+0s) by Foswiki::renderer at line 28
BEGIN {
2415µs if ( $Foswiki::cfg{UseLocale} ) {
25 require locale;
26 import locale();
27 }
281134µs14µs}
# spent 4µs making 1 call to Foswiki::Render::BEGIN@23
29
30# Counter used to generate unique placeholders for when we lift blocks
31# (such as <verbatim> out of the text during rendering.
321500nsour $placeholderMarker = 0;
33
34# Limiting lookbehind and lookahead for wikiwords and emphasis.
35# use like \b
3613µsour $STARTWW = qr/^|(?<=[\s\(])/m;
371900nsour $ENDWW = qr/$|(?=[\s,.;:!?)])/m;
38
39# Note: the following marker sequences are used in text to mark things that
40# have been hoisted or need to be marked for further processing. The strings
41# are carefully chosen so that they (1) are not normally present in written
42# text and (2) they do not combine with other characters to form valid
43# wide-byte characters. A subset of the 7-bit control characters is used
44# (codepoint < 0x07). Warning: the RENDERZONE_MARKER in Foswiki.pm uses \3
45
46# Marker used to indicate the start of a table
471300nsour $TABLEMARKER = "\0\1\2TABLE\2\1\0";
48
49# Marker used to indicate table rows that are valid header/footer rows
501200nsour $TRMARK = "is\1all\1th";
51
52# General purpose marker used to mark escapes inthe text; for example, we
53# use it to mark hoisted blocks, such as verbatim blocks.
541200nsour $REMARKER = "\0";
55
56# Optional End marker for escapes where the default end character ; also
57# must be removed. Used for email anti-spam encoding.
581300nsour $REEND = "\1";
59
60# Temporary marker for <nop> and <literal> tags. They are used as follows:
61# - Remove all <nop> and <literal>
62# - Take out <input ..> tags
63# - Restore all <nop> and <literal>
64# - ... do other rendering
65# - Put back all <input ...> tags
66# - Remove any extraneous markers.
671300nsour $NOPMARK = "\2";
68
69# Default format for a link to a non-existant topic
7016µs136µs
# spent 46µs (10+36) within Foswiki::Render::BEGIN@70 which was called: # once (10µs+36µs) by Foswiki::renderer at line 72
use constant DEFAULT_NEWLINKFORMAT => <<'NLF';
# spent 36µs making 1 call to constant::import
71<span class="foswikiNewLink">$text<a href="%SCRIPTURLPATH{"edit"}%/$web/$topic?topicparent=%WEB%.%TOPIC%" rel="nofollow" title="%MAKETEXT{"Create this topic"}%">?</a></span>
7213.36ms146µsNLF
# spent 46µs making 1 call to Foswiki::Render::BEGIN@70
73
7413µsmy %list_types = (
75 A => 'upper-alpha',
76 a => 'lower-alpha',
77 i => 'lower-roman',
78 I => 'upper-roman'
79);
80
81=begin TML
82
83---++ ClassMethod new ($session)
84
85Creates a new renderer
86
87=cut
88
89
# spent 10µs within Foswiki::Render::new which was called: # once (10µs+0s) by Foswiki::renderer at line 2287 of /var/www/foswikidev/core/lib/Foswiki.pm
sub new {
901900ns my ( $class, $session ) = @_;
9117µs my $this = bless( { session => $session }, $class );
92
9316µs return $this;
94}
95
96=begin TML
97
98---++ ObjectMethod finish()
99Break circular references.
100
101=cut
102
103# Note to developers; please undef *all* fields in the object explicitly,
104# whether they are references or not. That way this method is "golden
105# documentation" of the live fields in the object.
106
# spent 5µs within Foswiki::Render::finish which was called: # once (5µs+0s) by Foswiki::finish at line 2488 of /var/www/foswikidev/core/lib/Foswiki.pm
sub finish {
1071500ns my $this = shift;
1081900ns undef $this->{NEWLINKFORMAT};
1091800ns undef $this->{LINKTOOLTIPINFO};
1101500ns undef $this->{LIST};
11115µs undef $this->{session};
112}
113
114=begin TML
115
116---++ ObjectMethod internalLink ( $web, $topic, $linkText, $anchor, $linkIfAbsent, $keepWebPrefix, $hasExplicitLinkLabel ) -> $html
117
118Generate a link.
119
120Note: Topic names may be spaced out. Spaced out names are converted
121to <nop>WikWords, for example, "spaced topic name" points to "SpacedTopicName".
122 * =$web= - the web containing the topic to be linked
123 * =$topic= - the topic to be linked
124 * =$linkText= - text to use for the link
125 * =$anchor= - the link anchor, if any
126 * =$linkIfAbsent= - boolean: false means suppress link for
127 non-existing pages
128 * =$keepWebPrefix= - boolean: true to keep web prefix (for
129 non existing Web.TOPIC)
130 * =$hasExplicitLinkLabel= - boolean: true if
131 [[link][explicit link label]]
132
133Called from outside the package by Func::internalLink.
134
135This is the only way to get a =renderWikiWordHandler= called. When the handler
136is called it has an opportunity to modify the link text, but nothing else, and
137the output is pumped through the rest of the rendering process, which is a
138mistake. This is a recognised shortcoming of the handler.
139
140=cut
141
142# SMELL: this is callable from Func, and is used by the ImportExportPlugin
143# (but nothing else AFAICT) - C.
144# Calls _renderWikiWord, which in turn will use Plurals.pm to match fold
145# plurals to equivalency with their singular form
146
147
# spent 4.76ms (468µs+4.30) within Foswiki::Render::internalLink which was called 18 times, avg 265µs/call: # 18 times (468µs+4.30ms) by Foswiki::Render::_handleSquareBracketedLink at line 1565, avg 265µs/call
sub internalLink {
1481819µs my ( $this, $web, $topic, $linkText, $anchor, $linkIfAbsent, $keepWebPrefix,
149 $hasExplicitLinkLabel, $params )
150 = @_;
151
152 # Webname/Subweb/ -> Webname/Subweb
153188µs $web =~ s/\/\Z//;
154
155186µs if ( $linkText eq $web ) {
156 $linkText =~ s/\//\./g;
157 }
158
159 #WebHome links to tother webs render as the WebName
160187µs if ( ( $linkText eq $Foswiki::cfg{HomeTopicName} )
161 && ( $web ne $this->{session}->{webName} ) )
162 {
163 $linkText = $web;
164 }
165
166 # Get rid of leading/trailing spaces in topic name
1671829µs $topic =~ s/^\s*//;
1681858µs $topic =~ s/\s*$//;
169
170 # Allow spacing out, etc.
171 # Plugin authors use $hasExplicitLinkLabel to determine if the link label
172 # should be rendered differently even if the topic author has used a
173 # specific link label.
1741836µs1850µs $linkText =
# spent 50µs making 18 calls to Foswiki::Plugins::dispatch, avg 3µs/call
175 $this->{session}->{plugins}
176 ->dispatch( 'renderWikiWordHandler', $linkText, $hasExplicitLinkLabel,
177 $web, $topic )
178 || $linkText;
179
180 # Turn spaced-out names into WikiWords - upper case first letter of
181 # whole link, and first of each word. TODO: Try to turn this off,
182 # avoiding spaces being stripped elsewhere
183189µs $topic = ucfirst($topic);
1841813µs $topic =~ s/\s([[:alnum:]])/\U$1/g;
185
186 # If locales are in effect, the above conversions will taint the topic
187 # name (Foswiki:Tasks:Item2091)
1881821µs1852µs $topic = Foswiki::Sandbox::untaintUnchecked($topic);
# spent 52µs making 18 calls to Foswiki::Sandbox::untaintUnchecked, avg 3µs/call
189
190 # Add <nop> before WikiWord inside link text to prevent double links
19118156µs159µs $linkText =~ s/(?<=[\s\(])([[:upper:]])/<nop>$1/g;
# spent 59µs making 1 call to utf8::SWASHNEW
1921858µs184.14ms return _renderWikiWord( $this, $web, $topic, $linkText, $anchor,
# spent 4.14ms making 18 calls to Foswiki::Render::_renderWikiWord, avg 230µs/call
193 $linkIfAbsent, $keepWebPrefix, $params );
194}
195
196=begin TML
197
198---++ ObjectMethod getRenderedVersion ( $text, $topicObject ) -> $html
199
200The main rendering function.
201
202=cut
203
204
# spent 50.1ms (13.6+36.6) within Foswiki::Render::getRenderedVersion which was called 5 times, avg 10.0ms/call: # 5 times (13.6ms+36.6ms) by Foswiki::Meta::renderTML at line 3367 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 10.0ms/call
sub getRenderedVersion {
205521µs my ( $this, $text, $topicObject ) = @_;
206 ASSERT( $topicObject->isa('Foswiki::Meta') ) if DEBUG;
207
20852µs return '' unless defined $text; # nothing to do
209
21053µs my $session = $this->{session};
21151µs my $plugins = $session->{plugins};
21252µs my $prefs = $session->{prefs};
213
21456µs @{ $this->{LIST} } = ();
215
216 # Initial cleanup
217544µs $text =~ s/\r//g;
218
219 # whitespace before <! tag (if it is the first thing) is illegal
220528µs $text =~ s/^\s+(<![a-z])/$1/i;
221
222 # clutch to enforce correct rendering at end of doc
223553µs $text =~ s/\n?$/\n<nop>\n/s;
224
225 # Maps of placeholders to tag parameters and text
22653µs my $removed = {};
227
228 # verbatim before literal - see Item3431
22959µs5603µs $text = Foswiki::takeOutBlocks( $text, 'verbatim', $removed );
# spent 603µs making 5 calls to Foswiki::takeOutBlocks, avg 121µs/call
23058µs51.42ms $text = Foswiki::takeOutBlocks( $text, 'literal', $removed );
# spent 1.42ms making 5 calls to Foswiki::takeOutBlocks, avg 284µs/call
231510µs510µs $text = Foswiki::takeOutBlocks( $text, 'dirtyarea', $removed )
# spent 10µs making 5 calls to Foswiki::Meta::isCacheable, avg 2µs/call
232 if $topicObject->isCacheable();
233
234529µs5123µs $text =
# spent 123µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 25µs/call
235 $this->_takeOutProtected( $text, qr/<\?([^?]*)\?>/s, 'comment',
236 $removed );
237517µs5648µs $text =
# spent 648µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 130µs/call
238 $this->_takeOutProtected( $text, qr/<!DOCTYPE([^<>]*)>?/mi, 'comment',
239 $removed );
240516µs5575µs $text =
# spent 575µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 115µs/call
241 $this->_takeOutProtected( $text, qr/<head.*?<\/head>/si, 'head',
242 $removed );
243515µs5513µs $text = $this->_takeOutProtected( $text, qr/<textarea\b.*?<\/textarea>/si,
# spent 513µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 103µs/call
244 'textarea', $removed );
245515µs5648µs $text =
# spent 648µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 130µs/call
246 $this->_takeOutProtected( $text, qr/<script\b.*?<\/script>/si, 'script',
247 $removed );
248516µs5426µs $text =
# spent 426µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 85µs/call
249 $this->_takeOutProtected( $text, qr/<style\b.*?<\/style>/si, 'style',
250 $removed );
251
252 # Remove the sticky tags (used in WysiwygPlugin's TML2HTML conversion)
253 # since they could potentially break a browser.
254 # They are removed here and not in the plugin because the plugin might
255 # not be installed but the sticky tags are standard markup.
256528µs $text =~ s#</?sticky>##g;
257
258 # DEPRECATED startRenderingHandler before PRE removed
259 # SMELL: could parse more efficiently if this wasn't
260 # here.
261521µs1535µs $plugins->dispatch( 'startRenderingHandler', $text, $topicObject->web,
# spent 16µs making 5 calls to Foswiki::Plugins::dispatch, avg 3µs/call # spent 11µs making 5 calls to Foswiki::Meta::web, avg 2µs/call # spent 8µs making 5 calls to Foswiki::Meta::topic, avg 2µs/call
262 $topicObject->topic );
263
26459µs5385µs $text = Foswiki::takeOutBlocks( $text, 'pre', $removed );
# spent 385µs making 5 calls to Foswiki::takeOutBlocks, avg 77µs/call
265
266 # Join lines ending in '\' (don't need \r?, it was removed already)
267526µs $text =~ s/\\\n//gs;
268
26958µs518.5ms $plugins->dispatch( 'preRenderingHandler', $text, $removed );
# spent 18.5ms making 5 calls to Foswiki::Plugins::dispatch, avg 3.69ms/call
270
271511µs516µs if ( $plugins->haveHandlerFor('insidePREHandler') ) {
# spent 16µs making 5 calls to Foswiki::Plugins::haveHandlerFor, avg 3µs/call
272 foreach my $region ( sort keys %$removed ) {
273 next unless ( $region =~ m/^pre\d+$/i );
274 my @lines = split( /\r?\n/, $removed->{$region}{text} );
275 my $rt = '';
276 while ( scalar(@lines) ) {
277 my $line = shift(@lines);
278 $plugins->dispatch( 'insidePREHandler', $line );
279 if ( $line =~ m/\n/ ) {
280 unshift( @lines, split( /\r?\n/, $line ) );
281 next;
282 }
283 $rt .= $line . "\n";
284 }
285 $removed->{$region}{text} = $rt;
286 }
287 }
288
28957µs58µs if ( $plugins->haveHandlerFor('outsidePREHandler') ) {
# spent 8µs making 5 calls to Foswiki::Plugins::haveHandlerFor, avg 2µs/call
290
291 # DEPRECATED - this is the one call preventing
292 # effective optimisation of the TML processing loop,
293 # as it exposes the concept of a 'line loop' to plugins,
294 # but HTML is not a line-oriented language (though TML is).
295 # But without it, a lot of processing could be moved
296 # outside the line loop.
297 my @lines = split( /\r?\n/, $text );
298 my $rt = '';
299 while ( scalar(@lines) ) {
300 my $line = shift(@lines);
301 $plugins->dispatch( 'outsidePREHandler', $line );
302 if ( $line =~ m/\n/ ) {
303 unshift( @lines, split( /\r?\n/, $line ) );
304 next;
305 }
306 $rt .= $line . "\n";
307 }
308
309 $text = $rt;
310 }
311
312 # Remove input fields: Item11480
313557µs $text =~ s/<nop>/N$NOPMARK/g;
314523µs5467µs $text =
# spent 467µs making 5 calls to Foswiki::Render::_takeOutProtected, avg 93µs/call
315 $this->_takeOutProtected( $text, qr/<input\b.*?>/si, 'input', $removed );
316561µs $text =~ s/N$NOPMARK/<nop>/g;
317
318 # Escape rendering: Change ' !AnyWord' to ' <nop>AnyWord',
319 # for final ' AnyWord' output
320576µs $text =~ s/$STARTWW\!(?=[\w\*\=])/<nop>/gm;
321
322 # Blockquoted email (indented with '> ')
323 # Could be used to provide different colours for different numbers of '>'
3245180µs $text =~ s/^>(.*?)$/'&gt;<cite>$1<\/cite><br \/>/gm;
325
326 # locate isolated < and > and translate to entities
327 # Protect isolated <!-- and -->
328589µs $text =~ s/<!--/{$REMARKER!--/g;
329579µs $text =~ s/-->/--}$REMARKER/g;
330
331 # SMELL: this next fragment does not handle the case where HTML tags
332 # are embedded in the values provided to other tags. The only way to
333 # do this correctly is to parse the HTML (bleagh!). So we just assume
334 # they have been escaped.
3355550µs179µs $text =~ s/<(\/?[\w\-]+(:[\w\-]+)?)>/{$REMARKER$1}$REMARKER/g;
# spent 79µs making 1 call to utf8::SWASHNEW
3365985µs158µs $text =~ s/<([\w\-]+(:[\w\-]+)?(\s+.*?|\/)?)>/{$REMARKER$1}$REMARKER/g;
# spent 58µs making 1 call to utf8::SWASHNEW
337
338 # XML processing instruction only valid at start of text
339538µs $text =~ s/^<(\?\w.*?\?)>/{$REMARKER$1}$REMARKER/g;
340
341 # entitify lone < and >, praying that we haven't screwed up :-(
342 # Item1985: CDATA sections are not lone < and >
343527µs $text =~ s/<(?!\!\[CDATA\[)/&lt\;/g;
344526µs $text =~ s/(?<!\]\])>/&gt\;/g;
3455159µs $text =~ s/{$REMARKER/</go;
3465150µs $text =~ s/}$REMARKER/>/go;
347
348 # other entities
3495106µs $text =~ s/&(\w+);/$REMARKER$1;/g; # "&abc;"
3505354µs $text =~ s/&(#x?[0-9a-f]+);/$REMARKER$1;/gi; # "&#123;"
351532µs $text =~ s/&/&amp;/g; # escape standalone "&"
3525387µs $text =~ s/$REMARKER(#x?[0-9a-f]+;)/&$1/goi;
3535101µs $text =~ s/$REMARKER(\w+;)/&$1/go;
354
355 # clear the set of unique anchornames in order to inhibit
356 # the 'relabeling' of anchor names if the same topic is processed
357 # more than once, cf. explanation in expandMacros()
358518µs584µs my $anchors = $this->getAnchorNames($topicObject);
# spent 84µs making 5 calls to Foswiki::Render::getAnchorNames, avg 17µs/call
359520µs514µs $anchors->clear();
# spent 14µs making 5 calls to Foswiki::Render::Anchors::clear, avg 3µs/call
360
361 # '#WikiName' anchors. Don't attempt to make these unique; renaming
362 # user-defined anchors is not sensible.
3636437µs5320µs $text =~ s{^(\#$Foswiki::regex{wikiWordRegex})}
# spent 266µs making 4 calls to utf8::SWASHNEW, avg 67µs/call # spent 54µs making 1 call to Foswiki::Render::Anchors::add
364 {'<span id="'.$anchors->add( $1 ).'"></span>'}gem;
365
366 # Headings
367 # '<h6>...</h6>' HTML rule
368560µs $text =~ s/$Foswiki::regex{headerPatternHt}/
369 _makeAnchorHeading($this, $2, $1, $anchors)/ge;
370
371 # '----+++++++' rule
372572µs $text =~ s/$Foswiki::regex{headerPatternDa}/
373 _makeAnchorHeading($this, $2, length($1), $anchors)/ge;
374
375 # Horizontal rule
376563µs $text =~ s/^---+/<hr \/>/gm;
377
378 # Now we really _do_ need a line loop, to process TML
379 # line-oriented stuff.
38052µs my $isList = 0; # True when within a list
38151µs my $tableRow = 0;
38251µs my @result;
3835900ns my $isFirst = 1;
384
3855150µs foreach my $line ( split( /\r?\n/, $text ) ) {
386
387 # Table: | cell | cell |
388 # allow trailing white space after the last |
389220202µs if ( $line =~ m/^(\s*)\|.*\|\s*$/ ) {
390
391 unless ($tableRow) {
392
393 # mark the head of the table
394 push( @result, $TABLEMARKER );
395 }
396 $line =~ s/^(\s*)\|(.*)/$1._emitTR( $this, $2 )/e;
397 $tableRow++;
398 }
399 elsif ($tableRow) {
400 _addTHEADandTFOOT( \@result );
401 push( @result, '</table>' );
402 $tableRow = 0;
403 }
404
405 # Lists and paragraphs
406220217µs if ( $line =~ m/^\s*$/ ) {
4075313µs unless ( $tableRow || $isFirst ) {
408 $line = '<p></p>';
409 }
4105310µs $isList = 0;
411 }
412 elsif ( $line =~ m/^\S/ ) {
413 $isList = 0;
414 }
415 elsif ( $line =~ m/^(\t| {3})+\S/ ) {
41635162µs if ( $line =~
417 s/^((?:\t| {3})+)\$\s*([^:]+):\s+/<dt> $2 <\/dt><dd> / )
418 {
419
420 # Definition list
421 _addListItem( $this, \@result, 'dl', 'dd', '', $1 );
422 $isList = 1;
423 }
424 elsif ( $line =~ s/^((?:\t| {3})+)(\S+?):\s+/<dt> $2 <\/dt><dd> / )
425 {
426
427 # Definition list (deprecated)
428 _addListItem( $this, \@result, 'dl', 'dd', '', $1 );
429 $isList = 1;
430 }
431 elsif ( $line =~ s/^((\t| )+)\* /<li> / ) {
432
433 # Unnumbered list
4343339µs33258µs _addListItem( $this, \@result, 'ul', 'li', '', $1 );
# spent 258µs making 33 calls to Foswiki::Render::_addListItem, avg 8µs/call
435339µs $isList = 1;
436 }
437 elsif ( $line =~ s/^((\t| )+): /<div class='foswikiIndent'> / ) {
438
439 # Indent pseudo-list
440 _addListItem( $this, \@result, '', 'div', 'foswikiIndent', $1 );
441 $isList = 1;
442 }
443 elsif ( $line =~ m/^((\t| )+)([1AaIi]\.|\d+\.?) ?/ ) {
444
445 # Numbered list
446 my $ot = $3;
447 $ot =~ s/^(.).*/$1/;
448 if ( $ot !~ /^\d$/ ) {
449
450 # Use style="list-type-type:"
451 $ot = ' style="list-style-type:' . $list_types{$ot} . '"';
452 }
453 else {
454 $ot = '';
455 }
456 $line =~ s/^((\t| )+)([1AaIi]\.|\d+\.?) ?/<li$ot> /;
457 _addListItem( $this, \@result, 'ol', 'li', '', $1 );
458 $isList = 1;
459 }
460 elsif ( $isList && $line =~ m/^(\t| )+\s*\S/ ) {
461
462 # indented line extending prior list item
4632900ns push( @result, $line );
4642700ns next;
465 }
466 else {
467 $isList = 0;
468 }
469 }
470 elsif ( $isList && $line =~ m/^(\t| )+\s*\S/ ) {
471
472 # indented line extending prior list item; case where indent
473 # starts with is at least 3 spaces or a tab, but may not be a
474 # multiple of 3.
475 push( @result, $line );
476 next;
477 }
478
479 # Finish the list
480218216µs180650µs unless ( $isList || $isFirst ) {
# spent 650µs making 180 calls to Foswiki::Render::_addListItem, avg 4µs/call
481 _addListItem( $this, \@result, '', '', '', '' );
482 }
483
48421890µs push( @result, $line );
48521895µs $isFirst = 0;
486 }
487
48852µs if ($tableRow) {
489 _addTHEADandTFOOT( \@result );
490 push( @result, '</table>' );
491 }
49256µs516µs _addListItem( $this, \@result, '', '', '', '' );
# spent 16µs making 5 calls to Foswiki::Render::_addListItem, avg 3µs/call
493
494551µs $text = join( '', @result );
495
496 # SMELL: use of $STARTWW and $ENDWW really limit the number of places
497 # emphasis can happen. But it's a tradeoff between that and excessive
498 # greed.
499
500550µs $text =~ s/${STARTWW}==(\S+?|\S[^\n]*?\S)==$ENDWW/_fixedFontText($1,1)/gem;
501537µs $text =~ s/${STARTWW}__(\S+?|\S[^\n]*?\S)
502 __$ENDWW/<strong><em>$1<\/em><\/strong>/gmx;
503580µs $text =~ s/${STARTWW}\*(\S+?|\S[^\n]*?\S)\*$ENDWW/<strong>$1<\/strong>/gm;
504552µs $text =~ s/${STARTWW}\_(\S+?|\S[^\n]*?\S)\_$ENDWW/<em>$1<\/em>/gm;
5055112µs $text =~ s/${STARTWW}\=(\S+?|\S[^\n]*?\S)\=$ENDWW/_fixedFontText($1,0)/gem;
506
507 # Handle [[][] and [[]] links
508 # Change ' ![[...' to ' [<nop>[...' to protect from further rendering
509543µs $text =~ s/(^|\s)\!\[\[/$1\[<nop>\[/gm;
510
511 # Spaced-out Wiki words with alternative link text
512 # i.e. [[$1][$3]]
51327242µs227.51ms $text =~ s(\[\[([^\]\[\n]+)\](\[([^\]\n]+)\])?\])
# spent 7.51ms making 22 calls to Foswiki::Render::_handleSquareBracketedLink, avg 341µs/call
514 (_handleSquareBracketedLink( $this,$topicObject,$1,$3))ge;
515
516 # URI - don't apply if the URI is surrounded by url() to avoid naffing
517 # CSS
51852.72ms $text =~ s/(^|(?<!url)[-*\s(|])
519 ($Foswiki::regex{linkProtocolPattern}:
520 ([^\s<>"]+[^\s*.,!?;:)<|]))/
521 $1._externalLink( $this,$2)/geox;
522
523 # Normal mailto:foo@example.com ('mailto:' part optional)
52453.60ms $text =~ s/$STARTWW((mailto\:)?
525 $Foswiki::regex{emailAddrRegex})$ENDWW/
526 _mailLink( $this, $1 )/gemx;
527
528520µs10269µs unless ( Foswiki::isTrue( $prefs->getPreference('NOAUTOLINK') ) ) {
# spent 220µs making 5 calls to Foswiki::Prefs::getPreference, avg 44µs/call # spent 49µs making 5 calls to Foswiki::isTrue, avg 10µs/call
529
530 # Handle WikiWords
531 $text = Foswiki::takeOutBlocks( $text, 'noautolink', $removed );
532 $text =~ s($STARTWW
533 (?:($Foswiki::regex{webNameRegex})\.)?
534 ($Foswiki::regex{wikiWordRegex}|
535 $Foswiki::regex{abbrevRegex})
536 ($Foswiki::regex{anchorRegex})?)
537 (_handleWikiWord( $this, $topicObject, $1, $2, $3))gexom;
538 Foswiki::putBackBlocks( \$text, $removed, 'noautolink' );
539 }
540
541 # Restore input fields before calling the end/post handlers
542518µs5169µs $this->_putBackProtected( \$text, 'input', $removed );
# spent 169µs making 5 calls to Foswiki::Render::_putBackProtected, avg 34µs/call
543531µs $text =~ s/N$NOPMARK//g;
544
545510µs559µs Foswiki::putBackBlocks( \$text, $removed, 'pre' );
# spent 59µs making 5 calls to Foswiki::putBackBlocks, avg 12µs/call
546
547 # DEPRECATED plugins hook after PRE re-inserted
54859µs5482µs $plugins->dispatch( 'endRenderingHandler', $text );
# spent 482µs making 5 calls to Foswiki::Plugins::dispatch, avg 96µs/call
549
550 # replace verbatim with pre in the final output
551516µs560µs Foswiki::putBackBlocks( \$text, $removed, 'verbatim', 'pre',
# spent 60µs making 5 calls to Foswiki::putBackBlocks, avg 12µs/call
552 \&verbatimCallBack );
553535µs $text =~ s|\n?<nop>\n$||; # clean up clutch
554
555511µs581µs $this->_putBackProtected( \$text, 'style', $removed );
# spent 81µs making 5 calls to Foswiki::Render::_putBackProtected, avg 16µs/call
556511µs5299µs $this->_putBackProtected( \$text, 'script', $removed );
# spent 299µs making 5 calls to Foswiki::Render::_putBackProtected, avg 60µs/call
557510µs5440µs Foswiki::putBackBlocks( \$text, $removed, 'literal', '' );
# spent 440µs making 5 calls to Foswiki::putBackBlocks, avg 88µs/call
55858µs516µs $this->_putBackProtected( \$text, 'literal', $removed );
# spent 16µs making 5 calls to Foswiki::Render::_putBackProtected, avg 3µs/call
55958µs510µs Foswiki::putBackBlocks( \$text, $removed, 'dirtyarea' )
# spent 10µs making 5 calls to Foswiki::Meta::isCacheable, avg 2µs/call
560 if $topicObject->isCacheable();
56156µs528µs $this->_putBackProtected( \$text, 'comment', $removed );
# spent 28µs making 5 calls to Foswiki::Render::_putBackProtected, avg 6µs/call
56257µs534µs $this->_putBackProtected( \$text, 'head', $removed );
# spent 34µs making 5 calls to Foswiki::Render::_putBackProtected, avg 7µs/call
56357µs510µs $this->_putBackProtected( \$text, 'textarea', $removed );
# spent 10µs making 5 calls to Foswiki::Render::_putBackProtected, avg 2µs/call
564
565513µs5666µs $text = _adjustH($text);
# spent 666µs making 5 calls to Foswiki::Render::_adjustH, avg 133µs/call
566
567531µs1091µs $this->{session}->getLoginManager()->endRenderingHandler($text);
# spent 46µs making 5 calls to Foswiki::LoginManager::endRenderingHandler, avg 9µs/call # spent 44µs making 5 calls to Foswiki::getLoginManager, avg 9µs/call
568
56957µs5525µs $plugins->dispatch( 'postRenderingHandler', $text );
# spent 525µs making 5 calls to Foswiki::Plugins::dispatch, avg 105µs/call
570553µs return $text;
571}
572
573=begin TML
574
575---++ StaticMethod html($tag, $attrs, $content) -> $html
576
577Generates HTML for the given HTML tag name, plus an optional map of attributes
578and optional content. Attribute values will be safely encoded for use in HTML.
579However TML is *not* escaped.
580
581Can be used to replace many of the CGI::* html generation methods.
582
583Use it like this:
584
585 * Foswiki::Render::html('a', { href => $url, name => 'blah' }, 'jump');
586 * Foswiki::Render::html('br');
587 * Foswiki::Render::html('p', undef, 'Now is the time');
588
589=cut
590
591sub html {
592 my ( $tag, $attrs, $innerHTML ) = @_;
593 my $html = "<$tag";
594 if ($attrs) {
595 my @keys = keys %$attrs;
596 @keys = sort @keys if (DEBUG);
597 foreach my $k (@keys) {
598 my $v = $attrs->{$k};
599
600 # This is what CGI encodes, so....
601 $v =~ s/([&<>"\x8b\x9b'])/'&#'.ord($1).';'/ge;
602 $html .= " $k=\"$v\"";
603 }
604 }
605 $innerHTML = '' unless defined $innerHTML;
606 return "$html>$innerHTML</$tag>";
607}
608
609=begin TML
610
611---++ StaticMethod verbatimCallBack
612
613Callback for use with putBackBlocks that replaces &lt; and >
614by their HTML entities &amp;lt; and &amp;gt;
615
616=cut
617
618sub verbatimCallBack {
619 my $val = shift;
620
621 # SMELL: A shame to do this, but in Foswiki.org have converted
622 # 3 spaces to tabs since day 1
623 $val =~ s/\t/ /g;
624
625 return Foswiki::entityEncode($val);
626}
627
628=begin TML
629
630---++ ObjectMethod TML2PlainText( $text, $topicObject, $opts ) -> $plainText
631
632Strip TML markup from text for display as plain text without
633pushing it through the full rendering pipeline. Intended for
634generation of topic and change summaries. Adds nop tags to
635prevent subsequent rendering; nops get removed at the very end.
636
637$opts:
638 * showvar - shows !%VAR% names if not expanded
639 * expandvar - expands !%VARS%
640 * nohead - strips ---+ headings at the top of the text
641 * showmeta - does not filter meta-data
642
643=cut
644
645sub TML2PlainText {
646 my ( $this, $text, $topicObject, $opts ) = @_;
647 $opts ||= '';
648
649 return '' unless defined $text;
650
651 $text =~ s/\r//g; # SMELL, what about OS10?
652
653 if ( $opts =~ m/showmeta/ ) {
654 $text =~ s/%META:/%<nop>META:/g;
655 }
656 else {
657 $text =~ s/%META:[A-Z].*?}%//g;
658 }
659
660 if ( $opts =~ m/expandvar/ ) {
661 $text =~ s/(\%)(SEARCH){/$1<nop>$2/g; # prevent recursion
662 $topicObject = Foswiki::Meta->new( $this->{session} )
663 unless $topicObject;
664 $text = $topicObject->expandMacros($text);
665 }
666 else {
667 $text =~ s/%WEB%/$topicObject->web() || ''/ge;
668 $text =~ s/%TOPIC%/$topicObject->topic() || ''/ge;
669 my $wtn = $this->{session}->{prefs}->getPreference('WIKITOOLNAME')
670 || '';
671 $text =~ s/%WIKITOOLNAME%/$wtn/g;
672 if ( $opts =~ m/showvar/ ) {
673 $text =~ s/%(\w+({.*?}))%/$1/g; # defuse
674 }
675 else {
676 $text =~ s/%$Foswiki::regex{tagNameRegex}({.*?})?%//g; # remove
677 }
678 }
679
680 # Format e-mail to add spam padding (HTML tags removed later)
681 $text =~ s/$STARTWW(
682 (mailto\:)?
683 [a-zA-Z0-9-_.+]+@[a-zA-Z0-9-_.]+\.[a-zA-Z0-9-_]+
684 )$ENDWW
685 /_mailLink( $this, $1 )/gemx;
686 $text =~ s/<!--.*?-->//gs; # remove all HTML comments
687 $text =~ s/<(?!nop)[^>]*>//g; # remove all HTML tags except <nop>
688 $text =~ s/\&[a-z]+;/ /g; # remove entities
689 if ( $opts =~ m/nohead/ ) {
690
691 # skip headings on top
692 while ( $text =~ s/^\s*\-\-\-+\+[^\n\r]*// ) { }; # remove heading
693 }
694
695 #keep only test portion of [[][]] links
696 $text =~ s/\[\[([^\]]*\]\[)(.*?)\]\]/$2/g;
697
698 # SMELL: can't do this, it removes these characters even when they're
699 # not for formatting
700 #$text =~ s/[\[\]\*\|=_\&\<\>]/ /g;
701
702 $text =~ s/${STARTWW}==(\S+?|\S[^\n]*?\S)==$ENDWW/$1/gem;
703 $text =~ s/${STARTWW}__(\S+?|\S[^\n]*?\S)__$ENDWW/$1/gm;
704 $text =~ s/${STARTWW}\*(\S+?|\S[^\n]*?\S)\*$ENDWW/$1/gm;
705 $text =~ s/${STARTWW}\_(\S+?|\S[^\n]*?\S)\_$ENDWW/$1/gm;
706 $text =~ s/${STARTWW}\=(\S+?|\S[^\n]*?\S)\=$ENDWW/$1/gem;
707
708 #SMELL: need to correct these too
709 $text =~ s/[\[\]\|\&]/ /g; # remove remaining Wiki formatting chars
710
711 $text =~ s/^\-\-\-+\+*\s*\!*/ /gm; # remove heading formatting and hbar
712 $text =~ s/[\+\-]+/ /g; # remove special chars
713 $text =~ s/^\s+//; # remove leading whitespace
714 $text =~ s/\s+$//; # remove trailing whitespace
715 $text =~ s/!(\w+)/$1/gs; # remove all nop exclamation marks before words
716 $text =~ s/[\r\n]+/\n/s;
717 $text =~ s/[ \t]+/ /s;
718
719 # defuse "Web." prefix in "Web.TopicName" link
720 $text =~ s{$STARTWW
721 (($Foswiki::regex{webNameRegex})\.
722 ($Foswiki::regex{wikiWordRegex}
723 | $Foswiki::regex{abbrevRegex}))}
724 {$2.<nop>$3}gx;
725 $text =~ s/\<nop\>//g; # remove any remaining nops
726 $text =~ s/[\<\>]/ /g; # remove any remaining formatting
727
728 return $text;
729}
730
731=begin TML
732
733---++ ObjectMethod protectPlainText($text) -> $tml
734
735Protect plain text from expansions that would normally be done
736duing rendering, such as wikiwords. Topic summaries, for example,
737have to be protected this way.
738
739=cut
740
741sub protectPlainText {
742 my ( $this, $text ) = @_;
743
744 # prevent text from getting rendered in inline search and link tool
745 # tip text by escaping links (external, internal, Interwiki)
746 $text =~ s/((($Foswiki::regex{webNameRegex})\.)?
747 ($Foswiki::regex{wikiWordRegex}
748 |$Foswiki::regex{abbrevRegex}))/<nop>$1/gx;
749
750 $text =~ s/([@%])/<nop>$1<nop>/g; # email address, macro
751
752 return $text;
753}
754
755# DEPRECATED: retained for compatibility with various hack-job extensions
756sub makeTopicSummary {
757 my ( $this, $text, $topic, $web, $flags ) = @_;
758 my $topicObject = Foswiki::Meta->new( $this->{session}, $web, $topic );
759 return $topicObject->summariseText( '', $text );
760}
761
762=begin TML
763
764---++ ObjectMethod renderRevisionInfo($topicObject, $rev, $format) -> $string
765
766Obtain and render revision info for a topic.
767 * =$topicObject= - the topic
768 * =$rev= - the rev number, defaults to latest rev
769 * =$format= - the render format, defaults to
770 =$rev - $time - $wikiusername=. =$format= can contain
771 the following keys for expansion:
772 | =$web= | the web name |
773 | =$topic= | the topic name |
774 | =$rev= | the rev number |
775 | =$username= | the login of the saving user |
776 | =$wikiname= | the wikiname of the saving user |
777 | =$wikiusername= | the web.wikiname of the saving user |
778 | =$date= | the date of the rev (no time) |
779 | =$time= | the time of the rev |
780 | =$min=, =$sec=, etc. | Same date format qualifiers as GMTIME |
781
782=cut
783
784
# spent 48.0ms (231µs+47.8) within Foswiki::Render::renderRevisionInfo which was called 3 times, avg 16.0ms/call: # 3 times (231µs+47.8ms) by Foswiki::REVINFO at line 45 of /var/www/foswikidev/core/lib/Foswiki/Macros/REVINFO.pm, avg 16.0ms/call
sub renderRevisionInfo {
78535µs my ( $this, $topicObject, $rrev, $format ) = @_;
78632µs my $value = $format || 'r$rev - $date - $time - $wikiusername';
78734µs341µs $value = Foswiki::expandStandardEscapes($value);
# spent 41µs making 3 calls to Foswiki::expandStandardEscapes, avg 14µs/call
788
789 # nop if there are no format tokens
79039µs return $value
791 unless $value =~
792m/\$(?:year|ye|wikiusername|wikiname|week|we|web|wday|username|tz|topic|time|seconds|sec|rev|rcs|month|mo|minutes|min|longdate|isotz|iso|http|hours|hou|epoch|email|dow|day|date)/x;
793
79433µs my $users = $this->{session}->{users};
7953800ns if ($rrev) {
796 my $loadedRev = $topicObject->getLoadedRev() || 0;
797 unless ( $rrev == $loadedRev ) {
798 $topicObject = Foswiki::Meta->new($topicObject);
799 $topicObject = $topicObject->load($rrev);
800 }
801 }
80238µs315.4ms my $info = $topicObject->getRevisionInfo();
# spent 15.4ms making 3 calls to Foswiki::Meta::getRevisionInfo, avg 5.13ms/call
803
8043900ns my $wun = '';
80531µs my $wn = '';
80631µs my $un = '';
80732µs if ( $info->{author} ) {
808310µs332.0ms my $cUID = $users->getCanonicalUserID( $info->{author} );
# spent 32.0ms making 3 calls to Foswiki::Users::getCanonicalUserID, avg 10.7ms/call
809
810#pre-set cuid if author is the unknown user from the basemapper (ie, default value) to avoid further guesswork
81132µs $cUID = $info->{author}
812 if ( $info->{author} eq
813 $Foswiki::Users::BaseUserMapping::UNKNOWN_USER_CUID );
8143500ns if ( !$cUID ) {
815 my $ln = $users->getLoginName( $info->{author} );
816 $cUID = $info->{author}
817 if ( defined($ln) and ( $ln ne 'unknown' ) );
818 }
81931µs if ($cUID) {
82037µs369µs $wun = $users->webDotWikiName($cUID);
# spent 69µs making 3 calls to Foswiki::Users::webDotWikiName, avg 23µs/call
82134µs36µs $wn = $users->getWikiName($cUID);
# spent 6µs making 3 calls to Foswiki::Users::getWikiName, avg 2µs/call
82238µs370µs $un = $users->getLoginName($cUID);
# spent 70µs making 3 calls to Foswiki::Users::getLoginName, avg 24µs/call
823 }
824
825 #only do the legwork if we really have to
82634µs if ( not( defined($wun) and defined($wn) and defined($un) )
827 or ( ( $wun eq '' ) or ( $wn eq '' ) or ( $un eq '' ) ) )
828 {
829 my $user = $info->{author};
830
831 # If we are still unsure, then use whatever is saved in the meta.
832 # But obscure it if the RenderLoggedInButUnknownUsers is enabled.
833 if ( $Foswiki::cfg{RenderLoggedInButUnknownUsers} ) {
834 $user = $info->{author} = 'unknown';
835 }
836 else {
837
838 #cUID's are forced to ascii by escaping other chars..
839 #$cUID =~ s/([^a-zA-Z0-9])/'_'.sprintf('%02x', ord($1))/ge;
840
841#remove any SomeMapping_ prefix from the cuid - as that initial '_' is not escaped.
842 $user =~ s/^[A-Z][A-Za-z]+Mapping_//;
843
844 #and then xform any escaped chars.
845262µs225µs
# spent 21µs (18+3) within Foswiki::Render::BEGIN@845 which was called: # once (18µs+3µs) by Foswiki::renderer at line 845
use bytes;
# spent 21µs making 1 call to Foswiki::Render::BEGIN@845 # spent 3µs making 1 call to bytes::import
846 $user =~ s/_([0-9a-f][0-9a-f])/chr(hex($1))/ge;
84724.00ms218µs
# spent 15µs (12+3) within Foswiki::Render::BEGIN@847 which was called: # once (12µs+3µs) by Foswiki::renderer at line 847
no bytes;
# spent 15µs making 1 call to Foswiki::Render::BEGIN@847 # spent 3µs making 1 call to bytes::unimport
848 }
849 $wun ||= $user;
850 $wn ||= $user;
851 $un ||= $user;
852 }
853 }
854
85534µs $value =~ s/\$web/$topicObject->web() || ''/ge;
85633µs $value =~ s/\$topic\(([^\)]*)\)/
857 Foswiki::Render::breakName( $topicObject->topic(), $1 )/ge;
85832µs $value =~ s/\$topic/$topicObject->topic() || ''/ge;
859312µs $value =~ s/\$rev/$info->{version}/g;
86038µs161µs $value =~ s/\$time/
# spent 61µs making 1 call to Foswiki::Time::formatTime
861 Foswiki::Time::formatTime($info->{date}, '$hour:$min:$sec')/ge;
862318µs365µs $value =~ s/\$date/
# spent 65µs making 3 calls to Foswiki::Time::formatTime, avg 22µs/call
863 Foswiki::Time::formatTime(
864 $info->{date}, $Foswiki::cfg{DefaultDateFormat} )/ge;
865321µs $value =~ s/(\$(rcs|longdate|isotz|iso|http|email|))/
866811µs869µs Foswiki::Time::formatTime($info->{date}, $1 )/ge;
# spent 69µs making 8 calls to Foswiki::Time::formatTime, avg 9µs/call
867
86838µs if ( $value =~
869m/\$(?:year|ye|week|we|web|wday|username|tz|seconds|sec|rcs|month|mo|minutes|min|longdate|hours|hou|epoch|dow|day)/
870 )
871 {
872 $value = Foswiki::Time::formatTime( $info->{date}, $value );
873 }
87432µs $value =~ s/\$username/$un/g;
875311µs $value =~ s/\$wikiname/$wn/g;
87632µs $value =~ s/\$wikiusername/$wun/g;
877
878312µs return $value;
879}
880
881=begin TML
882
883---++ ObjectMethod forEachLine( $text, \&fn, \%options ) -> $newText
884
885Iterate over each line, calling =\&fn= on each.
886\%options may contain:
887 * =pre= => true, will call fn for each line in pre blocks
888 * =verbatim= => true, will call fn for each line in verbatim blocks
889 * =literal= => true, will call fn for each line in literal blocks
890 * =noautolink= => true, will call fn for each line in =noautolink= blocks
891The spec of \&fn is =sub fn( $line, \%options ) -> $newLine=. The %options
892hash passed into this function is passed down to the sub, and the keys
893=in_literal=, =in_pre=, =in_verbatim= and =in_noautolink= are set boolean
894TRUE if the line is from one (or more) of those block types.
895
896The return result replaces $line in $newText.
897
898=cut
899
900
# spent 1.88ms (988µs+889µs) within Foswiki::Render::forEachLine which was called 6 times, avg 313µs/call: # 6 times (988µs+889µs) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 324 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 313µs/call
sub forEachLine {
90168µs my ( $this, $text, $fn, $options ) = @_;
902
90361µs return '' unless defined $text;
904
90564µs $options->{in_pre} = 0;
90661µs $options->{in_pre} = 0;
90762µs $options->{in_verbatim} = 0;
90866µs $options->{in_literal} = 0;
90965µs $options->{in_noautolink} = 0;
91062µs my $newText = '';
9116140µs foreach my $line ( split( /([\r\n]+)/, $text ) ) {
91291122µs if ( $line =~ m/[\r\n]/ ) {
913436µs $newText .= $line;
914438µs next;
915 }
9164835µs $options->{in_verbatim}++ if ( $line =~ m|^\s*<verbatim\b[^>]*>\s*$|i );
9174815µs $options->{in_verbatim}-- if ( $line =~ m|^\s*</verbatim>\s*$|i );
9184815µs $options->{in_literal}++ if ( $line =~ m|^\s*<literal\b[^>]*>\s*$|i );
9194815µs $options->{in_literal}-- if ( $line =~ m|^\s*</literal>\s*$|i );
9204829µs unless ( ( $options->{in_verbatim} > 0 )
921 || ( ( $options->{in_literal} > 0 ) ) )
922 {
92348177µs $options->{in_pre}++ if ( $line =~ m|<pre\b|i );
92448171µs $options->{in_pre}-- if ( $line =~ m|</pre>|i );
9254818µs $options->{in_noautolink}++
926 if ( $line =~ m|^\s*<noautolink\b[^>]*>\s*$|i );
9274819µs $options->{in_noautolink}--
928 if ( $line =~ m|^\s*</noautolink>\s*|i );
929 }
9304892µs48889µs unless ( $options->{in_pre} > 0 && !$options->{pre}
# spent 889µs making 48 calls to Foswiki::_fixupIncludedTopic, avg 19µs/call
931 || $options->{in_verbatim} > 0 && !$options->{verbatim}
932 || $options->{in_literal} > 0 && !$options->{literal}
933 || $options->{in_noautolink} > 0 && !$options->{noautolink} )
934 {
935 $line = &$fn( $line, $options );
936 }
9374834µs $newText .= $line;
938 }
939620µs return $newText;
940}
941
942=begin TML
943
944---++ StaticMethod breakName( $text, $args) -> $text
945
946 * =$text= - text to "break"
947 * =$args= - string of format (\d+)([,\s*]\.\.\.)?)
948Hyphenates $text every $1 characters, or if $2 is "..." then shortens to
949$1 characters and appends "..." (making the final string $1+3 characters
950long)
951
952_Moved from Search.pm because it was obviously unhappy there,
953as it is a rendering function_
954
955=cut
956
957sub breakName {
958 my ( $text, $args ) = @_;
959
960 my @params = split( /[\,\s]+/, $args, 2 );
961 if (@params) {
962 my $len = $params[0] || 1;
963 $len = 1 if ( $len < 1 );
964 my $sep = '- ';
965 $sep = $params[1] if ( @params > 1 );
966 if ( $sep =~ m/^\.\.\./i ) {
967
968 # make name shorter like 'ThisIsALongTop...'
969 $text =~ s/(.{$len})(.+)/$1.../s;
970
971 }
972 else {
973
974 # split and hyphenate the topic like 'ThisIsALo- ngTopic'
975 $text =~ s/(.{$len})/$1$sep/gs;
976 $text =~ s/$sep$//;
977 }
978 }
979 return $text;
980}
981
982=begin TML
983
984---++ StaticMethod protectFormFieldValue($value, $attrs) -> $html
985
986Given the value of a form field, and a set of attributes that control how
987to display that value, protect the value from further processing.
988
989The protected value is determined from the value of the field after:
990 * newlines are replaced with &lt;br> or the value of $attrs->{newline}
991 * processing through breakName if $attrs->{break} is defined
992 * escaping of $vars if $attrs->{protectdollar} is defined
993 * | is replaced with &amp;#124; or the value of $attrs->{bar} if defined
994
995=cut
996
997sub protectFormFieldValue {
998 my ( $value, $attrs ) = @_;
999
1000 $value = '' unless defined($value);
1001
1002 if ( $attrs && $attrs->{break} ) {
1003 $value =~ s/^\s*(.*?)\s*$/$1/g;
1004 $value = breakName( $value, $attrs->{break} );
1005 }
1006
1007 # Item3489, Item2837. Prevent $vars in formfields from
1008 # being expanded in formatted searches.
1009 if ( $attrs && $attrs->{protectdollar} ) {
1010 $value =~ s/\$(n|nop|quot|percnt|dollar)/\$<nop>$1/g;
1011 }
1012
1013 # change newlines
1014 my $newline = '<br />';
1015 if ( $attrs && defined $attrs->{newline} ) {
1016 $newline = $attrs->{newline};
1017 $newline =~ s/\$n/\n/gs;
1018 }
1019 $value =~ s/\r?\n/$newline/gs;
1020
1021 # change vbars
1022 my $bar = '&#124;';
1023 if ( $attrs && $attrs->{bar} ) {
1024 $bar = $attrs->{bar};
1025 }
1026 $value =~ s/\|/$bar/g;
1027
1028 return $value;
1029}
1030
1031=begin TML
1032
1033---++ ObjectMethod getAnchorNames( $topicObject ) -> $set
1034
1035Get the anchor name set generated for the given topic. This is so that the
1036same anchor names can be generated for each time the same topic is
1037%INCLUDEd (the same anchor target will be generated for each time the
1038topic is included.
1039
1040Note that anchor names generated this way are unique since the last time the
1041anchor set is cleared, which happens (1) whenever a new session is started
1042and (2) whenever a new %TOC macro is rendered (see Foswiki/Macros/TOC).
1043
1044Returns an object of type Foswiki::Render::Anchors.
1045
1046=cut
1047
1048
# spent 84µs (55+28) within Foswiki::Render::getAnchorNames which was called 5 times, avg 17µs/call: # 5 times (55µs+28µs) by Foswiki::Render::getRenderedVersion at line 358, avg 17µs/call
sub getAnchorNames {
104955µs my ( $this, $topicObject ) = @_;
1050510µs518µs my $id = $topicObject->getPath();
# spent 18µs making 5 calls to Foswiki::Meta::getPath, avg 4µs/call
105155µs my $a = $this->{_anchorNames}{$id};
105252µs unless ($a) {
105316µs110µs $a = new Foswiki::Render::Anchors();
# spent 10µs making 1 call to Foswiki::Render::Anchors::new
105412µs $this->{_anchorNames}{$id} = $a;
1055 }
1056513µs return $a;
1057}
1058
1059# Get the template for a "new topic" link
1060sub _newLinkFormat {
1061 my $this = shift;
1062 unless ( $this->{NEWLINKFORMAT} ) {
1063 $this->{NEWLINKFORMAT} =
1064 $this->{session}->{prefs}->getPreference('NEWLINKFORMAT')
1065 || DEFAULT_NEWLINKFORMAT;
1066 }
1067 return $this->{NEWLINKFORMAT};
1068}
1069
1070# Add a list item, of the given type and indent depth. The list item may
1071# cause the opening or closing of lists currently being handled.
1072
# spent 924µs within Foswiki::Render::_addListItem which was called 218 times, avg 4µs/call: # 180 times (650µs+0s) by Foswiki::Render::getRenderedVersion at line 480, avg 4µs/call # 33 times (258µs+0s) by Foswiki::Render::getRenderedVersion at line 434, avg 8µs/call # 5 times (16µs+0s) by Foswiki::Render::getRenderedVersion at line 492, avg 3µs/call
sub _addListItem {
1073218135µs my ( $this, $result, $type, $element, $css, $indent ) = @_;
1074
107521887µs $indent =~ s/ /\t/g;
107621846µs my $depth = length($indent);
1077
107821876µs my $size = scalar( @{ $this->{LIST} } );
1079
1080 # The whitespaces either side of the tags are required for the
1081 # emphasis REs to work.
108221862µs if ( $size < $depth ) {
108382µs my $firstTime = 1;
108484µs while ( $size < $depth ) {
1085813µs push( @{ $this->{LIST} }, { type => $type, element => $element } );
108681µs push( @$result,
1087 " <$element" . ( $css ? " class='$css'" : "" ) . ">\n" )
1088 unless ($firstTime);
108986µs push( @$result, ' <' . $type . ">\n" ) if $type;
109081µs $firstTime = 0;
109183µs $size++;
1092 }
1093 }
1094 else {
109521075µs while ( $size > $depth ) {
109685µs my $tags = pop( @{ $this->{LIST} } );
109785µs my $r = "\n</" . $tags->{element} . '>';
109885µs $r .= '</' . $tags->{type} . '> ' if $tags->{type};
109983µs push( @$result, $r );
110089µs $size--;
1101 }
110221073µs if ($size) {
1103 push( @$result,
1104 "\n</" . $this->{LIST}->[ $size - 1 ]->{element} . '> ' );
1105 }
1106 else {
110718576µs push( @$result, "\n" );
1108 }
1109 }
1110
1111218431µs if ($size) {
11123314µs my $oldt = $this->{LIST}->[ $size - 1 ];
11133316µs if ( $oldt->{type} ne $type ) {
1114 my $r = '';
1115 $r .= ' </' . $oldt->{type} . '>' if $oldt->{type};
1116 $r .= '<' . $type . ">\n" if $type;
1117 push( @$result, $r ) if $r;
1118 pop( @{ $this->{LIST} } );
1119 push( @{ $this->{LIST} }, { type => $type, element => $element } );
1120 }
1121 }
1122}
1123
1124# Given that we have just seen the end of a table, work out the thead,
1125# tbody and tfoot sections
1126sub _addTHEADandTFOOT {
1127 my ($lines) = @_;
1128
1129 # scan back to the head of the table
1130 my $i = scalar(@$lines) - 1;
1131 my @thRows;
1132 my $inFoot = 1;
1133 my $footLines = 0;
1134 my $headLines = 0;
1135
1136 while ( $i >= 0 && $lines->[$i] ne $TABLEMARKER ) {
1137 if ( $lines->[$i] =~ m/^\s*$/ ) {
1138
1139 # Remove blank lines in tables; they generate spurious <p>'s
1140 splice( @$lines, $i, 1 );
1141 }
1142 elsif ( $lines->[$i] =~ s/$TRMARK=(["'])(.*?)\1//i ) {
1143 if ($2) {
1144
1145 # In head or foot
1146 if ($inFoot) {
1147
1148 #print STDERR "FOOT: $lines->[$i]\n";
1149 $footLines++;
1150 }
1151 else {
1152
1153 #print STDERR "HEAD: $lines->[$i]\n";
1154 $headLines++;
1155 }
1156 }
1157 else {
1158
1159 # In body
1160 #print STDERR "BODY: $lines->[$i]\n";
1161 $inFoot = 0;
1162 $headLines = 0;
1163 }
1164 }
1165 $i--;
1166 }
1167 $lines->[ $i++ ] = " <table class='foswikiTable'>";
1168
1169 if ($headLines) {
1170 splice( @$lines, $i++, 0, '<thead>' );
1171 splice( @$lines, $i + $headLines, 0, '</thead>' );
1172 $i += $headLines + 1;
1173 }
1174
1175 if ($footLines) {
1176
1177 # Extract the foot and stick it in the table after the head (if any)
1178 # WRC says browsers prefer this
1179 my $firstFoot = scalar(@$lines) - $footLines;
1180 my @foot = splice( @$lines, $firstFoot, $footLines );
1181 unshift( @foot, '<tfoot>' );
1182 push( @foot, '</tfoot>' );
1183 splice( @$lines, $i, 0, @foot );
1184 $i += scalar(@foot);
1185 }
1186 splice( @$lines, $i, 0, '<tbody>' );
1187 push( @$lines, '</tbody>' );
1188}
1189
1190sub _emitTR {
1191 my ( $this, $row ) = @_;
1192
1193 $row =~ s/\t/ /g; # change tabs to space
1194 $row =~ s/\s*$//; # remove trailing spaces
1195 # calc COLSPAN
1196 $row =~ s/(\|\|+)/
1197 'colspan'.$REMARKER.length($1).'|'/ge;
1198 my $cells = '';
1199 my $containsTableHeader;
1200 my $isAllTH = 1;
1201 foreach ( split( /\|/, $row ) ) {
1202 my %attr;
1203
1204 # Avoid matching single columns
1205 if (s/colspan$REMARKER([0-9]+)//o) {
1206 $attr{colspan} = $1;
1207 }
1208 s/^\s+$/ &nbsp; /;
1209 my ( $l1, $l2 ) = ( 0, 0 );
1210 if (/^(\s*).*?(\s*)$/) {
1211 $l1 = length($1);
1212 $l2 = length($2);
1213 }
1214 if ( $l1 >= 2 ) {
1215 if ( $l2 <= 1 ) {
1216 $attr{align} = 'right';
1217 }
1218 else {
1219 $attr{align} = 'center';
1220 }
1221 }
1222
1223 # implicit untaint is OK, because we are just taking topic data
1224 # and rendering it; no security step is bypassed.
1225 if (/^\s*\*(.*)\*\s*$/) {
1226 $cells .= CGI::th( \%attr, "<strong> $1 </strong>" ) . "\n";
1227 }
1228 else {
1229 $cells .= CGI::td( \%attr, " $_ " ) . "\n";
1230 $isAllTH = 0;
1231 }
1232 }
1233 return CGI::Tr( { $TRMARK => $isAllTH }, $cells );
1234}
1235
1236sub _fixedFontText {
1237 my ( $text, $embolden ) = @_;
1238
1239 # preserve white space, so replace it by '&nbsp; ' patterns
1240 $text =~ s/\t/ /g;
1241 $text =~ s|((?:[\s]{2})+)([^\s])|'&nbsp; ' x (length($1) / 2) . $2|eg;
1242 $text = '<b>' . $text . '</b>' if $embolden;
1243 return '<code>' . $text . '</code>';
1244}
1245
1246# Build an HTML &lt;Hn> element with suitable anchor for linking
1247# from %<nop>TOC%
1248sub _makeAnchorHeading {
1249 my ( $this, $text, $level, $anchors ) = @_;
1250
1251 # - Build '<nop><h1><a name='atext'></a> heading </h1>' markup
1252 # - Initial '<nop>' is needed to prevent subsequent matches.
1253 # filter '!!', '%NOTOC%'
1254 $text =~ s/$Foswiki::regex{headerPatternNoTOC}//;
1255
1256 my $html =
1257 '<nop><h'
1258 . $level . ' ' . 'id="'
1259 . $anchors->makeHTMLTarget($text) . '"> '
1260 . $text . ' </h'
1261 . $level . '>';
1262
1263 return $html;
1264}
1265
1266# TODO: this should be overridable by plugins.
1267
# spent 4.14ms (188µs+3.95) within Foswiki::Render::_renderWikiWord which was called 18 times, avg 230µs/call: # 18 times (188µs+3.95ms) by Foswiki::Render::internalLink at line 192, avg 230µs/call
sub _renderWikiWord {
12681821µs my ( $this, $web, $topic, $linkText, $anchor, $linkIfAbsent, $keepWebPrefix,
1269 $params )
1270 = @_;
1271188µs my $session = $this->{session};
12721851µs181.32ms my $topicExists = $session->topicExists( $web, $topic );
# spent 1.32ms making 18 calls to Foswiki::topicExists, avg 73µs/call
1273
1274185µs my $singular = '';
1275183µs unless ($topicExists) {
1276
1277 # topic not found - try to singularise
1278 require Foswiki::Plurals;
1279 $singular = Foswiki::Plurals::singularForm( $web, $topic );
1280 if ($singular) {
1281 $topicExists = $session->topicExists( $web, $singular );
1282 $topic = $singular if $topicExists;
1283 }
1284 }
1285
1286184µs if ($topicExists) {
1287
1288 # add a dependency so that the page gets invalidated as soon as the
1289 # topic is deleted
12901814µs $this->{session}->{cache}->addDependency( $web, $topic )
1291 if $Foswiki::cfg{Cache}{Enabled};
1292
12931868µs182.63ms return _renderExistingWikiWord( $this, $web, $topic, $linkText, $anchor,
# spent 2.63ms making 18 calls to Foswiki::Render::_renderExistingWikiWord, avg 146µs/call
1294 $params );
1295 }
1296 if ($linkIfAbsent) {
1297
1298 # CDot: disabled until SuggestSingularNotPlural is resolved
1299 # if ($singular && $singular ne $topic) {
1300 # #unshift( @topics, $singular);
1301 # }
1302
1303 # add a dependency so that the page gets invalidated as soon as the
1304 # WikiWord comes into existance
1305 # Note we *ignore* the params if the target topic does not exist
1306 $this->{session}->{cache}->addDependency( $web, $topic )
1307 if $Foswiki::cfg{Cache}{Enabled};
1308
1309 return _renderNonExistingWikiWord( $this, $web, $topic, $linkText );
1310 }
1311 if ($keepWebPrefix) {
1312 return $web . '.' . $linkText;
1313 }
1314
1315 return $linkText;
1316}
1317
1318
# spent 2.63ms (429µs+2.20) within Foswiki::Render::_renderExistingWikiWord which was called 18 times, avg 146µs/call: # 18 times (429µs+2.20ms) by Foswiki::Render::_renderWikiWord at line 1293, avg 146µs/call
sub _renderExistingWikiWord {
13191816µs my ( $this, $web, $topic, $text, $anchor, $params ) = @_;
1320
1321183µs my @cssClasses;
13221817µs push( @cssClasses, 'foswikiCurrentWebHomeLink' )
1323 if ( ( $web eq $this->{session}->{webName} )
1324 && ( $topic eq $Foswiki::cfg{HomeTopicName} ) );
1325
1326184µs my $inCurrentTopic = 0;
1327
13281813µs if ( ( $web eq $this->{session}->{webName} )
1329 && ( $topic eq $this->{session}->{topicName} ) )
1330 {
1331 push( @cssClasses, 'foswikiCurrentTopicLink' );
1332 $inCurrentTopic = 1;
1333 }
1334
1335183µs my %attrs;
13361827µs18606µs my $href = $this->{session}->getScriptUrl( 0, 'view', $web, $topic );
# spent 606µs making 18 calls to Foswiki::getScriptUrl, avg 34µs/call
1337183µs if ($params) {
1338 $href .= $params;
1339 }
1340
1341182µs if ($anchor) {
1342 $anchor = Foswiki::Render::Anchors::make($anchor);
1343 $anchor = Foswiki::urlEncode($anchor);
1344
1345 # No point in trying to make it unique; just aim at the first
1346 # occurrence
1347 # Item8556 - drop path if same topic
1348 $href = $inCurrentTopic ? "#$anchor" : "$href#$anchor";
1349 }
1350189µs $attrs{class} = join( ' ', @cssClasses ) if ( $#cssClasses >= 0 );
13511816µs $attrs{href} = $href;
1352
1353 # Add a tooltip, if it's enabled
13541811µs unless ( defined( $this->{LINKTOOLTIPINFO} ) ) {
13551836µs18637µs $this->{LINKTOOLTIPINFO} =
# spent 637µs making 18 calls to Foswiki::Prefs::getPreference, avg 35µs/call
1356 $this->{session}->{prefs}->getPreference('LINKTOOLTIPINFO')
1357 || '';
13581859µs if ( $this->{LINKTOOLTIPINFO} =~ m/^on$/i ) {
1359 $this->{LINKTOOLTIPINFO} = '$username - $date - r$rev: $summary';
1360 }
1361 elsif ( $this->{LINKTOOLTIPINFO} =~ m/^(off)?$/i ) {
1362 undef $this->{LINKTOOLTIPINFO};
1363 }
1364 }
1365185µs if ( defined $this->{LINKTOOLTIPINFO}
1366 && $this->{session}->inContext('view') )
1367 {
1368 require Foswiki::Render::ToolTip;
1369 my $tooltip =
1370 Foswiki::Render::ToolTip::render( $this->{session}, $web, $topic,
1371 $this->{LINKTOOLTIPINFO} );
1372 $attrs{title} = $tooltip if $tooltip;
1373 }
1374
13751828µs18283µs my $aFlag = CGI::autoEscape(0);
# spent 188µs making 17 calls to CGI::autoEscape, avg 11µs/call # spent 96µs making 1 call to CGI::AUTOLOAD
13761833µs18497µs my $link = CGI::a( \%attrs, $text );
# spent 497µs making 18 calls to CGI::a, avg 28µs/call
13771818µs18160µs CGI::autoEscape($aFlag);
# spent 160µs making 18 calls to CGI::autoEscape, avg 9µs/call
1378
1379 # When we pass the tooltip text to CGI::a it may contain
1380 # <nop>s, and CGI::a will convert the < to &lt;. This is a
1381 # basic problem with <nop>.
1382 #$link =~ s/&lt;nop&gt;/<nop>/g;
13831856µs return $link;
1384}
1385
1386sub _renderNonExistingWikiWord {
1387 my ( $this, $web, $topic, $text ) = @_;
1388
1389 my $ans = $this->_newLinkFormat;
1390 $ans =~ s/\$web/$web/g;
1391 $ans =~ s/\$topic/$topic/g;
1392 $ans =~ s/\$text/$text/g;
1393 my $topicObject = Foswiki::Meta->new(
1394 $this->{session},
1395 $this->{session}->{webName},
1396 $this->{session}->{topicName}
1397 );
1398 return $topicObject->expandMacros($ans);
1399}
1400
1401# _handleWikiWord is called for a wiki word that needs linking.
1402# Handle the various link constructions. e.g.:
1403# WikiWord
1404# Web.WikiWord
1405# Web.WikiWord#anchor
1406#
1407# This routine adds missing parameters before passing off to internallink
1408sub _handleWikiWord {
1409 my ( $this, $topicObject, $web, $topic, $anchor ) = @_;
1410
1411 my $linkIfAbsent = 1;
1412 my $keepWeb = 0;
1413 my $text;
1414
1415 # For some strange reason, $web doesn't get untainted by the regex
1416 # that invokes this function. We can untaint it safely, because it's
1417 # validated by the RE.
1418 $web = Foswiki::Sandbox::untaintUnchecked($web);
1419
1420 $web = $topicObject->web() unless ( defined($web) );
1421 if ( defined($anchor) ) {
1422 ASSERT( ( $anchor =~ m/\#.*/ ) ) if DEBUG; # must include a hash.
1423 }
1424 else {
1425 $anchor = '';
1426 }
1427
1428 if ( defined($anchor) ) {
1429
1430 # 'Web.TopicName#anchor' or 'Web.ABBREV#anchor' link
1431 $text = $topic . $anchor;
1432 }
1433 else {
1434 $anchor = '';
1435
1436 # 'Web.TopicName' or 'Web.ABBREV' link:
1437 if ( $topic eq $Foswiki::cfg{HomeTopicName}
1438 && $web ne $this->{session}->{webName} )
1439 {
1440 $text = $web;
1441 }
1442 else {
1443 $text = $topic;
1444 }
1445 }
1446
1447 # true to keep web prefix for non-existing Web.TOPIC
1448 # Have to leave "web part" of ABR.ABR.ABR intact if topic not found
1449 $keepWeb =
1450 ( $topic =~ m/^$Foswiki::regex{abbrevRegex}$/
1451 && $web ne $this->{session}->{webName} );
1452
1453 # false means suppress link for non-existing pages
1454 $linkIfAbsent = ( $topic !~ /^$Foswiki::regex{abbrevRegex}$/o );
1455
1456 return $this->internalLink( $web, $topic, $text, $anchor, $linkIfAbsent,
1457 $keepWeb, undef );
1458}
1459
1460# Protect WikiWords, TLAs and URLs from further rendering with <nop>
1461
# spent 1.60ms (1.09+509µs) within Foswiki::Render::_escapeAutoLinks which was called 22 times, avg 73µs/call: # 22 times (1.09ms+509µs) by Foswiki::Render::_handleSquareBracketedLink at line 1503, avg 73µs/call
sub _escapeAutoLinks {
1462227µs my $text = shift;
1463
1464226µs if ($text) {
1465
1466 # WikiWords, TLAs, and email addresses
146722984µs8509µs $text =~ s/(?<=[\s\(])
# spent 509µs making 8 calls to utf8::SWASHNEW, avg 64µs/call
1468 (
1469 (?:
1470 (?:($Foswiki::regex{webNameRegex})\.)?
1471 (?: $Foswiki::regex{wikiWordRegex}
1472 | $Foswiki::regex{abbrevRegex} )
1473 )
1474 | $Foswiki::regex{emailAddrRegex}
1475 )/<nop>$1/gx;
1476
1477 # Explicit links
14782255µs $text =~ s/($Foswiki::regex{linkProtocolPattern}):(?=\S)/$1<nop>:/g;
1479 }
14802257µs return $text;
1481}
1482
1483# Handle SquareBracketed links mentioned on page $web.$topic
1484# format: [[$link]]
1485# format: [[$link][$text]]
1486
# spent 7.51ms (817µs+6.69) within Foswiki::Render::_handleSquareBracketedLink which was called 22 times, avg 341µs/call: # 22 times (817µs+6.69ms) by Foswiki::Render::getRenderedVersion at line 513, avg 341µs/call
sub _handleSquareBracketedLink {
14872238µs my ( $this, $topicObject, $link, $text ) = @_;
1488
1489 # Strip leading/trailing spaces
14902225µs $link =~ s/^\s+//;
14912230µs $link =~ s/\s+$//;
1492
1493226µs my $hasExplicitLinkLabel = 0;
1494
14952210µs if ( defined($text) ) {
1496
1497 # [[$link][$text]]
1498227µs $hasExplicitLinkLabel = 1;
14992243µs2296µs if ( my $img = $this->_isImageLink($text) ) {
# spent 96µs making 22 calls to Foswiki::Render::_isImageLink, avg 4µs/call
1500 $text = $img;
1501 }
1502 else {
15032231µs221.60ms $text = _escapeAutoLinks($text);
# spent 1.60ms making 22 calls to Foswiki::Render::_escapeAutoLinks, avg 73µs/call
1504 }
1505 }
1506
15072277µs434µs if ( $link =~ m#^($Foswiki::regex{linkProtocolPattern}:|/)# ) {
# spent 34µs making 4 calls to Foswiki::Render::_externalLink, avg 8µs/call
1508 return $this->_externalLink( $link, $text );
1509 }
1510
1511 # Extract '?params'
1512 # $link =~ s/(\?.*?)(?>#|$)//;
1513185µs my $params = '';
1514189µs if ( $link =~ s/(\?.*$)// ) {
1515 $params = $1;
1516 }
1517
1518183µs $text = _escapeAutoLinks($link) unless defined $text;
15191831µs $text =~ s/${STARTWW}==(\S+?|\S[^\n]*?\S)==$ENDWW/_fixedFontText($1,1)/gem;
15201824µs $text =~ s/${STARTWW}__(\S+?|\S[^\n]*?\S)
1521 __$ENDWW/<strong><em>$1<\/em><\/strong>/gmx;
15221824µs $text =~ s/${STARTWW}\*(\S+?|\S[^\n]*?\S)\*$ENDWW/<strong>$1<\/strong>/gm;
15231822µs $text =~ s/${STARTWW}\_(\S+?|\S[^\n]*?\S)\_$ENDWW/<em>$1<\/em>/gm;
15241821µs $text =~ s/${STARTWW}\=(\S+?|\S[^\n]*?\S)\=$ENDWW/_fixedFontText($1,0)/gem;
1525
1526 # Extract '#anchor'
1527 # $link =~ s/(\#[a-zA-Z_0-9\-]*$)//;
1528183µs my $anchor = '';
15291825µs if ( $link =~ s/($Foswiki::regex{anchorRegex}$)// ) {
1530 $anchor = $1;
1531
1532 #$text =~ s/#$anchor//;
1533 }
1534
1535 # filter out &any; entities (legacy)
15361819µs $link =~ s/\&[a-z]+\;//gi;
1537
1538 # filter out &#123; entities (legacy)
1539187µs $link =~ s/\&\#[0-9]+\;//g;
1540
1541 # Filter junk
15421841µs $link =~ s/$Foswiki::cfg{NameFilter}+/ /g;
1543
1544 ASSERT( UNTAINTED($link) ) if DEBUG;
1545
1546 # Capitalise first word
15471812µs $link = ucfirst($link);
1548
1549 # Collapse spaces and capitalise following letter
15501815µs $link =~ s/\s([[:alnum:]])/\U$1/g;
1551
1552 # Get rid of remaining spaces, i.e. spaces in front of -'s and ('s
15531812µs $link =~ s/\s//g;
1554
1555 # The link is used in the topic name, and if locales are in effect,
1556 # the above conversions will taint the name (Foswiki:Tasks:Item2091)
15571828µs1870µs $link = Foswiki::Sandbox::untaintUnchecked($link);
# spent 70µs making 18 calls to Foswiki::Sandbox::untaintUnchecked, avg 4µs/call
1558
1559183µs $link ||= $topicObject->topic;
1560
1561 # Topic defaults to the current topic
15621861µs36131µs my ( $web, $topic ) =
# spent 99µs making 18 calls to Foswiki::normalizeWebTopicName, avg 5µs/call # spent 33µs making 18 calls to Foswiki::Meta::web, avg 2µs/call
1563 $this->{session}->normalizeWebTopicName( $topicObject->web, $link );
1564
15651862µs184.76ms return $this->internalLink( $web, $topic, $text, $anchor, 1, undef,
# spent 4.76ms making 18 calls to Foswiki::Render::internalLink, avg 265µs/call
1566 $hasExplicitLinkLabel, $params );
1567}
1568
1569# Check if text is an image # (as indicated by the file type)
1570# return an img tag, otherwise nothing
1571
# spent 96µs within Foswiki::Render::_isImageLink which was called 22 times, avg 4µs/call: # 22 times (96µs+0s) by Foswiki::Render::_handleSquareBracketedLink at line 1499, avg 4µs/call
sub _isImageLink {
15722211µs my ( $this, $url ) = @_;
1573
15742216µs return if $url =~ m/<nop>/;
15752213µs $url =~ s/^\s+//;
15762220µs $url =~ s/\s+$//;
1577229µs if ( $url =~ m#^https?://[^?]*\.(?:gif|jpg|jpeg|png)$#i ) {
1578 my $filename = $url;
1579 $filename =~ s@.*/@@;
1580 return CGI::img( { src => $url, alt => $filename } );
1581 }
15822259µs return;
1583}
1584
1585# Handle an external link typed directly into text. If it's an image
1586# and no text is specified, then use an img tag, otherwise generate a link.
1587
# spent 34µs within Foswiki::Render::_externalLink which was called 4 times, avg 8µs/call: # 4 times (34µs+0s) by Foswiki::Render::_handleSquareBracketedLink at line 1507, avg 8µs/call
sub _externalLink {
158845µs my ( $this, $url, $text ) = @_;
1589
15904900ns if ( !$text && ( my $img = $this->_isImageLink($url) ) ) {
1591 return $img;
1592 }
159342µs my $opt = '';
159444µs if ( $url =~ m/^mailto:/i ) {
1595 if ( $Foswiki::cfg{AntiSpam}{EmailPadding} ) {
1596 $url =~ s/(\@[\w\_\-\+]+)(\.)
1597 /$1$Foswiki::cfg{AntiSpam}{EmailPadding}$2/x;
1598 if ($text) {
1599 $text =~ s/(\@[\w\_\-\+]+)(\.)
1600 /$1$Foswiki::cfg{AntiSpam}{EmailPadding}$2/x;
1601 }
1602 }
1603 if ( $Foswiki::cfg{AntiSpam}{EntityEncode} ) {
1604
1605 # Much harder obfuscation scheme. For link text we only encode '@'
1606 # See also http://develop.twiki.org/~twiki4/cgi-bin/view/Bugs/Item2928
1607 # and http://develop.twiki.org/~twiki4/cgi-bin/view/Bugs/Item3430
1608 # before touching this
1609 # Note: & is already encoded, so don't encode any entities
1610 # See http://foswiki.org/Tasks/Item10905
1611 $url =~ s/&(\w+);/$REMARKER$1$REEND/g; # "&abc;"
1612 $url =~ s/&(#x?[0-9a-f]+);/$REMARKER$1$REEND/gi; # "&#123;"
1613 $url =~ s/([^\w$REMARKER$REEND])/'&#'.ord($1).';'/ge;
1614 $url =~ s/$REMARKER(#x?[0-9a-f]+)$REEND/&$1;/goi;
1615 $url =~ s/$REMARKER(\w+)$REEND/&$1;/go;
1616 if ($text) {
1617 $text =~ s/\@/'&#'.ord('@').';'/ge;
1618 }
1619 }
1620 }
16214800ns $text ||= $url;
1622
1623 # Item5787: if a URL has spaces, escape them so the URL has less
1624 # chance of being broken by later rendering.
162544µs $url =~ s/ /%20/g;
1626
1627 # SMELL: Can't use CGI::a here, because it encodes ampersands in
1628 # the link, and those have already been encoded once in the
1629 # rendering loop (they are identified as "stand-alone"). One
1630 # encoding works; two is too many. None would be better for everyone!
1631421µs return '<a href="' . $url . '"' . $opt . '>' . $text . '</a>';
1632}
1633
1634# Generate a "mailTo" link
1635sub _mailLink {
1636 my ( $this, $text ) = @_;
1637
1638 my $url = $text;
1639 return $text if $url =~ m/^(?:!|\<nop\>)/;
1640
1641#use Email::Valid ();
1642#my $tmpEmail = $url;
1643#$tmpEmail =~ s/^mailto://;
1644#my $errtxt = '';
1645#$errtxt = "<b>INVALID</b> $tmpEmail " unless (Email::Valid->address($tmpEmail));
1646
1647 # Any special characters in the user portion must be %hex escaped.
1648 $url =~
1649s/^((?:mailto\:)?)?(.*?)(@.*?)$/'mailto:'._escapeMailAddress( $2 ).$3/msie;
1650 my $lenLeft = length($2);
1651 my $lenRight = length($3);
1652
1653 # Per RFC 3696 Errata, length restricted to 254 overall
1654 # per RFC 2821 RCPT limits
1655 return $text
1656 if ( $lenLeft > 64 || $lenRight > 254 || $lenLeft + $lenRight > 254 );
1657
1658 $url = 'mailto:' . $url unless $url =~ m/^mailto:/i;
1659 return _externalLink( $this, $url, $text );
1660}
1661
1662sub _escapeMailAddress {
1663 my $txt = shift;
1664 $txt =~ s/([<>#"%'{}\|\\\^~`\?&=]|\s)/sprintf('%%%02x', ord($1))/ge;
1665 return $txt;
1666}
1667
1668# Adjust heading levels
1669# <h off="1"> will increase the indent level by 1
1670# <h off="-1"> will decrease the indent level by 1
1671
# spent 666µs within Foswiki::Render::_adjustH which was called 5 times, avg 133µs/call: # 5 times (666µs+0s) by Foswiki::Render::getRenderedVersion at line 565, avg 133µs/call
sub _adjustH {
1672512µs my ($text) = @_;
1673
16745631µs my @blocks = split( /(<ho(?:\s+off="(?:[-+]?\d+)")?\s*\/?>)/i, $text );
1675
1676528µs return $text unless scalar(@blocks) > 1;
1677
1678 sub _cap {
1679 return 1 if ( $_[0] < 1 );
1680 return 6 if ( $_[0] > 6 );
1681 return $_[0];
1682 }
1683
1684 my $off = 0;
1685 my $out = '';
1686 while ( scalar(@blocks) ) {
1687 my $i = shift(@blocks);
1688 if ( $i =~ m/^<ho(?:\s+off="([-+]?\d+)")?\s*\/?>$/i && $1 ) {
1689 $off += $1;
1690 }
1691 else {
1692 $i =~ s/(<\/?h)(\d)((\s+.*?)?>)/$1 . _cap($2 + $off) . $3/gesi
1693 if ($off);
1694 $out .= $i;
1695 }
1696 }
1697 return $out;
1698}
1699
1700# _takeOutProtected( \$text, $re, $id, \%map ) -> $text
1701#
1702# * =$text= - Text to process
1703# * =$re= - Regular expression that matches tag expressions to remove
1704# * =\%map= - Reference to a hash to contain the removed blocks
1705#
1706# Return value: $text with blocks removed. Unlike takeOuBlocks, this
1707# *preserves* the tags.
1708#
1709# used to extract from $text comment type tags like &lt;!DOCTYPE blah>
1710#
1711# WARNING: if you want to take out &lt;!-- comments --> you _will_ need
1712# to re-write all the takeOuts to use a different placeholder
1713
# spent 3.40ms (3.26+137µs) within Foswiki::Render::_takeOutProtected which was called 35 times, avg 97µs/call: # 5 times (639µs+9µs) by Foswiki::Render::getRenderedVersion at line 237, avg 130µs/call # 5 times (558µs+90µs) by Foswiki::Render::getRenderedVersion at line 245, avg 130µs/call # 5 times (568µs+7µs) by Foswiki::Render::getRenderedVersion at line 240, avg 115µs/call # 5 times (513µs+0s) by Foswiki::Render::getRenderedVersion at line 243, avg 103µs/call # 5 times (443µs+23µs) by Foswiki::Render::getRenderedVersion at line 314, avg 93µs/call # 5 times (417µs+9µs) by Foswiki::Render::getRenderedVersion at line 248, avg 85µs/call # 5 times (123µs+0s) by Foswiki::Render::getRenderedVersion at line 234, avg 25µs/call
sub _takeOutProtected {
17143535µs my ( $this, $intext, $re, $id, $map ) = @_;
1715
1716673.12ms32138µs $intext =~ s/($re)/_replaceBlock($1, $id, $map)/ge;
# spent 138µs making 32 calls to Foswiki::Render::_replaceBlock, avg 4µs/call
1717
171835130µs return $intext;
1719}
1720
1721
# spent 138µs within Foswiki::Render::_replaceBlock which was called 32 times, avg 4µs/call: # 32 times (138µs+0s) by Foswiki::Render::_takeOutProtected at line 1716, avg 4µs/call
sub _replaceBlock {
17223229µs my ( $scoop, $id, $map ) = @_;
1723326µs my $placeholder = $placeholderMarker;
1724323µs $placeholderMarker++;
17253252µs $map->{ $id . $placeholder }{text} = $scoop;
1726
17273283µs return '<!--' . $REMARKER . $id . $placeholder . $REMARKER . '-->';
1728}
1729
1730# _putBackProtected( \$text, $id, \%map, $callback ) -> $text
1731# Return value: $text with blocks added back
1732# * =\$text= - reference to text to process
1733# * =$id= - type of taken-out block e.g. 'verbatim'
1734# * =\%map= - map placeholders to blocks removed by takeOutBlocks
1735# * =$callback= - Reference to function to call on each block being inserted (optional)
1736#
1737#Reverses the actions of takeOutProtected.
1738
# spent 636µs within Foswiki::Render::_putBackProtected which was called 35 times, avg 18µs/call: # 5 times (299µs+0s) by Foswiki::Render::getRenderedVersion at line 556, avg 60µs/call # 5 times (169µs+0s) by Foswiki::Render::getRenderedVersion at line 542, avg 34µs/call # 5 times (81µs+0s) by Foswiki::Render::getRenderedVersion at line 555, avg 16µs/call # 5 times (34µs+0s) by Foswiki::Render::getRenderedVersion at line 562, avg 7µs/call # 5 times (28µs+0s) by Foswiki::Render::getRenderedVersion at line 561, avg 6µs/call # 5 times (16µs+0s) by Foswiki::Render::getRenderedVersion at line 558, avg 3µs/call # 5 times (10µs+0s) by Foswiki::Render::getRenderedVersion at line 563, avg 2µs/call
sub _putBackProtected {
17393521µs my ( $this, $text, $id, $map, $callback ) = @_;
1740 ASSERT( ref($map) eq 'HASH' ) if DEBUG;
1741
174235153µs foreach my $placeholder ( keys %$map ) {
1743174147µs next unless $placeholder =~ m/^$id\d+$/;
17443221µs my $val = $map->{$placeholder}{text};
1745324µs $val = &$callback($val) if ( defined($callback) );
174632310µs $$text =~ s/<!--$REMARKER$placeholder$REMARKER-->/$val/;
17473236µs delete( $map->{$placeholder} );
1748 }
1749}
1750
175116µs1;
1752__END__