/**
  * parse a CSS string using a regex parser
  *
  * Called by {@link Stylesheet::parse_css()} 
  *
  * @param string $str 
  */
 private function _parse_css($str)
 {
     // Destroy comments
     $css = preg_replace("'/\\*.*?\\*/'si", "", $str);
     // FIXME: handle '{' within strings, e.g. [attr="string {}"]
     // Something more legible:
     $re = "/\\s*                                   # Skip leading whitespace                             \n" . "( @([^\\s]+)\\s+([^{;]*) (?:;|({)) )?    # Match @rules followed by ';' or '{'                 \n" . "(?(1)                                  # Only parse sub-sections if we're in an @rule...     \n" . "  (?(4)                                # ...and if there was a leading '{'                   \n" . "    \\s*( (?:(?>[^{}]+) ({)?            # Parse rulesets and individual @page rules           \n" . "            (?(6) (?>[^}]*) }) \\s*)+?  \n" . "       )                               \n" . "   })                                  # Balancing '}'                                \n" . "|                                      # Branch to match regular rules (not preceeded by '@')\n" . "([^{]*{[^}]*}))                        # Parse normal rulesets\n" . "/xs";
     if (preg_match_all($re, $css, $matches, PREG_SET_ORDER) === false) {
         // An error occured
         throw new DOMPDF_Exception("Error parsing css file: preg_match_all() failed.");
     }
     // After matching, the array indicies are set as follows:
     //
     // [0] => complete text of match
     // [1] => contains '@import ...;' or '@media {' if applicable
     // [2] => text following @ for cases where [1] is set
     // [3] => media types or full text following '@import ...;'
     // [4] => '{', if present
     // [5] => rulesets within media rules
     // [6] => '{', within media rules
     // [7] => individual rules, outside of media rules
     //
     //pre_r($matches);
     foreach ($matches as $match) {
         $match[2] = trim($match[2]);
         if ($match[2] !== "") {
             // Handle @rules
             switch ($match[2]) {
                 case "import":
                     $this->_parse_import($match[3]);
                     break;
                 case "media":
                     if (in_array(mb_strtolower(trim($match[3])), self::$ACCEPTED_MEDIA_TYPES)) {
                         $this->_parse_sections($match[5]);
                     }
                     break;
                 case "page":
                     // Store the style for later...
                     if (is_null($this->_page_style)) {
                         $this->_page_style = $this->_parse_properties($match[5]);
                     } else {
                         $this->_page_style->merge($this->_parse_properties($match[5]));
                     }
                     break;
                 default:
                     // ignore everything else
                     break;
             }
             continue;
         }
         if ($match[7] !== "") {
             $this->_parse_sections($match[7]);
         }
     }
 }
Beispiel #2
0
 /**
  * parse a CSS string using a regex parser
  *
  * Called by {@link Stylesheet::parse_css()}
  *
  * @param string $str
  */
 private function _parse_css($str)
 {
     $str = trim($str);
     // Destroy comments and remove HTML comments
     $css = preg_replace(array("'/\\*.*?\\*/'si", "/^<!--/", "/-->\$/"), "", $str);
     // FIXME: handle '{' within strings, e.g. [attr="string {}"]
     // Something more legible:
     $re = "/\\s*                                   # Skip leading whitespace                             \n" . "( @([^\\s]+)\\s+([^{;]*) (?:;|({)) )?    # Match @rules followed by ';' or '{'                 \n" . "(?(1)                                  # Only parse sub-sections if we're in an @rule...     \n" . "  (?(4)                                # ...and if there was a leading '{'                   \n" . "    \\s*( (?:(?>[^{}]+) ({)?            # Parse rulesets and individual @page rules           \n" . "            (?(6) (?>[^}]*) }) \\s*)+?  \n" . "       )                               \n" . "   })                                  # Balancing '}'                                \n" . "|                                      # Branch to match regular rules (not preceeded by '@')\n" . "([^{]*{[^}]*}))                        # Parse normal rulesets\n" . "/xs";
     if (preg_match_all($re, $css, $matches, PREG_SET_ORDER) === false) {
         // An error occured
         throw new DOMPDF_Exception("Error parsing css file: preg_match_all() failed.");
     }
     // After matching, the array indicies are set as follows:
     //
     // [0] => complete text of match
     // [1] => contains '@import ...;' or '@media {' if applicable
     // [2] => text following @ for cases where [1] is set
     // [3] => media types or full text following '@import ...;'
     // [4] => '{', if present
     // [5] => rulesets within media rules
     // [6] => '{', within media rules
     // [7] => individual rules, outside of media rules
     //
     //pre_r($matches);
     foreach ($matches as $match) {
         $match[2] = trim($match[2]);
         if ($match[2] !== "") {
             // Handle @rules
             switch ($match[2]) {
                 case "import":
                     $this->_parse_import($match[3]);
                     break;
                 case "media":
                     $acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
                     if (defined("DOMPDF_DEFAULT_MEDIA_TYPE")) {
                         $acceptedmedia[] = DOMPDF_DEFAULT_MEDIA_TYPE;
                     } else {
                         $acceptedmedia[] = self::$ACCEPTED_DEFAULT_MEDIA_TYPE;
                     }
                     if (in_array(mb_strtolower(trim($match[3])), $acceptedmedia)) {
                         $this->_parse_sections($match[5]);
                     }
                     break;
                 case "page":
                     //This handles @page to be applied to page oriented media
                     //Note: This has a reduced syntax:
                     //@page { margin:1cm; color:blue; }
                     //Not a sequence of styles like a full.css, but only the properties
                     //of a single style, which is applied to the very first "root" frame before
                     //processing other styles of the frame.
                     //Working properties:
                     // margin (for margin around edge of paper)
                     // font-family (default font of pages)
                     // color (default text color of pages)
                     //Non working properties:
                     // border
                     // padding
                     // background-color
                     //Todo:Reason is unknown
                     //Other properties (like further font or border attributes) not tested.
                     //If a border or background color around each paper sheet is desired,
                     //assign it to the <body> tag, possibly only for the css of the correct media type.
                     // If the page has a name, skip the style.
                     if ($match[3] !== "") {
                         return;
                     }
                     // Store the style for later...
                     if (is_null($this->_page_style)) {
                         $this->_page_style = $this->_parse_properties($match[5]);
                     } else {
                         $this->_page_style->merge($this->_parse_properties($match[5]));
                     }
                     break;
                 case "font-face":
                     $this->_parse_font_face($match[5]);
                     break;
                 default:
                     // ignore everything else
                     break;
             }
             continue;
         }
         if ($match[7] !== "") {
             $this->_parse_sections($match[7]);
         }
     }
 }
Beispiel #3
0
 /**
  * merge() should not merge style if the states are different
  */
 public function testMerge_doesNotMergeStyles_ifStatesAreDifferent()
 {
     $style1 = new Style();
     $style2 = new Style();
     // $style2->getDocument()->setSomething();
     $style2->getSection()->setIndex(999);
     $style2->getParagraph()->setIndex(999);
     $style2->getCharacter()->setIsBold(true);
     $style2->merge($style1);
     // $this->assertNotSame($style1->getDocument(), $style2->getDocument());
     $this->assertNotSame($style1->getSection(), $style2->getSection());
     $this->assertNotSame($style1->getParagraph(), $style2->getParagraph());
     $this->assertNotSame($style1->getCharacter(), $style2->getCharacter());
     return;
 }