Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
InsertionMode
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
7 / 7
16
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 doctype
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 comment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 error
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 splitInitialMatch
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 handleFramesetWhitespace
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 stripNulls
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 characters
n/a
0 / 0
n/a
0 / 0
0
 startTag
n/a
0 / 0
n/a
0 / 0
0
 endTag
n/a
0 / 0
n/a
0 / 0
0
 endDocument
n/a
0 / 0
n/a
0 / 0
0
1<?php
2
3namespace Wikimedia\RemexHtml\TreeBuilder;
4
5use Wikimedia\RemexHtml\PropGuard;
6use Wikimedia\RemexHtml\Tokenizer\Attributes;
7
8abstract class InsertionMode {
9    use PropGuard;
10
11    /** @var TreeBuilder */
12    protected $builder;
13
14    /** @var Dispatcher */
15    protected $dispatcher;
16
17    public function __construct( TreeBuilder $builder, Dispatcher $dispatcher ) {
18        $this->builder = $builder;
19        $this->dispatcher = $dispatcher;
20    }
21
22    public function doctype( $name, $public, $system, $quirks, $sourceStart, $sourceLength ) {
23        $this->builder->error( "unexpected doctype", $sourceStart );
24    }
25
26    public function comment( $text, $sourceStart, $sourceLength ) {
27        $this->builder->comment( null, $text, $sourceStart, $sourceLength );
28    }
29
30    public function error( $text, $pos ) {
31        $this->builder->error( $text, $pos );
32    }
33
34    protected function splitInitialMatch( $isStartOfToken, $mask, $text, $start, $length,
35        $sourceStart, $sourceLength
36    ) {
37        $matchLength = strspn( $text, $mask, $start, $length );
38        if ( $isStartOfToken && $matchLength ) {
39            // Do some extra work to figure out a plausible start position if
40            // the text node started with <![CDATA[
41            // FIXME: make this optional?
42            $sourceText = $this->builder->tokenizer->getPreprocessedText();
43            $isCdata = substr_compare( $sourceText, '<![CDATA[', $sourceStart, $sourceLength ) === 0;
44            $cdataLength = $isCdata ? strlen( '<![CDATA[' ) : 0;
45        } else {
46            $cdataLength = 0;
47        }
48
49        return [
50            [
51                $start,
52                $matchLength,
53                $sourceStart,
54                $matchLength + $cdataLength,
55            ], [
56                $start + $matchLength,
57                $length - $matchLength,
58                $sourceStart + $matchLength + $cdataLength,
59                $sourceLength - $matchLength - $cdataLength
60            ]
61        ];
62    }
63
64    protected function handleFramesetWhitespace( $inBody, $text, $start, $length,
65        $sourceStart, $sourceLength
66    ) {
67        $isStartOfToken = true;
68        $builder = $this->builder;
69
70        do {
71            [ $part1, $part2 ] = $this->splitInitialMatch(
72                $isStartOfToken, "\t\n\f\r ", $text, $start, $length, $sourceStart, $sourceLength );
73            $isStartOfToken = false;
74
75            [ $start, $length, $sourceStart, $sourceLength ] = $part1;
76            if ( $length ) {
77                if ( $inBody ) {
78                    $this->dispatcher->inBody->characters( $text, $start, $length,
79                        $sourceStart, $sourceLength );
80                } else {
81                    $builder->insertCharacters( $text, $start, $length, $sourceStart, $sourceLength );
82                }
83            }
84
85            [ $start, $length, $sourceStart, $sourceLength ] = $part2;
86            if ( $length ) {
87                $builder->error( "unexpected non-whitespace character", $sourceStart );
88                $start++;
89                $length--;
90                $sourceStart++;
91                $sourceLength--;
92            }
93        } while ( $length > 0 );
94    }
95
96    protected function stripNulls( $callback, $text, $start, $length, $sourceStart, $sourceLength ) {
97        $errorOffset = $sourceStart - $start;
98        while ( $length > 0 ) {
99            $validLength = strcspn( $text, "\0", $start, $length );
100            if ( $validLength ) {
101                $callback( $text, $start, $validLength, $sourceStart, $sourceLength );
102                $start += $validLength;
103                $length -= $validLength;
104            }
105            if ( $length <= 0 ) {
106                break;
107            }
108            $this->error( 'unexpected null character', $start + $errorOffset );
109            $start++;
110            $length--;
111        }
112    }
113
114    abstract public function characters( $text, $start, $length, $sourceStart, $sourceLength );
115
116    abstract public function startTag( $name, Attributes $attrs, $selfClose,
117        $sourceStart, $sourceLength );
118
119    abstract public function endTag( $name, $sourceStart, $sourceLength );
120
121    abstract public function endDocument( $pos );
122}