set_type($type); } function get_type() { return $this->_type; } function set_type($type) { $this->_type = $type; } } class CSSPageSelectorAll extends CSSPageSelector { function CSSPageSelectorAll() { $this->CSSPageSelector(CSS_PAGE_SELECTOR_ALL); } } class CSSPageSelectorNamed extends CSSPageSelector { var $_name; function CSSPageSelectorNamed($name) { $this->CSSPageSelector(CSS_PAGE_SELECTOR_NAMED); $this->set_name($name); } function get_name() { return $this->_name; } function set_name($name) { $this->_name = $name; } } class CSSPageSelectorFirst extends CSSPageSelector { function CSSPageSelectorFirst() { $this->CSSPageSelector(CSS_PAGE_SELECTOR_FIRST); } } class CSSPageSelectorLeft extends CSSPageSelector { function CSSPageSelectorLeft() { $this->CSSPageSelector(CSS_PAGE_SELECTOR_LEFT); } } class CSSPageSelectorRight extends CSSPageSelector { function CSSPageSelectorRight() { $this->CSSPageSelector(CSS_PAGE_SELECTOR_RIGHT); } } class CSSAtRulePage { var $selector; var $margin_boxes; var $css; function CSSAtRulePage($selector, &$pipeline) { $this->selector = $selector; $this->margin_boxes = array(); $this->css =& new CSSPropertyCollection(); } function &getSelector() { return $this->selector; } function getAtRuleMarginBoxes() { return $this->margin_boxes; } /** * Note that only one margin box rule could be added; subsequent adds * will overwrite existing data */ function addAtRuleMarginBox($rule) { $this->margin_boxes[$rule->getSelector()] = $rule; } function setCSSProperty($property) { $this->css->add_property($property); } } class CSSAtRuleMarginBox { var $selector; var $css; /** * TODO: CSS_TEXT_ALIGN should get top/bottom values by default for * left-top, left-bottom, right-top and right-bottom boxes */ function CSSAtRuleMarginBox($selector, &$pipeline) { $this->selector = $selector; $css = "-html2ps-html-content: ''; content: ''; width: auto; height: auto; margin: 0; border: none; padding: 0; font: auto;"; $css = $css . $this->_getCSSDefaults($selector); $this->css = new CSSRule(array( array(SELECTOR_ANY), parse_css_properties($css, $null), '', null), $pipeline); } function getSelector() { return $this->selector; } function _getCSSDefaults($selector) { $text_align_handler =& CSS::get_handler(CSS_TEXT_ALIGN); $vertical_align_handler =& CSS::get_handler(CSS_VERTICAL_ALIGN); switch ($selector) { case CSS_MARGIN_BOX_SELECTOR_TOP: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER: return 'text-align: right; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_TOP_LEFT: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_TOP_CENTER: return 'text-align: center; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT: return 'text-align: right; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER: return 'text-align: right; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER: return 'text-align: center; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT: return 'text-align: right; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER: return 'text-align: left; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_LEFT_TOP: return 'text-align: center; vertical-align: top'; case CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE: return 'text-align: center; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM: return 'text-align: center; vertical-align: bottom'; case CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP: return 'text-align: center; vertical-align: top'; case CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE: return 'text-align: center; vertical-align: middle'; case CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM: return 'text-align: center; vertical-align: bottom'; }; } function setCSSProperty($property) { $this->css->add_property($property); } function &get_css_property($code) { return $this->css->get_property($code); } } /** * Handle @page rules in current CSS media As parse_css_media is * called for selected media only, we can store data to global CSS * state - no data should be ignored * * at-page rules will be removed after parsing * * @param $css String contains raw CSS data to be processed * @return String CSS text without at-page rules */ function parse_css_atpage_rules($css, &$css_ruleset) { while (preg_match('/^(.*?)@page(.*)/is', $css, $matches)) { $data = $matches[2]; $css = $matches[1].parse_css_atpage_rule(trim($data), $css_ruleset); }; return $css; } function parse_css_atpage_rule($css, &$css_ruleset) { /** * Extract selector and left bracket */ if (!preg_match('/^(.*?){(.*)$/is', $css, $matches)) { error_log('No selector and/or open bracket found in @page rule'); return $css; }; $raw_selector = trim($matches[1]); $css = trim($matches[2]); $selector =& parse_css_atpage_selector($raw_selector); $at_rule =& new CSSAtRulePage($selector, $css_ruleset); /** * The body of @page rule may contain declaraction (detected by ';'), * margin box at-rule (detected by @top and similar tokens) or } indicating termination of * @page rule */ while (preg_match('/^(.*?)(;|@|})(.*)$/is', $css, $matches)) { $raw_prefix = trim($matches[1]); $raw_token = trim($matches[2]); $raw_suffix = trim($matches[3]); switch ($raw_token) { case ';': /** * Normal declaration (text contained in $raw_prefix */ parse_css_atpage_declaration($raw_prefix, $at_rule, $css_ruleset); $css = $raw_suffix; break; case '@': /** * Margin box at-rule */ $css = parse_css_atpage_margin_box($raw_suffix, $at_rule, $css_ruleset); break; case '}': /** * End-of-rule */ $css_ruleset->add_at_rule_page($at_rule); return $raw_suffix; }; }; /** * Note that we should normally exit via '}' token handler above */ error_log('No close bracket found in @page rule'); $css_ruleset->add_at_rule_page($at_rule); return $css; } /** * Parses CSS at-page rule selector; syntax of this selector can be seen in * CSS 3 specification at http://www.w3.org/TR/css3-page/#syntax-page-selector * * */ function &parse_css_atpage_selector($selector) { switch ($selector) { case '': $selector =& new CSSPageSelectorAll(); return $selector; case ':first': $selector =& new CSSPageSelectorFirst(); return $selector; case ':left': $selector =& new CSSPageSelectorLeft(); return $selector; case ':right': $selector =& new CSSPageSelectorRight(); return $selector; default: if (CSS::is_identifier($selector)) { $selector =& new CSSPageSelectorNamed($selector); return $selector; } else { error_log(sprintf('Unknown page selector in @page rule: \'%s\'', $selector)); $selector =& new CSSPageSelectorAll(); return $selector; }; }; } function parse_css_atpage_margin_box($css, &$at_rule, &$pipeline) { if (!preg_match("/^([-\w]*)\s*{(.*)/is",$css,$matches)) { error_log("Invalid margin box at-rule format"); return $css; }; $raw_margin_box_selector = trim($matches[1]); $css = trim($matches[2]); $margin_box_selector = parse_css_atpage_margin_box_selector($raw_margin_box_selector); $at_rule_margin_box = new CSSAtRuleMarginBox($margin_box_selector, $pipeline); /** * The body of margin box at-rule may contain declaraction (detected * by ';'), or } indicating termination of at-rule */ while (preg_match('/^(.*?)(;|})(.*)$/is', $css, $matches)) { $raw_prefix = trim($matches[1]); $raw_token = trim($matches[2]); $raw_suffix = trim($matches[3]); switch ($raw_token) { case ';': /** * Normal declaration (text contained in $raw_prefix */ parse_css_atpage_margin_box_declaration($raw_prefix, $at_rule_margin_box, $pipeline); $css = $raw_suffix; break; case '}': /** * End-of-rule */ $at_rule->addAtRuleMarginBox($at_rule_margin_box); return $raw_suffix; }; }; /** * Note that we should normally exit via '}' token handler above */ error_log('No close bracket found in margin box at-rule'); $at_rule->addAtRuleMarginBox($at_rule_margin_box); return $css; } function parse_css_atpage_margin_box_selector($css) { switch ($css) { case 'top': return CSS_MARGIN_BOX_SELECTOR_TOP; case 'top-left-corner': return CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER; case 'top-left': return CSS_MARGIN_BOX_SELECTOR_TOP_LEFT; case 'top-center': return CSS_MARGIN_BOX_SELECTOR_TOP_CENTER; case 'top-right': return CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT; case 'top-right-corner': return CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER; case 'bottom': return CSS_MARGIN_BOX_SELECTOR_BOTTOM; case 'bottom-left-corner': return CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER; case 'bottom-left': return CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT; case 'bottom-center': return CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER; case 'bottom-right': return CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT; case 'bottom-right-corner': return CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER; case 'left-top': return CSS_MARGIN_BOX_SELECTOR_LEFT_TOP; case 'left-middle': return CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE; case 'left-bottom': return CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM; case 'right-top': return CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP; case 'right-middle': return CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE; case 'right-bottom': return CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM; default: error_log(sprintf('Unrecognized margin box selector: \'%s\'', $css)); return CSS_MARGIN_BOX_SELECTOR_TOP; } }; function parse_css_atpage_declaration($css, &$at_rule, &$pipeline) { $parsed =& parse_css_property($css, $pipeline); if (!is_null($parsed)) { $properties = $parsed->getPropertiesSortedByPriority(); foreach ($properties as $property) { $at_rule->setCSSProperty($property); }; }; } function parse_css_atpage_margin_box_declaration($css, &$at_rule, &$pipeline) { $parsed =& parse_css_property($css, $pipeline); if (!is_null($parsed)) { $properties = $parsed->getPropertiesSortedByPriority(); foreach ($properties as $property) { $at_rule->setCSSProperty($property); }; }; } ?>