Removed remaining profile calls
[lhc/web/wiklou.git] / includes / parser / Parser.php
index 07eb340..fcdf68c 100644 (file)
@@ -79,7 +79,6 @@ class Parser {
        const HALF_PARSED_VERSION = 2;
 
        # Flags for Parser::setFunctionHook
-       # Also available as global constants from Defines.php
        const SFH_NO_HASH = 1;
        const SFH_OBJECT_ARGS = 2;
 
@@ -91,6 +90,9 @@ class Parser {
        const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)([^][<>"\\x00-\\x20\\x7F\p{Zs}]+)
                \\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sxu';
 
+       # Regular expression for a non-newline space
+       const SPACE_NOT_NL = '(?:\t|&nbsp;|&\#0*160;|&\#[Xx]0*[Aa]0;|\p{Zs})';
+
        # State constants for the definition list colon extraction
        const COLON_STATE_TEXT = 0;
        const COLON_STATE_TAG = 1;
@@ -144,7 +146,8 @@ class Parser {
         * @var MagicWordArray
         */
        public $mSubstWords;
-       public $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols; # Initialised in constructor
+       # Initialised in constructor
+       public $mConf, $mPreprocessor, $mExtLinkBracketedRegex, $mUrlProtocols;
 
        # Cleared with clearState():
        /**
@@ -284,7 +287,7 @@ class Parser {
                        unset( $tmp );
                }
 
-               wfRunHooks( 'ParserCloned', array( $this ) );
+               Hooks::run( 'ParserCloned', array( $this ) );
        }
 
        /**
@@ -296,14 +299,12 @@ class Parser {
                }
                $this->mFirstCall = false;
 
-               wfProfileIn( __METHOD__ );
 
                CoreParserFunctions::register( $this );
                CoreTagHooks::register( $this );
                $this->initialiseVariables();
 
-               wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
-               wfProfileOut( __METHOD__ );
+               Hooks::run( 'ParserFirstCallInit', array( &$this ) );
        }
 
        /**
@@ -312,7 +313,6 @@ class Parser {
         * @private
         */
        public function clearState() {
-               wfProfileIn( __METHOD__ );
                if ( $this->mFirstCall ) {
                        $this->firstCallInit();
                }
@@ -370,8 +370,7 @@ class Parser {
 
                $this->mProfiler = new SectionProfiler();
 
-               wfRunHooks( 'ParserClearState', array( &$this ) );
-               wfProfileOut( __METHOD__ );
+               Hooks::run( 'ParserClearState', array( &$this ) );
        }
 
        /**
@@ -396,8 +395,6 @@ class Parser {
 
                global $wgShowHostnames;
                $fname = __METHOD__ . '-' . wfGetCaller();
-               wfProfileIn( __METHOD__ );
-               wfProfileIn( $fname );
 
                if ( $clearState ) {
                        $magicScopeVariable = $this->lock();
@@ -429,11 +426,11 @@ class Parser {
                        $this->mRevisionSize = null;
                }
 
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
                # No more strip!
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->internalParse( $text );
-               wfRunHooks( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
 
                $text = $this->internalParseHalfParsed( $text, true, $linestart );
 
@@ -499,14 +496,14 @@ class Parser {
                        $this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
                                array( $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() )
                        );
-                       wfRunHooks( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
+                       Hooks::run( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
 
                        $limitReport = "NewPP limit report\n";
                        if ( $wgShowHostnames ) {
                                $limitReport .= 'Parsed by ' . wfHostname() . "\n";
                        }
                        foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
-                               if ( wfRunHooks( 'ParserLimitReportFormat',
+                               if ( Hooks::run( 'ParserLimitReportFormat',
                                        array( $key, &$value, &$limitReport, false, false )
                                ) ) {
                                        $keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
@@ -524,7 +521,7 @@ class Parser {
                        // Since we're not really outputting HTML, decode the entities and
                        // then re-encode the things that need hiding inside HTML comments.
                        $limitReport = htmlspecialchars_decode( $limitReport );
-                       wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) );
+                       Hooks::run( 'ParserLimitReport', array( $this, &$limitReport ) );
 
                        // Sanitize for comment. Note '‐' in the replacement is U+2010,
                        // which looks much like the problematic '-'.
@@ -533,14 +530,14 @@ class Parser {
 
                        // Add on template profiling data
                        $dataByFunc = $this->mProfiler->getFunctionStats();
-                       uasort( $dataByFunc, function( $a, $b ) {
+                       uasort( $dataByFunc, function ( $a, $b ) {
                                return $a['real'] < $b['real']; // descending order
                        } );
                        $profileReport = "Transclusion expansion time report (%,ms,calls,template)\n";
                        foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
                                $profileReport .= sprintf( "%6.2f%% %8.3f %6d - %s\n",
                                        $item['%real'], $item['real'], $item['calls'],
-                                       htmlspecialchars($item['name'] ) );
+                                       htmlspecialchars( $item['name'] ) );
                        }
                        $text .= "\n<!-- \n$profileReport-->\n";
 
@@ -558,8 +555,6 @@ class Parser {
                $this->mRevisionSize = $oldRevisionSize;
                $this->mInputSize = false;
                $this->currentRevisionCache = null;
-               wfProfileOut( $fname );
-               wfProfileOut( __METHOD__ );
 
                return $this->mOutput;
        }
@@ -587,11 +582,9 @@ class Parser {
         * @return string UNSAFE half-parsed HTML
         */
        public function recursiveTagParse( $text, $frame = false ) {
-               wfProfileIn( __METHOD__ );
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->internalParse( $text, false, $frame );
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -613,10 +606,8 @@ class Parser {
         * @return string Fully parsed HTML
         */
        public function recursiveTagParseFully( $text, $frame = false ) {
-               wfProfileIn( __METHOD__ );
                $text = $this->recursiveTagParse( $text, $frame );
                $text = $this->internalParseHalfParsed( $text, false );
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -631,18 +622,18 @@ class Parser {
         * @param bool|PPFrame $frame
         * @return mixed|string
         */
-       public function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null, $frame = false ) {
-               wfProfileIn( __METHOD__ );
+       public function preprocess( $text, Title $title = null,
+               ParserOptions $options, $revid = null, $frame = false
+       ) {
                $magicScopeVariable = $this->lock();
                $this->startParse( $title, $options, self::OT_PREPROCESS, true );
                if ( $revid !== null ) {
                        $this->mRevisionId = $revid;
                }
-               wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
-               wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
                $text = $this->replaceVariables( $text, $frame );
                $text = $this->mStripState->unstripBoth( $text );
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -656,10 +647,8 @@ class Parser {
         * @since 1.19
         */
        public function recursivePreprocess( $text, $frame = false ) {
-               wfProfileIn( __METHOD__ );
                $text = $this->replaceVariables( $text, $frame );
                $text = $this->mStripState->unstripBoth( $text );
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -1014,7 +1003,6 @@ class Parser {
         * @return string
         */
        public function doTableStuff( $text ) {
-               wfProfileIn( __METHOD__ );
 
                $lines = StringUtils::explode( "\n", $text );
                $out = '';
@@ -1201,7 +1189,6 @@ class Parser {
                        $out = '';
                }
 
-               wfProfileOut( __METHOD__ );
 
                return $out;
        }
@@ -1219,13 +1206,11 @@ class Parser {
         * @return string
         */
        public function internalParse( $text, $isMain = true, $frame = false ) {
-               wfProfileIn( __METHOD__ );
 
                $origText = $text;
 
                # Hook to suspend the parser in this state
-               if ( !wfRunHooks( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
-                       wfProfileOut( __METHOD__ );
+               if ( !Hooks::run( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
                        return $text;
                }
 
@@ -1245,14 +1230,14 @@ class Parser {
                        $text = $this->replaceVariables( $text );
                }
 
-               wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
                $text = Sanitizer::removeHTMLtags(
                        $text,
                        array( &$this, 'attributeStripCallback' ),
                        false,
                        array_keys( $this->mTransparentTagHooks )
                );
-               wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
+               Hooks::run( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
 
                # Tables need to come after variable replacement for things to work
                # properly; putting them before other transformations should keep
@@ -1276,7 +1261,6 @@ class Parser {
                $text = $this->doMagicLinks( $text );
                $text = $this->formatHeadings( $text, $origText, $isMain );
 
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -1330,7 +1314,7 @@ class Parser {
                $text = $this->mStripState->unstripNoWiki( $text );
 
                if ( $isMain ) {
-                       wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
+                       Hooks::run( 'ParserBeforeTidy', array( &$this, &$text ) );
                }
 
                $text = $this->replaceTransparentTags( $text );
@@ -1369,7 +1353,7 @@ class Parser {
                }
 
                if ( $isMain ) {
-                       wfRunHooks( 'ParserAfterTidy', array( &$this, &$text ) );
+                       Hooks::run( 'ParserAfterTidy', array( &$this, &$text ) );
                }
 
                return $text;
@@ -1387,22 +1371,24 @@ class Parser {
         * @return string
         */
        public function doMagicLinks( $text ) {
-               wfProfileIn( __METHOD__ );
                $prots = wfUrlProtocolsWithoutProtRel();
                $urlChar = self::EXT_LINK_URL_CLASS;
+               $space = self::SPACE_NOT_NL; #  non-newline space
+               $spdash = "(?:-|$space)"; # a dash or a non-newline space
+               $spaces = "$space++"; # possessive match of 1 or more spaces
                $text = preg_replace_callback(
                        '!(?:                           # Start cases
                                (<a[ \t\r\n>].*?</a>) |     # m[1]: Skip link text
                                (<.*?>) |                   # m[2]: Skip stuff inside HTML elements' . "
-                               (\\b(?i:$prots)$urlChar+) |  # m[3]: Free external links" . '
-                               (?:RFC|PMID)\s+([0-9]+) |   # m[4]: RFC or PMID, capture number
-                               ISBN\s+(\b                  # m[5]: ISBN, capture number
-                                       (?: 97[89] [\ \-]? )?   # optional 13-digit ISBN prefix
-                                       (?: [0-9]  [\ \-]? ){9} # 9 digits with opt. delimiters
+                               (\b(?i:$prots)$urlChar+) |  # m[3]: Free external links
+                               \b(?:RFC|PMID) $spaces      # m[4]: RFC or PMID, capture number
+                                       ([0-9]+)\b |
+                               \bISBN $spaces (            # m[5]: ISBN, capture number
+                                       (?: 97[89] $spdash? )?   # optional 13-digit ISBN prefix
+                                       (?: [0-9]  $spdash? ){9} # 9 digits with opt. delimiters
                                        [0-9Xx]                 # check digit
-                                       \b)
-                       )!xu', array( &$this, 'magicLinkCallback' ), $text );
-               wfProfileOut( __METHOD__ );
+                               )\b
+                       )!xu", array( &$this, 'magicLinkCallback' ), $text );
                return $text;
        }
 
@@ -1442,6 +1428,8 @@ class Parser {
                } elseif ( isset( $m[5] ) && $m[5] !== '' ) {
                        # ISBN
                        $isbn = $m[5];
+                       $space = self::SPACE_NOT_NL; #  non-newline space
+                       $isbn = preg_replace( "/$space/", ' ', $isbn );
                        $num = strtr( $isbn, array(
                                '-' => '',
                                ' ' => '',
@@ -1465,7 +1453,6 @@ class Parser {
         * @private
         */
        public function makeFreeExternalLink( $url ) {
-               wfProfileIn( __METHOD__ );
 
                $trail = '';
 
@@ -1485,7 +1472,20 @@ class Parser {
                        $sep .= ')';
                }
 
-               $numSepChars = strspn( strrev( $url ), $sep );
+               $urlRev = strrev( $url );
+               $numSepChars = strspn( $urlRev, $sep );
+               # Don't break a trailing HTML entity by moving the ; into $trail
+               # This is in hot code, so use substr_compare to avoid having to
+               # create a new string object for the comparison
+               if ( $numSepChars && substr_compare( $url, ";", -$numSepChars, 1 ) === 0) {
+                       # more optimization: instead of running preg_match with a $
+                       # anchor, which can be slow, do the match on the reversed
+                       # string starting at the desired offset.
+                       # un-reversed regexp is: /&([a-z]+|#x[\da-f]+|#\d+)$/i
+                       if ( preg_match( '/\G([a-z]+|[\da-f]+x#|\d+#)&/i', $urlRev, $m2, 0, $numSepChars ) ) {
+                               $numSepChars--;
+                       }
+               }
                if ( $numSepChars ) {
                        $trail = substr( $url, -$numSepChars ) . $trail;
                        $url = substr( $url, 0, -$numSepChars );
@@ -1506,7 +1506,6 @@ class Parser {
                        $pasteurized = self::normalizeLinkUrl( $url );
                        $this->mOutput->addExternalLink( $pasteurized );
                }
-               wfProfileOut( __METHOD__ );
                return $text . $trail;
        }
 
@@ -1520,12 +1519,10 @@ class Parser {
         * @return string
         */
        public function doHeadings( $text ) {
-               wfProfileIn( __METHOD__ );
                for ( $i = 6; $i >= 1; --$i ) {
                        $h = str_repeat( '=', $i );
                        $text = preg_replace( "/^$h(.+)$h\\s*$/m", "<h$i>\\1</h$i>", $text );
                }
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -1538,14 +1535,12 @@ class Parser {
         * @return string The altered text
         */
        public function doAllQuotes( $text ) {
-               wfProfileIn( __METHOD__ );
                $outtext = '';
                $lines = StringUtils::explode( "\n", $text );
                foreach ( $lines as $line ) {
                        $outtext .= $this->doQuotes( $line ) . "\n";
                }
                $outtext = substr( $outtext, 0, -1 );
-               wfProfileOut( __METHOD__ );
                return $outtext;
        }
 
@@ -1747,11 +1742,9 @@ class Parser {
         * @return string
         */
        public function replaceExternalLinks( $text ) {
-               wfProfileIn( __METHOD__ );
 
                $bits = preg_split( $this->mExtLinkBracketedRegex, $text, -1, PREG_SPLIT_DELIM_CAPTURE );
                if ( $bits === false ) {
-                       wfProfileOut( __METHOD__ );
                        throw new MWException( "PCRE needs to be compiled with "
                                . "--enable-unicode-properties in order for MediaWiki to function" );
                }
@@ -1815,7 +1808,6 @@ class Parser {
                        $this->mOutput->addExternalLink( $pasteurized );
                }
 
-               wfProfileOut( __METHOD__ );
                return $s;
        }
 
@@ -2013,9 +2005,7 @@ class Parser {
         */
        public function replaceInternalLinks2( &$s ) {
                global $wgExtraInterlanguageLinkPrefixes;
-               wfProfileIn( __METHOD__ );
 
-               wfProfileIn( __METHOD__ . '-setup' );
                static $tc = false, $e1, $e1_img;
                # the % is needed to support urlencoded titles as well
                if ( !$tc ) {
@@ -2047,8 +2037,6 @@ class Parser {
                }
 
                if ( is_null( $this->mTitle ) ) {
-                       wfProfileOut( __METHOD__ . '-setup' );
-                       wfProfileOut( __METHOD__ );
                        throw new MWException( __METHOD__ . ": \$this->mTitle is null\n" );
                }
                $nottalk = !$this->mTitle->isTalkPage();
@@ -2065,7 +2053,6 @@ class Parser {
                }
 
                $useSubpages = $this->areSubpagesAllowed();
-               wfProfileOut( __METHOD__ . '-setup' );
 
                // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
                # Loop for each link
@@ -2081,7 +2068,6 @@ class Parser {
                        }
 
                        if ( $useLinkPrefixExtension ) {
-                               wfProfileIn( __METHOD__ . '-prefixhandling' );
                                if ( preg_match( $e2, $s, $m ) ) {
                                        $prefix = $m[2];
                                        $s = $m[1];
@@ -2093,12 +2079,10 @@ class Parser {
                                        $prefix = $first_prefix;
                                        $first_prefix = false;
                                }
-                               wfProfileOut( __METHOD__ . '-prefixhandling' );
                        }
 
                        $might_be_img = false;
 
-                       wfProfileIn( __METHOD__ . "-e1" );
                        if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt
                                $text = $m[2];
                                # If we get a ] at the beginning of $m[3] that means we have a link that's something like:
@@ -2132,11 +2116,8 @@ class Parser {
                                $trail = "";
                        } else { # Invalid form; output directly
                                $s .= $prefix . '[[' . $line;
-                               wfProfileOut( __METHOD__ . "-e1" );
                                continue;
                        }
-                       wfProfileOut( __METHOD__ . "-e1" );
-                       wfProfileIn( __METHOD__ . "-misc" );
 
                        $origLink = $m[1];
 
@@ -2145,7 +2126,6 @@ class Parser {
                        # should be external links.
                        if ( preg_match( '/^(?i:' . $this->mUrlProtocols . ')/', $origLink ) ) {
                                $s .= $prefix . '[[' . $line;
-                               wfProfileOut( __METHOD__ . "-misc" );
                                continue;
                        }
 
@@ -2162,21 +2142,16 @@ class Parser {
                                $link = substr( $link, 1 );
                        }
 
-                       wfProfileOut( __METHOD__ . "-misc" );
-                       wfProfileIn( __METHOD__ . "-title" );
                        $nt = Title::newFromText( $this->mStripState->unstripNoWiki( $link ) );
                        if ( $nt === null ) {
                                $s .= $prefix . '[[' . $line;
-                               wfProfileOut( __METHOD__ . "-title" );
                                continue;
                        }
 
                        $ns = $nt->getNamespace();
                        $iw = $nt->getInterwiki();
-                       wfProfileOut( __METHOD__ . "-title" );
 
                        if ( $might_be_img ) { # if this is actually an invalid link
-                               wfProfileIn( __METHOD__ . "-might_be_img" );
                                if ( $ns == NS_FILE && $noforce ) { # but might be an image
                                        $found = false;
                                        while ( true ) {
@@ -2208,16 +2183,13 @@ class Parser {
                                                $holders->merge( $this->replaceInternalLinks2( $text ) );
                                                $s .= "{$prefix}[[$link|$text";
                                                # note: no $trail, because without an end, there *is* no trail
-                                               wfProfileOut( __METHOD__ . "-might_be_img" );
                                                continue;
                                        }
                                } else { # it's not an image, so output it raw
                                        $s .= "{$prefix}[[$link|$text";
                                        # note: no $trail, because without an end, there *is* no trail
-                                       wfProfileOut( __METHOD__ . "-might_be_img" );
                                        continue;
                                }
-                               wfProfileOut( __METHOD__ . "-might_be_img" );
                        }
 
                        $wasblank = ( $text == '' );
@@ -2234,7 +2206,6 @@ class Parser {
                        # Link not escaped by : , create the various objects
                        if ( $noforce && !$nt->wasLocalInterwiki() ) {
                                # Interwikis
-                               wfProfileIn( __METHOD__ . "-interwiki" );
                                if (
                                        $iw && $this->mOptions->getInterwikiMagic() && $nottalk && (
                                                Language::fetchLanguageName( $iw, null, 'mw' ) ||
@@ -2249,13 +2220,10 @@ class Parser {
 
                                        $s = rtrim( $s . $prefix );
                                        $s .= trim( $trail, "\n" ) == '' ? '': $prefix . $trail;
-                                       wfProfileOut( __METHOD__ . "-interwiki" );
                                        continue;
                                }
-                               wfProfileOut( __METHOD__ . "-interwiki" );
 
                                if ( $ns == NS_FILE ) {
-                                       wfProfileIn( __METHOD__ . "-image" );
                                        if ( !wfIsBadImage( $nt->getDBkey(), $this->mTitle ) ) {
                                                if ( $wasblank ) {
                                                        # if no parameters were passed, $text
@@ -2276,12 +2244,10 @@ class Parser {
                                        } else {
                                                $s .= $prefix . $trail;
                                        }
-                                       wfProfileOut( __METHOD__ . "-image" );
                                        continue;
                                }
 
                                if ( $ns == NS_CATEGORY ) {
-                                       wfProfileIn( __METHOD__ . "-category" );
                                        $s = rtrim( $s . "\n" ); # bug 87
 
                                        if ( $wasblank ) {
@@ -2299,7 +2265,6 @@ class Parser {
                                         */
                                        $s .= trim( $prefix . $trail, "\n" ) == '' ? '' : $prefix . $trail;
 
-                                       wfProfileOut( __METHOD__ . "-category" );
                                        continue;
                                }
                        }
@@ -2315,22 +2280,19 @@ class Parser {
                        # NS_MEDIA is a pseudo-namespace for linking directly to a file
                        # @todo FIXME: Should do batch file existence checks, see comment below
                        if ( $ns == NS_MEDIA ) {
-                               wfProfileIn( __METHOD__ . "-media" );
                                # Give extensions a chance to select the file revision for us
                                $options = array();
                                $descQuery = false;
-                               wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                               Hooks::run( 'BeforeParserFetchFileAndTitle',
                                        array( $this, $nt, &$options, &$descQuery ) );
                                # Fetch and register the file (file title may be different via hooks)
                                list( $file, $nt ) = $this->fetchFileAndTitle( $nt, $options );
                                # Cloak with NOPARSE to avoid replacement in replaceExternalLinks
                                $s .= $prefix . $this->armorLinks(
                                        Linker::makeMediaLinkFile( $nt, $file, $text ) ) . $trail;
-                               wfProfileOut( __METHOD__ . "-media" );
                                continue;
                        }
 
-                       wfProfileIn( __METHOD__ . "-always_known" );
                        # Some titles, such as valid special pages or files in foreign repos, should
                        # be shown as bluelinks even though they're not included in the page table
                        #
@@ -2343,9 +2305,7 @@ class Parser {
                                # Links will be added to the output link list after checking
                                $s .= $holders->makeHolder( $nt, $text, array(), $trail, $prefix );
                        }
-                       wfProfileOut( __METHOD__ . "-always_known" );
                }
-               wfProfileOut( __METHOD__ );
                return $holders;
        }
 
@@ -2544,7 +2504,6 @@ class Parser {
         * @return string The lists rendered as HTML
         */
        public function doBlockLevels( $text, $linestart ) {
-               wfProfileIn( __METHOD__ );
 
                # Parsing through the text line by line.  The main thing
                # happening here is handling of block-level elements p, pre,
@@ -2653,7 +2612,6 @@ class Parser {
 
                        # If we have no prefixes, go to paragraph mode.
                        if ( 0 == $prefixLength ) {
-                               wfProfileIn( __METHOD__ . "-paragraph" );
                                # No prefix (not in list)--go to paragraph mode
                                # XXX: use a stack for nestable elements like span, table and div
                                $openmatch = preg_match(
@@ -2722,7 +2680,6 @@ class Parser {
                                                }
                                        }
                                }
-                               wfProfileOut( __METHOD__ . "-paragraph" );
                        }
                        # somewhere above we forget to get out of pre block (bug 785)
                        if ( $preCloseMatch && $this->mInPre ) {
@@ -2747,7 +2704,6 @@ class Parser {
                        $this->mLastSection = '';
                }
 
-               wfProfileOut( __METHOD__ );
                return $output;
        }
 
@@ -2762,12 +2718,10 @@ class Parser {
         * @return string The position of the ':', or false if none found
         */
        public function findColonNoLinks( $str, &$before, &$after ) {
-               wfProfileIn( __METHOD__ );
 
                $pos = strpos( $str, ':' );
                if ( $pos === false ) {
                        # Nothing to find!
-                       wfProfileOut( __METHOD__ );
                        return false;
                }
 
@@ -2776,7 +2730,6 @@ class Parser {
                        # Easy; no tag nesting to worry about
                        $before = substr( $str, 0, $pos );
                        $after = substr( $str, $pos + 1 );
-                       wfProfileOut( __METHOD__ );
                        return $pos;
                }
 
@@ -2800,7 +2753,6 @@ class Parser {
                                                # We found it!
                                                $before = substr( $str, 0, $i );
                                                $after = substr( $str, $i + 1 );
-                                               wfProfileOut( __METHOD__ );
                                                return $i;
                                        }
                                        # Embedded in a tag; don't break it.
@@ -2810,7 +2762,6 @@ class Parser {
                                        $colon = strpos( $str, ':', $i );
                                        if ( $colon === false ) {
                                                # Nothing else interesting
-                                               wfProfileOut( __METHOD__ );
                                                return false;
                                        }
                                        $lt = strpos( $str, '<', $i );
@@ -2819,7 +2770,6 @@ class Parser {
                                                        # We found it!
                                                        $before = substr( $str, 0, $colon );
                                                        $after = substr( $str, $colon + 1 );
-                                                       wfProfileOut( __METHOD__ );
                                                        return $i;
                                                }
                                        }
@@ -2870,7 +2820,6 @@ class Parser {
                                        $stack--;
                                        if ( $stack < 0 ) {
                                                wfDebug( __METHOD__ . ": Invalid input; too many close tags\n" );
-                                               wfProfileOut( __METHOD__ );
                                                return false;
                                        }
                                        $state = self::COLON_STATE_TEXT;
@@ -2905,16 +2854,13 @@ class Parser {
                                }
                                break;
                        default:
-                               wfProfileOut( __METHOD__ );
                                throw new MWException( "State machine error in " . __METHOD__ );
                        }
                }
                if ( $stack > 0 ) {
                        wfDebug( __METHOD__ . ": Invalid input; not enough close tags (stack $stack, state $state)\n" );
-                       wfProfileOut( __METHOD__ );
                        return false;
                }
-               wfProfileOut( __METHOD__ );
                return false;
        }
 
@@ -2946,14 +2892,14 @@ class Parser {
                 * Some of these require message or data lookups and can be
                 * expensive to check many times.
                 */
-               if ( wfRunHooks( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
+               if ( Hooks::run( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
                        if ( isset( $this->mVarCache[$index] ) ) {
                                return $this->mVarCache[$index];
                        }
                }
 
                $ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
-               wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
+               Hooks::run( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
 
                $pageLang = $this->getFunctionLang();
 
@@ -3261,7 +3207,7 @@ class Parser {
                                break;
                        default:
                                $ret = null;
-                               wfRunHooks(
+                               Hooks::run(
                                        'ParserGetVariableValueSwitch',
                                        array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
                                );
@@ -3282,13 +3228,11 @@ class Parser {
         * @private
         */
        public function initialiseVariables() {
-               wfProfileIn( __METHOD__ );
                $variableIDs = MagicWord::getVariableIDs();
                $substIDs = MagicWord::getSubstIDs();
 
                $this->mVariables = new MagicWordArray( $variableIDs );
                $this->mSubstWords = new MagicWordArray( $substIDs );
-               wfProfileOut( __METHOD__ );
        }
 
        /**
@@ -3363,7 +3307,6 @@ class Parser {
                if ( strlen( $text ) < 1 || strlen( $text ) > $this->mOptions->getMaxIncludeSize() ) {
                        return $text;
                }
-               wfProfileIn( __METHOD__ );
 
                if ( $frame === false ) {
                        $frame = $this->getPreprocessor()->newFrame();
@@ -3377,7 +3320,6 @@ class Parser {
                $flags = $argsOnly ? PPFrame::NO_TEMPLATES : 0;
                $text = $frame->expand( $dom, $flags );
 
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -3455,8 +3397,6 @@ class Parser {
         * @return string The text of the template
         */
        public function braceSubstitution( $piece, $frame ) {
-               wfProfileIn( __METHOD__ );
-               wfProfileIn( __METHOD__ . '-setup' );
 
                // Flags
 
@@ -3489,12 +3429,10 @@ class Parser {
                # @todo FIXME: If piece['parts'] is null then the call to getLength()
                # below won't work b/c this $args isn't an object
                $args = ( null == $piece['parts'] ) ? array() : $piece['parts'];
-               wfProfileOut( __METHOD__ . '-setup' );
 
                $profileSection = null; // profile templates
 
                # SUBST
-               wfProfileIn( __METHOD__ . '-modifiers' );
                if ( !$found ) {
 
                        $substMatch = $this->mSubstWords->matchStartAndRemove( $part1 );
@@ -3551,11 +3489,9 @@ class Parser {
                                $forceRawInterwiki = true;
                        }
                }
-               wfProfileOut( __METHOD__ . '-modifiers' );
 
                # Parser functions
                if ( !$found ) {
-                       wfProfileIn( __METHOD__ . '-pfunc' );
 
                        $colonPos = strpos( $part1, ':' );
                        if ( $colonPos !== false ) {
@@ -3567,8 +3503,6 @@ class Parser {
                                try {
                                        $result = $this->callParserFunction( $frame, $func, $funcArgs );
                                } catch ( Exception $ex ) {
-                                       wfProfileOut( __METHOD__ . '-pfunc' );
-                                       wfProfileOut( __METHOD__ );
                                        throw $ex;
                                }
 
@@ -3577,7 +3511,6 @@ class Parser {
                                # here.
                                extract( $result );
                        }
-                       wfProfileOut( __METHOD__ . '-pfunc' );
                }
 
                # Finish mangling title and then check for loops.
@@ -3613,7 +3546,6 @@ class Parser {
                # Load from database
                if ( !$found && $title ) {
                        $profileSection = $this->mProfiler->scopedProfileIn( $title->getPrefixedDBkey() );
-                       wfProfileIn( __METHOD__ . '-loadtpl' );
                        if ( !$title->isExternal() ) {
                                if ( $title->isSpecialPage()
                                        && $this->mOptions->getAllowSpecialInclusion()
@@ -3687,7 +3619,6 @@ class Parser {
                                        . '</span>';
                                wfDebug( __METHOD__ . ": template loop broken at '$titleText'\n" );
                        }
-                       wfProfileOut( __METHOD__ . '-loadtpl' );
                }
 
                # If we haven't found text to substitute by now, we're done
@@ -3697,7 +3628,6 @@ class Parser {
                        if ( $profileSection ) {
                                $this->mProfiler->scopedProfileOut( $profileSection );
                        }
-                       wfProfileOut( __METHOD__ );
                        return array( 'object' => $text );
                }
 
@@ -3763,7 +3693,6 @@ class Parser {
                        $ret = array( 'text' => $text );
                }
 
-               wfProfileOut( __METHOD__ );
                return $ret;
        }
 
@@ -3789,7 +3718,6 @@ class Parser {
        public function callParserFunction( $frame, $function, array $args = array() ) {
                global $wgContLang;
 
-               wfProfileIn( __METHOD__ );
 
                # Case sensitive functions
                if ( isset( $this->mFunctionSynonyms[1][$function] ) ) {
@@ -3800,23 +3728,19 @@ class Parser {
                        if ( isset( $this->mFunctionSynonyms[0][$function] ) ) {
                                $function = $this->mFunctionSynonyms[0][$function];
                        } else {
-                               wfProfileOut( __METHOD__ );
                                return array( 'found' => false );
                        }
                }
 
-               wfProfileIn( __METHOD__ . '-pfunc-' . $function );
                list( $callback, $flags ) = $this->mFunctionHooks[$function];
 
                # Workaround for PHP bug 35229 and similar
                if ( !is_callable( $callback ) ) {
-                       wfProfileOut( __METHOD__ . '-pfunc-' . $function );
-                       wfProfileOut( __METHOD__ );
                        throw new MWException( "Tag hook for $function is not callable\n" );
                }
 
                $allArgs = array( &$this );
-               if ( $flags & SFH_OBJECT_ARGS ) {
+               if ( $flags & self::SFH_OBJECT_ARGS ) {
                        # Convert arguments to PPNodes and collect for appending to $allArgs
                        $funcArgs = array();
                        foreach ( $args as $k => $v ) {
@@ -3876,8 +3800,6 @@ class Parser {
                        $result['text'] = $this->preprocessToDom( $result['text'], $preprocessFlags );
                        $result['isChildObj'] = true;
                }
-               wfProfileOut( __METHOD__ . '-pfunc-' . $function );
-               wfProfileOut( __METHOD__ );
 
                return $result;
        }
@@ -4012,7 +3934,7 @@ class Parser {
                for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
                        # Give extensions a chance to select the revision instead
                        $id = false; # Assume current
-                       wfRunHooks( 'BeforeParserFetchTemplateAndtitle',
+                       Hooks::run( 'BeforeParserFetchTemplateAndtitle',
                                array( $parser, $title, &$skip, &$id ) );
 
                        if ( $skip ) {
@@ -4207,7 +4129,6 @@ class Parser {
         * @return array
         */
        public function argSubstitution( $piece, $frame ) {
-               wfProfileIn( __METHOD__ );
 
                $error = false;
                $parts = $piece['parts'];
@@ -4242,7 +4163,6 @@ class Parser {
                        $ret = array( 'text' => $text );
                }
 
-               wfProfileOut( __METHOD__ );
                return $ret;
        }
 
@@ -4373,7 +4293,6 @@ class Parser {
         * @return string
         */
        public function doDoubleUnderscore( $text ) {
-               wfProfileIn( __METHOD__ );
 
                # The position of __TOC__ needs to be recorded
                $mw = MagicWord::get( 'toc' );
@@ -4421,7 +4340,6 @@ class Parser {
                        $this->mOutput->setProperty( $key, '' );
                }
 
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -4615,14 +4533,15 @@ class Parser {
                        # * <sup> and <sub> (bug 8393)
                        # * <i> (bug 26375)
                        # * <b> (r105284)
+                       # * <bdi> (bug 72884)
                        # * <span dir="rtl"> and <span dir="ltr"> (bug 35167)
                        #
                        # We strip any parameter from accepted tags (second regex), except dir="rtl|ltr" from <span>,
                        # to allow setting directionality in toc items.
                        $tocline = preg_replace(
                                array(
-                                       '#<(?!/?(span|sup|sub|i|b)(?: [^>]*)?>).*?' . '>#',
-                                       '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|i|b))(?: .*?)?' . '>#'
+                                       '#<(?!/?(span|sup|sub|bdi|i|b)(?: [^>]*)?>).*?' . '>#',
+                                       '#<(/?(?:span(?: dir="(?:rtl|ltr)")?|sup|sub|bdi|i|b))(?: .*?)?' . '>#'
                                ),
                                array( '', '<$1>' ),
                                $safeHeadline
@@ -4821,7 +4740,7 @@ class Parser {
                         * &$sectionContent : ref to the content of the section
                         * $showEditLinks : boolean describing whether this section has an edit link
                         */
-                       wfRunHooks( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
+                       Hooks::run( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
 
                        $i++;
                }
@@ -4863,6 +4782,7 @@ class Parser {
 
                $pairs = array(
                        "\r\n" => "\n",
+                       "\r" => "\n",
                );
                $text = str_replace( array_keys( $pairs ), array_values( $pairs ), $text );
                if ( $options->getPreSaveTransform() ) {
@@ -5125,7 +5045,6 @@ class Parser {
                }
                $executing = true;
 
-               wfProfileIn( __METHOD__ );
                if ( !$title ) {
                        global $wgTitle;
                        $title = $wgTitle;
@@ -5134,7 +5053,6 @@ class Parser {
                $text = $this->preprocess( $text, $title, $options );
 
                $executing = false;
-               wfProfileOut( __METHOD__ );
                return $text;
        }
 
@@ -5218,7 +5136,7 @@ class Parser {
         * The callback function should have the form:
         *    function myParserFunction( &$parser, $arg1, $arg2, $arg3 ) { ... }
         *
-        * Or with SFH_OBJECT_ARGS:
+        * Or with Parser::SFH_OBJECT_ARGS:
         *    function myParserFunction( $parser, $frame, $args ) { ... }
         *
         * The callback may either return the text result of the function, or an array with the text
@@ -5232,10 +5150,10 @@ class Parser {
         * @param string $id The magic word ID
         * @param callable $callback The callback function (and object) to use
         * @param int $flags A combination of the following flags:
-        *     SFH_NO_HASH   No leading hash, i.e. {{plural:...}} instead of {{#if:...}}
+        *     Parser::SFH_NO_HASH      No leading hash, i.e. {{plural:...}} instead of {{#if:...}}
         *
-        *     SFH_OBJECT_ARGS   Pass the template arguments as PPNode objects instead of text. This
-        *     allows for conditional expansion of the parse tree, allowing you to eliminate dead
+        *     Parser::SFH_OBJECT_ARGS  Pass the template arguments as PPNode objects instead of text.
+        *     This allows for conditional expansion of the parse tree, allowing you to eliminate dead
         *     branches and thus speed up parsing. It is also possible to analyse the parse tree of
         *     the arguments, and to control the way they are expanded.
         *
@@ -5277,7 +5195,7 @@ class Parser {
                                $syn = $wgContLang->lc( $syn );
                        }
                        # Add leading hash
-                       if ( !( $flags & SFH_NO_HASH ) ) {
+                       if ( !( $flags & self::SFH_NO_HASH ) ) {
                                $syn = '#' . $syn;
                        }
                        # Remove trailing colon
@@ -5361,7 +5279,6 @@ class Parser {
         * @return string HTML
         */
        public function renderImageGallery( $text, $params ) {
-               wfProfileIn( __METHOD__ );
 
                $mode = false;
                if ( isset( $params['mode'] ) ) {
@@ -5404,7 +5321,7 @@ class Parser {
                }
                $ig->setAdditionalOptions( $params );
 
-               wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
+               Hooks::run( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
 
                $lines = StringUtils::explode( "\n", $text );
                foreach ( $lines as $line ) {
@@ -5431,13 +5348,12 @@ class Parser {
                        # file (which potentially could be of a different type and have different handler).
                        $options = array();
                        $descQuery = false;
-                       wfRunHooks( 'BeforeParserFetchFileAndTitle',
+                       Hooks::run( 'BeforeParserFetchFileAndTitle',
                                array( $this, $title, &$options, &$descQuery ) );
                        # Don't register it now, as ImageGallery does that later.
                        $file = $this->fetchFileNoRegister( $title, $options );
                        $handler = $file ? $file->getHandler() : false;
 
-                       wfProfileIn( __METHOD__ . '-getMagicWord' );
                        $paramMap = array(
                                'img_alt' => 'gallery-internal-alt',
                                'img_link' => 'gallery-internal-link',
@@ -5450,7 +5366,6 @@ class Parser {
                        }
 
                        $mwArray = new MagicWordArray( array_keys( $paramMap ) );
-                       wfProfileOut( __METHOD__ . '-getMagicWord' );
 
                        $label = '';
                        $alt = '';
@@ -5512,8 +5427,7 @@ class Parser {
                        $ig->add( $title, $label, $alt, $link, $handlerOptions );
                }
                $html = $ig->toHTML();
-               wfRunHooks( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
-               wfProfileOut( __METHOD__ );
+               Hooks::run( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
                return $html;
        }
 
@@ -5601,7 +5515,7 @@ class Parser {
                # Give extensions a chance to select the file revision for us
                $options = array();
                $descQuery = false;
-               wfRunHooks( 'BeforeParserFetchFileAndTitle',
+               Hooks::run( 'BeforeParserFetchFileAndTitle',
                        array( $this, $title, &$options, &$descQuery ) );
                # Fetch and register the file (file title may be different via hooks)
                list( $file, $title ) = $this->fetchFileAndTitle( $title, $options );
@@ -5765,7 +5679,7 @@ class Parser {
                        $params['frame']['title'] = $this->stripAltText( $caption, $holders );
                }
 
-               wfRunHooks( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
+               Hooks::run( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
 
                # Linker does the rest
                $time = isset( $options['time'] ) ? $options['time'] : false;
@@ -6085,7 +5999,6 @@ class Parser {
         */
        public function getRevisionTimestamp() {
                if ( is_null( $this->mRevisionTimestamp ) ) {
-                       wfProfileIn( __METHOD__ );
 
                        global $wgContLang;
 
@@ -6100,7 +6013,6 @@ class Parser {
                        # it needs to be consistent for all visitors.
                        $this->mRevisionTimestamp = $wgContLang->userAdjust( $timestamp, '' );
 
-                       wfProfileOut( __METHOD__ );
                }
                return $this->mRevisionTimestamp;
        }
@@ -6355,14 +6267,12 @@ class Parser {
         * @return array
         */
        public function serializeHalfParsedText( $text ) {
-               wfProfileIn( __METHOD__ );
                $data = array(
                        'text' => $text,
                        'version' => self::HALF_PARSED_VERSION,
                        'stripState' => $this->mStripState->getSubState( $text ),
                        'linkHolders' => $this->mLinkHolders->getSubArray( $text )
                );
-               wfProfileOut( __METHOD__ );
                return $data;
        }