Completed
Push — master ( 01c66d...b0da91 )
by Lars
03:57
created

src/CssToInlineStyles.php (2 issues)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace voku\CssToInlineStyles;
4
5
use Symfony\Component\CssSelector\CssSelectorConverter;
6
use Symfony\Component\CssSelector\Exception\ExceptionInterface;
7
use voku\helper\HtmlDomParser;
8
9
/**
10
 * CSS to Inline Styles class
11
 *
12
 * @author     Tijs Verkoyen <[email protected]>
13
 */
14
class CssToInlineStyles
15
{
16
17
  /**
18
   * regular expression: css media queries
19
   *
20
   * @var string
21
   */
22
  private static $cssMediaQueriesRegEx = '#@media\\s+(?:only\\s)?(?:[\\s{\\(]|screen|all)\\s?[^{]+{.*}\\s*}\\s*#misU';
23
24
  /**
25
   * regular expression: css charset
26
   *
27
   * @var string
28
   */
29
  private static $cssCharsetRegEx = '/@charset [\'"][^\'"]+[\'"];/i';
30
31
  /**
32
   * regular expression: conditional inline style tags
33
   *
34
   * @var string
35
   */
36
  private static $excludeConditionalInlineStylesBlockRegEx = '/<!--.*<style.*-->/isU';
37
38
  /**
39
   * regular expression: inline style tags
40
   *
41
   * @var string
42
   */
43
  private static $styleTagRegEx = '|<style(.*)>(.*)</style>|isU';
44
45
  /**
46
   * regular expression: css-comments
47
   *
48
   * @var string
49
   */
50
  private static $styleCommentRegEx = '/\\/\\*.*\\*\\//sU';
51
52
  /**
53
   * The CSS to use
54
   *
55
   * @var  string
56
   */
57
  private $css;
58
59
  /**
60
   * Should the generated HTML be cleaned
61
   *
62
   * @var  bool
63
   */
64
  private $cleanup = false;
65
66
  /**
67
   * The encoding to use.
68
   *
69
   * @var  string
70
   */
71
  private $encoding = 'UTF-8';
72
73
  /**
74
   * The HTML to process
75
   *
76
   * @var  string
77
   */
78
  private $html;
79
80
  /**
81
   * Use inline-styles block as CSS
82
   *
83
   * @var bool
84
   */
85
  private $useInlineStylesBlock = false;
86
87
  /**
88
   * Use link block reference as CSS
89
   *
90
   * @var bool
91
   */
92
  private $loadCSSFromHTML = false;
93
94
  /**
95
   * Strip original style tags
96
   *
97
   * @var bool
98
   */
99
  private $stripOriginalStyleTags = false;
100
101
  /**
102
   * Exclude conditional inline-style blocks
103
   *
104
   * @var bool
105
   */
106
  private $excludeConditionalInlineStylesBlock = true;
107
108
  /**
109
   * Exclude media queries from "$this->css" and keep media queries for inline-styles blocks
110
   *
111
   * @var bool
112
   */
113
  private $excludeMediaQueries = true;
114
115
  /**
116
   * Exclude media queries from "$this->css" and keep media queries for inline-styles blocks
117
   *
118
   * @var bool
119
   */
120
  private $excludeCssCharset = true;
121
122
  /**
123
   * Creates an instance, you could set the HTML and CSS here, or load it
124
   * later.
125
   *
126
   * @param  null|string $html The HTML to process.
127
   * @param  null|string $css  The CSS to use.
128
   */
129 48
  public function __construct($html = null, $css = null)
130
  {
131 48
    if (null !== $html) {
132 2
      $this->setHTML($html);
133
    }
134
135 48
    if (null !== $css) {
136 2
      $this->setCSS($css);
137
    }
138 48
  }
139
140
  /**
141
   * Set HTML to process
142
   *
143
   * @param  string $html The HTML to process.
144
   */
145 46
  public function setHTML($html)
146
  {
147
    // strip style definitions, if we use css-class "cleanup" on a style-element
148 46
    $this->html = (string)preg_replace('/<style[^>]+class="cleanup"[^>]*>.*<\/style>/Usi', ' ', $html);
149 46
  }
150
151
  /**
152
   * Set CSS to use
153
   *
154
   * @param  string $css The CSS to use.
155
   */
156 44
  public function setCSS($css)
157
  {
158 44
    $this->css = (string)$css;
159 44
  }
160
161
  /**
162
   * Sort an array on the specificity element
163
   *
164
   * @return int
165
   *
166
   * @param Specificity[] $e1 The first element.
167
   * @param Specificity[] $e2 The second element.
168
   */
169 17
  private static function sortOnSpecificity($e1, $e2)
170
  {
171
    // Compare the specificity
172 17
    $value = $e1['specificity']->compareTo($e2['specificity']);
173
174
    // if the specificity is the same, use the order in which the element appeared
175 17
    if (0 === $value) {
176 12
      $value = $e1['order'] - $e2['order'];
177
    }
178
179 17
    return $value;
180
  }
181
182
  /**
183
   * Converts the loaded HTML into an HTML-string with inline styles based on the loaded CSS
184
   *
185
   * @param bool $outputXHTML                             [optional] Should we output valid XHTML?
186
   * @param int  $libXMLOptions                           [optional] $libXMLOptions Since PHP 5.4.0 and Libxml 2.6.0,
187
   *                                                      you may also use the options parameter to specify additional
188
   *                                                      Libxml parameters. Recommend these options:
189
   *                                                      LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
190
   * @param bool $path                                    [optional] Set the path to your external css-files.
191
   *
192
   * @return string
193
   *
194
   * @throws Exception
195
   */
196 46
  public function convert($outputXHTML = false, $libXMLOptions = 0, $path = false)
0 ignored issues
show
The parameter $libXMLOptions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
197
  {
198
    // redefine
199 46
    $outputXHTML = (bool)$outputXHTML;
200
201
    // validate
202 46
    if (!$this->html) {
203 1
      throw new Exception('No HTML provided.');
204
    }
205
206
    // use local variables
207 45
    $css = $this->css;
208
209
    // create new HtmlDomParser
210 45
    $dom = HtmlDomParser::str_get_html($this->html);
0 ignored issues
show
The call to HtmlDomParser::str_get_html() has too many arguments starting with $this->html.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
211
212
    // check if there is some link css reference
213 45
    if ($this->loadCSSFromHTML) {
214 1
      foreach ($dom->find('link') as $node) {
215
216
        /** @noinspection PhpUndefinedMethodInspection */
217 1
        $file = ($path ?: __DIR__) . '/' . $node->getAttribute('href');
218
219 1
        if (file_exists($file)) {
220 1
          $css .= file_get_contents($file);
221
222
          // converting to inline css because we don't need/want to load css files, so remove the link
223 1
          $node->outertext = '';
224
        }
225
      }
226
    }
227
228
    // should we use inline style-block
229 45
    if ($this->useInlineStylesBlock) {
230
231 27
      if (true === $this->excludeConditionalInlineStylesBlock) {
232 23
        $this->html = preg_replace(self::$excludeConditionalInlineStylesBlockRegEx, '', $this->html);
233
      }
234
235 27
      $css .= $this->getCssFromInlineHtmlStyleBlock($this->html);
236
    }
237
238
    // process css
239 45
    $cssRules = $this->processCSS($css);
240
241
    // create new XPath
242 45
    $xPath = $this->createXPath($dom->getDocument(), $cssRules);
243
244
    // strip original style tags if we need to
245 45
    if ($this->stripOriginalStyleTags === true) {
246 13
      $this->stripOriginalStyleTags($xPath);
247
    }
248
249
    // cleanup the HTML if we need to
250 45
    if (true === $this->cleanup) {
251 3
      $this->cleanupHTML($xPath);
252
    }
253
254
    // should we output XHTML?
255 45
    if (true === $outputXHTML) {
256 6
      return $dom->xml();
257
    }
258
259
    // just regular HTML 4.01 as it should be used in newsletters
260 40
    return $dom->html();
261
  }
262
263
  /**
264
   * get css from inline-html style-block
265
   *
266
   * @param string $html
267
   *
268
   * @return string
269
   */
270 29
  public function getCssFromInlineHtmlStyleBlock($html)
271
  {
272
    // init var
273 29
    $css = '';
274 29
    $matches = array();
275
276
    // match the style blocks
277 29
    preg_match_all(self::$styleTagRegEx, $html, $matches);
278
279
    // any style-blocks found?
280 29
    if (!empty($matches[2])) {
281
      // add
282 28
      foreach ($matches[2] as $match) {
283 28
        $css .= trim($match) . "\n";
284
      }
285
    }
286
287 29
    return $css;
288
  }
289
290
  /**
291
   * Process the loaded CSS
292
   *
293
   * @param $css
294
   *
295
   * @return array
296
   */
297 45
  private function processCSS($css)
298
  {
299
    //reset current set of rules
300 45
    $cssRules = array();
301
302
    // init vars
303 45
    $css = (string)$css;
304
305 45
    $css = $this->doCleanup($css);
306
307
    // rules are splitted by }
308 45
    $rules = (array)explode('}', $css);
309
310
    // init var
311 45
    $i = 1;
312
313
    // loop rules
314 45
    foreach ($rules as $rule) {
315
      // split into chunks
316 45
      $chunks = explode('{', $rule);
317
318
      // invalid rule?
319 45
      if (!isset($chunks[1])) {
320 45
        continue;
321
      }
322
323
      // set the selectors
324 34
      $selectors = trim($chunks[0]);
325
326
      // get cssProperties
327 34
      $cssProperties = trim($chunks[1]);
328
329
      // split multiple selectors
330 34
      $selectors = (array)explode(',', $selectors);
331
332
      // loop selectors
333 34
      foreach ($selectors as $selector) {
334
        // cleanup
335 34
        $selector = trim($selector);
336
337
        // build an array for each selector
338 34
        $ruleSet = array();
339
340
        // store selector
341 34
        $ruleSet['selector'] = $selector;
342
343
        // process the properties
344 34
        $ruleSet['properties'] = $this->processCSSProperties($cssProperties);
345
346
347
        // calculate specificity
348 34
        $ruleSet['specificity'] = Specificity::fromSelector($selector);
349
350
        // remember the order in which the rules appear
351 34
        $ruleSet['order'] = $i;
352
353
        // add into rules
354 34
        $cssRules[] = $ruleSet;
355
356
        // increment
357 34
        $i++;
358
      }
359
    }
360
361
    // sort based on specificity
362 45
    if (0 !== count($cssRules)) {
363 34
      usort($cssRules, array(__CLASS__, 'sortOnSpecificity'));
364
    }
365
366 45
    return $cssRules;
367
  }
368
369
  /**
370
   * @param string $css
371
   *
372
   * @return string
373
   */
374 45
  private function doCleanup($css)
375
  {
376
    // remove newlines & replace double quotes by single quotes
377 45
    $css = str_replace(
378 45
        array("\r", "\n", '"'),
379 45
        array('', '', '\''),
380
        $css
381
    );
382
383
    // remove comments
384 45
    $css = preg_replace(self::$styleCommentRegEx, '', $css);
385
386
    // remove spaces
387 45
    $css = preg_replace('/\s\s+/', ' ', $css);
388
389
    // remove css charset
390 45
    if (true === $this->excludeCssCharset) {
391 45
      $css = $this->stripeCharsetInCss($css);
392
    }
393
394
    // remove css media queries
395 45
    if (true === $this->excludeMediaQueries) {
396 44
      $css = $this->stripeMediaQueries($css);
397
    }
398
399 45
    return (string)$css;
400
  }
401
402
  /**
403
   * remove css media queries from the string
404
   *
405
   * @param string $css
406
   *
407
   * @return string
408
   */
409 44
  private function stripeMediaQueries($css)
410
  {
411
    // remove comments previously to matching media queries
412 44
    $css = preg_replace(self::$styleCommentRegEx, '', $css);
413
414 44
    return (string)preg_replace(self::$cssMediaQueriesRegEx, '', $css);
415
  }
416
417
  /**
418
   * remove charset from the string
419
   *
420
   * @param $css
421
   *
422
   * @return string
423
   */
424 45
  private function stripeCharsetInCss($css)
425
  {
426 45
    return (string)preg_replace(self::$cssCharsetRegEx, '', $css);
427
  }
428
429
  /**
430
   * Process the CSS-properties
431
   *
432
   * @return array
433
   *
434
   * @param  string $propertyString The CSS-properties.
435
   */
436 34
  private function processCSSProperties($propertyString)
437
  {
438
    // split into chunks
439 34
    $properties = $this->splitIntoProperties($propertyString);
440
441
    // init var
442 34
    $pairs = array();
443
444
    // loop properties
445 34
    foreach ($properties as $property) {
446
      // split into chunks
447 34
      $chunks = (array)explode(':', $property, 2);
448
449
      // validate
450 34
      if (!isset($chunks[1])) {
451 28
        continue;
452
      }
453
454
      // cleanup
455 33
      $chunks[0] = trim($chunks[0]);
456 33
      $chunks[1] = trim($chunks[1]);
457
458
      // add to pairs array
459
      if (
460 33
          !isset($pairs[$chunks[0]])
461
          ||
462 33
          !in_array($chunks[1], $pairs[$chunks[0]], true)
463
      ) {
464 33
        $pairs[$chunks[0]][] = $chunks[1];
465
      }
466
    }
467
468
    // sort the pairs
469 34
    ksort($pairs);
470
471
    // return
472 34
    return $pairs;
473
  }
474
475
  /**
476
   * Split a style string into an array of properties.
477
   * The returned array can contain empty strings.
478
   *
479
   * @param string $styles ex: 'color:blue;font-size:12px;'
480
   *
481
   * @return array an array of strings containing css property ex: array('color:blue','font-size:12px')
482
   */
483 34
  private function splitIntoProperties($styles)
484
  {
485 34
    $properties = (array)explode(';', $styles);
486 34
    $propertiesCount = count($properties);
487
488
    /** @noinspection ForeachInvariantsInspection */
489 34
    for ($i = 0; $i < $propertiesCount; $i++) {
490
      // If next property begins with base64,
491
      // Then the ';' was part of this property (and we should not have split on it).
492
      if (
493 34
          isset($properties[$i + 1])
494
          &&
495 34
          strpos($properties[$i + 1], 'base64,') !== false
496
      ) {
497 1
        $properties[$i] .= ';' . $properties[$i + 1];
498 1
        $properties[$i + 1] = '';
499 1
        ++$i;
500
      }
501
    }
502
503 34
    return $properties;
504
  }
505
506
  /**
507
   * create XPath
508
   *
509
   * @param \DOMDocument $document
510
   * @param array        $cssRules
511
   *
512
   * @return \DOMXPath
513
   */
514 45
  private function createXPath(\DOMDocument $document, array $cssRules)
515
  {
516 45
    $xPath = new \DOMXPath($document);
517
518
    // any rules?
519 45
    if (0 !== count($cssRules)) {
520
      // loop rules
521 34
      foreach ($cssRules as $rule) {
522
523 34
        $ruleSelector = $rule['selector'];
524 34
        $ruleProperties = $rule['properties'];
525
526 34
        if (!$ruleSelector || !$ruleProperties) {
527 3
          continue;
528
        }
529
530
        try {
531 33
          $converter = new CssSelectorConverter();
532 33
          $query = $converter->toXPath($ruleSelector);
533 3
        } catch (ExceptionInterface $e) {
534 3
          $query = null;
535
        }
536 33
        $converter = null;
537
538
        // validate query
539 33
        if (null === $query) {
540 3
          continue;
541
        }
542
543
        // search elements
544 32
        $elements = $xPath->query($query);
545
546
        // validate elements
547 32
        if (false === $elements) {
548
          continue;
549
        }
550
551
        // loop found elements
552 32
        foreach ($elements as $element) {
553
554
          /**
555
           * @var $element \DOMElement
556
           */
557
558
          if (
559 32
              $ruleSelector == '*'
560
              &&
561
              (
562 1
                  $element->tagName == 'html'
563 1
                  || $element->tagName === 'title'
564 1
                  || $element->tagName == 'meta'
565 1
                  || $element->tagName == 'head'
566 1
                  || $element->tagName == 'style'
567 1
                  || $element->tagName == 'script'
568 32
                  || $element->tagName == 'link'
569
              )
570
          ) {
571 1
            continue;
572
          }
573
574
          // no styles stored?
575 32
          if (null === $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')) {
576
577
            // init var
578 32
            $originalStyle = '';
579
580 32
            if (null !== $element->attributes->getNamedItem('style')) {
581
              /** @noinspection PhpUndefinedFieldInspection */
582 9
              $originalStyle = $element->attributes->getNamedItem('style')->value;
583
            }
584
585
            // store original styles
586 32
            $element->setAttribute('data-css-to-inline-styles-original-styles', $originalStyle);
587
588
            // clear the styles
589 32
            $element->setAttribute('style', '');
590
          }
591
592 32
          $propertiesString = $this->createPropertyChunks($element, $ruleProperties);
593
594
          // set attribute
595 32
          if ('' != $propertiesString) {
596 32
            $element->setAttribute('style', $propertiesString);
597
          }
598
        }
599
      }
600
601
      // reapply original styles
602
      // search elements
603 34
      $elements = $xPath->query('//*[@data-css-to-inline-styles-original-styles]');
604
605
      // loop found elements
606 34
      foreach ($elements as $element) {
607
        // get the original styles
608
        /** @noinspection PhpUndefinedFieldInspection */
609 32
        $originalStyle = $element->attributes->getNamedItem('data-css-to-inline-styles-original-styles')->value;
610
611 32
        if ('' != $originalStyle) {
612 9
          $originalStyles = $this->splitIntoProperties($originalStyle);
613
614 9
          $originalProperties = $this->splitStyleIntoChunks($originalStyles);
615
616 9
          $propertiesString = $this->createPropertyChunks($element, $originalProperties);
617
618
          // set attribute
619 9
          if ('' != $propertiesString) {
620 9
            $element->setAttribute('style', $propertiesString);
621
          }
622
        }
623
624
        // remove placeholder
625 32
        $element->removeAttribute('data-css-to-inline-styles-original-styles');
626
      }
627
    }
628
629 45
    return $xPath;
630
  }
631
632
  /**
633
   * @param \DOMElement $element
634
   * @param array       $ruleProperties
635
   *
636
   * @return array
637
   */
638 32
  private function createPropertyChunks(\DOMElement $element, array $ruleProperties)
639
  {
640
    // init var
641 32
    $properties = array();
642
643
    // get current styles
644 32
    $stylesAttribute = $element->attributes->getNamedItem('style');
645
646
    // any styles defined before?
647 32
    if (null !== $stylesAttribute) {
648
      // get value for the styles attribute
649
      /** @noinspection PhpUndefinedFieldInspection */
650 32
      $definedStyles = (string)$stylesAttribute->value;
651
652
      // split into properties
653 32
      $definedProperties = $this->splitIntoProperties($definedStyles);
654
655 32
      $properties = $this->splitStyleIntoChunks($definedProperties);
656
    }
657
658
    // add new properties into the list
659 32
    foreach ($ruleProperties as $key => $value) {
660
      // If one of the rules is already set and is !important, don't apply it,
661
      // except if the new rule is also important.
662
      if (
663 32
          !isset($properties[$key])
664
          ||
665 10
          false === stripos($properties[$key], '!important')
666
          ||
667 32
          false !== stripos(implode('', (array)$value), '!important')
668
      ) {
669 32
        $properties[$key] = $value;
670
      }
671
    }
672
673
    // build string
674 32
    $propertyChunks = array();
675
676
    // build chunks
677 32
    foreach ($properties as $key => $values) {
678 32
      foreach ((array)$values as $value) {
679 32
        $propertyChunks[] = $key . ': ' . $value . ';';
680
      }
681
    }
682
683 32
    return implode(' ', $propertyChunks);
684
  }
685
686
  /**
687
   * @param array $definedProperties
688
   *
689
   * @return array
690
   */
691 32
  private function splitStyleIntoChunks(array $definedProperties)
692
  {
693
    // init var
694 32
    $properties = array();
695
696
    // loop properties
697 32
    foreach ($definedProperties as $property) {
698
      // validate property
699
      if (
700 32
          !$property
701
          ||
702 32
          strpos($property, ':') === false
703
      ) {
704 32
        continue;
705
      }
706
707
      // split into chunks
708 17
      $chunks = (array)explode(':', trim($property), 2);
709
710
      // validate
711 17
      if (!isset($chunks[1])) {
712
        continue;
713
      }
714
715
      // loop chunks
716 17
      $properties[$chunks[0]] = trim($chunks[1]);
717
    }
718
719 32
    return $properties;
720
  }
721
722
  /**
723
   * Strip style tags into the generated HTML
724
   *
725
   * @param  \DOMXPath $xPath The DOMXPath for the entire document.
726
   *
727
   * @return string
728
   */
729 13
  private function stripOriginalStyleTags(\DOMXPath $xPath)
730
  {
731
    // get all style tags
732 13
    $nodes = $xPath->query('descendant-or-self::style');
733 13
    foreach ($nodes as $node) {
734 12
      if ($this->excludeMediaQueries === true) {
735
736
        // remove comments previously to matching media queries
737 11
        $node->nodeValue = preg_replace(self::$styleCommentRegEx, '', $node->nodeValue);
738
739
        // search for Media Queries
740 11
        preg_match_all(self::$cssMediaQueriesRegEx, $node->nodeValue, $mqs);
741
742
        // replace the nodeValue with just the Media Queries
743 11
        $node->nodeValue = implode("\n", $mqs[0]);
744
745
      } else {
746
        // remove the entire style tag
747 12
        $node->parentNode->removeChild($node);
748
      }
749
    }
750 13
  }
751
752
  /**
753
   * Remove id and class attributes.
754
   *
755
   * @param  \DOMXPath $xPath The DOMXPath for the entire document.
756
   *
757
   * @return string
758
   */
759 3
  private function cleanupHTML(\DOMXPath $xPath)
760
  {
761 3
    $nodes = $xPath->query('//@class | //@id');
762 3
    foreach ($nodes as $node) {
763 3
      $node->ownerElement->removeAttributeNode($node);
764
    }
765 3
  }
766
767
  /**
768
   * Should the IDs and classes be removed?
769
   *
770
   * @param  bool $on Should we enable cleanup?
771
   */
772 3
  public function setCleanup($on = true)
773
  {
774 3
    $this->cleanup = (bool)$on;
775 3
  }
776
777
  /**
778
   * Set the encoding to use with the DOMDocument
779
   *
780
   * @param  string $encoding The encoding to use.
781
   *
782
   * @deprecated Doesn't have any effect
783
   */
784
  public function setEncoding($encoding)
785
  {
786
    $this->encoding = (string)$encoding;
787
  }
788
789
  /**
790
   * Set use of inline styles block
791
   * If this is enabled the class will use the style-block in the HTML.
792
   *
793
   * @param  bool $on Should we process inline styles?
794
   */
795 27
  public function setUseInlineStylesBlock($on = true)
796
  {
797 27
    $this->useInlineStylesBlock = (bool)$on;
798 27
  }
799
800
  /**
801
   * Set use of inline link block
802
   * If this is enabled the class will use the links reference in the HTML.
803
   *
804
   * @return void
805
   *
806
   * @param  bool [optional] $on Should we process link styles?
807
   */
808 2
  public function setLoadCSSFromHTML($on = true)
809
  {
810 2
    $this->loadCSSFromHTML = (bool)$on;
811 2
  }
812
813
  /**
814
   * Set strip original style tags
815
   * If this is enabled the class will remove all style tags in the HTML.
816
   *
817
   * @param  bool $on Should we process inline styles?
818
   */
819 17
  public function setStripOriginalStyleTags($on = true)
820
  {
821 17
    $this->stripOriginalStyleTags = (bool)$on;
822 17
  }
823
824
  /**
825
   * Set exclude media queries
826
   *
827
   * If this is enabled the media queries will be removed before inlining the rules.
828
   *
829
   * WARNING: If you use inline styles block "<style>" the this option will keep the media queries.
830
   *
831
   * @param bool $on
832
   */
833 14
  public function setExcludeMediaQueries($on = true)
834
  {
835 14
    $this->excludeMediaQueries = (bool)$on;
836 14
  }
837
838
  /**
839
   * Set exclude charset
840
   *
841
   * @param bool $on
842
   */
843 1
  public function setExcludeCssCharset($on = true)
844
  {
845 1
    $this->excludeCssCharset = (bool)$on;
846 1
  }
847
848
  /**
849
   * Set exclude conditional inline-style blocks e.g.: <!--[if gte mso 9]><style>.foo { bar } </style><![endif]-->
850
   *
851
   * @param bool $on
852
   */
853 6
  public function setExcludeConditionalInlineStylesBlock($on = true)
854
  {
855 6
    $this->excludeConditionalInlineStylesBlock = (bool)$on;
856 6
  }
857
}
858