KD2 Framework  Check-in [545a52d7de]

Overview
Comment:CSSParser: implement caching of nodes, speeds things up to 3 times!
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 545a52d7de7f4280e02955a9204e957215064aff
User & Date: bohwaz on 2023-04-16 10:05:34
Other Links: manifest | tags
Context
2023-04-16
22:28
Brindille: make variables array public check-in: 88b698b997 user: bohwaz tags: trunk
10:05
CSSParser: implement caching of nodes, speeds things up to 3 times! check-in: 545a52d7de user: bohwaz tags: trunk
2023-04-08
13:47
Add comment check-in: e635906ff3 user: bohwaz tags: trunk
Changes

Modified src/lib/KD2/HTML/CSSParser.php from [6b4382e74d] to [efce114f71].

1

2
3
4
5
6
7
8
<?php


namespace KD2\HTML;

use DOMDocument;
use DOMElement;
use DOMNode;
use DOMXPath;

>







1
2
3
4
5
6
7
8
9
<?php
declare(strict_types=1);

namespace KD2\HTML;

use DOMDocument;
use DOMElement;
use DOMNode;
use DOMXPath;
49
50
51
52
53
54
55

56
57
58
59
60
61
62
		// Properties: border: 1px solid red; padding: 1px }
		'property' => '\s*-?' . self::RULE_NAME_TOKEN . '\s*:\s*[^;]+?\s*[;\}]\s*',
		'open' => '\s*[^\{\}]+?\s*\{\s*',
		'close' => '\s*\}\s*',
	];

	protected array $declarations = [];


	public function xpath(DOMNode $dom, string $query, int $item = null)
	{
		$xpath = new DOMXPath($dom instanceOf DOMDocument ? $dom : $dom->ownerDocument);
		$result = $xpath->query($query, $dom);

		if (null !== $item) {







>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
		// Properties: border: 1px solid red; padding: 1px }
		'property' => '\s*-?' . self::RULE_NAME_TOKEN . '\s*:\s*[^;]+?\s*[;\}]\s*',
		'open' => '\s*[^\{\}]+?\s*\{\s*',
		'close' => '\s*\}\s*',
	];

	protected array $declarations = [];
	protected array $cache = [];

	public function xpath(DOMNode $dom, string $query, int $item = null)
	{
		$xpath = new DOMXPath($dom instanceOf DOMDocument ? $dom : $dom->ownerDocument);
		$result = $xpath->query($query, $dom);

		if (null !== $item) {
388
389
390
391
392
393
394
































395
396
397
398
399
400
401







402
403
404
405
406
407
408
			if (!array_intersect($selector['classes'], $classes)) {
				return false;
			}
		}

		return true;
	}

































	/**
	 * Return all CSS declarations applying specifically to a node
	 * (not including inherited properties from parents)
	 */
	public function match(DOMElement $search_node): array
	{







		$declarations = [];

		foreach ($this->declarations as &$declaration) {
			foreach ($declaration['selectors'] as &$selector) {
				$last = end($selector);
				$node = $search_node;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







>
>
>
>
>
>
>







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
			if (!array_intersect($selector['classes'], $classes)) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Build the element path, including ID and name, useful for cache
	 * @see https://github.com/SerenityOS/serenity/blob/master/Userland/Libraries/LibWeb/CSS/StyleComputer.cpp#L1579
	 * @see https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/
	 */
	public function getElementPath(DOMElement $node): string
	{
		$path = [];

		do {
			$name = $node->nodeName;

			if ($class = $node->getAttribute('class')) {
				if (false !== strpos($class, ' ')) {
					$name .= '.' . preg_replace('/\s+/', '.', $class);
				}
				else {
					$name .= '.' . $class;
				}
			}
			else if ($id = $node->getAttribute('id')) {
				$name .= '#' . $id;
			}

			$path[] = $name;
		}
		while (($node = $node->parentNode) && $node instanceof DOMElement);

		$path = array_reverse($path);
		return implode('/', $path);
	}

	/**
	 * Return all CSS declarations applying specifically to a node
	 * (not including inherited properties from parents)
	 */
	public function match(DOMElement $search_node): array
	{
		$path = $this->getElementPath($search_node);

		// Try to use cache, this speeds up things 3x times
		if (array_key_exists($path, $this->cache)) {
			return $this->cache[$path];
		}

		$declarations = [];

		foreach ($this->declarations as &$declaration) {
			foreach ($declaration['selectors'] as &$selector) {
				$last = end($selector);
				$node = $search_node;

429
430
431
432
433
434
435


436
437
438
439
440
441
442
				}

				$declarations[] = $declaration;
			}
		}

		unset($declaration, $selector);



		return $declarations;
	}

	/**
	 * Return all properties applying to a node, including inherited properties from parents
	 */







>
>







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
				}

				$declarations[] = $declaration;
			}
		}

		unset($declaration, $selector);

		$this->cache[$path] = $declarations;

		return $declarations;
	}

	/**
	 * Return all properties applying to a node, including inherited properties from parents
	 */