function get_min_max_width() { if (!is_null($this->_min_max_cache)) { return $this->_min_max_cache; } $style = $this->_frame->get_style(); // Account for margins & padding $dims = array($style->padding_left, $style->padding_right, $style->border_left_width, $style->border_right_width, $style->margin_left, $style->margin_right); $cb_w = $this->_frame->get_containing_block("w"); $delta = $style->length_in_pt($dims, $cb_w); // Handle degenerate case if (!$this->_frame->get_first_child()) { return $this->_min_max_cache = array($delta, $delta, "min" => $delta, "max" => $delta); } $low = array(); $high = array(); for ($iter = $this->_frame->get_children()->getIterator(); $iter->valid(); $iter->next()) { $inline_min = 0; $inline_max = 0; // Add all adjacent inline widths together to calculate max width while ($iter->valid() && in_array($iter->current()->get_style()->display, Style::$INLINE_TYPES)) { $child = $iter->current(); $minmax = $child->get_min_max_width(); if (in_array($iter->current()->get_style()->white_space, array("pre", "nowrap"))) { $inline_min += $minmax["min"]; } else { $low[] = $minmax["min"]; } $inline_max += $minmax["max"]; $iter->next(); } if ($inline_max > 0) { $high[] = $inline_max; } if ($inline_min > 0) { $low[] = $inline_min; } if ($iter->valid()) { list($low[], $high[]) = $iter->current()->get_min_max_width(); continue; } } $min = count($low) ? max($low) : 0; $max = count($high) ? max($high) : 0; // Use specified width if it is greater than the minimum defined by the // content. If the width is a percentage ignore it for now. $width = $style->width; if ($width !== "auto" && !Helpers::is_percent($width)) { $width = $style->length_in_pt($width, $cb_w); if ($min < $width) { $min = $width; } if ($max < $width) { $max = $width; } } $min += $delta; $max += $delta; return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max); }
function render(Frame $frame) { $style = $frame->get_style(); $node = $frame->get_node(); list($x, $y, $w, $h) = $frame->get_border_box(); $this->_set_opacity($frame->get_opacity($style->opacity)); if ($node->nodeName === "body") { $h = $frame->get_containing_block("h") - $style->length_in_pt(array($style->margin_top, $style->border_top_width, $style->border_bottom_width, $style->margin_bottom), $style->width); } // Handle anchors & links if ($node->nodeName === "a" && ($href = $node->getAttribute("href"))) { $href = Helpers::build_url($this->_dompdf->getProtocol(), $this->_dompdf->getBaseHost(), $this->_dompdf->getBasePath(), $href); $this->_canvas->add_link($href, $x, $y, $w, $h); } // Draw our background, border and content list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h); if ($tl + $tr + $br + $bl > 0) { $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl); } if (($bg = $style->background_color) !== "transparent") { $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg); } if (($url = $style->background_image) && $url !== "none") { $this->_background_image($url, $x, $y, $w, $h, $style); } if ($tl + $tr + $br + $bl > 0) { $this->_canvas->clipping_end(); } $border_box = array($x, $y, $w, $h); $this->_render_border($frame, $border_box); $this->_render_outline($frame, $border_box); if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutBlocks()) { $this->_debug_layout($frame->get_border_box(), "red"); if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) { $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5)); } } if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines() && $frame->get_decorator()) { foreach ($frame->get_decorator()->get_line_boxes() as $line) { $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange"); } } }
function render(Frame $frame) { // Render background & borders $style = $frame->get_style(); $cb = $frame->get_containing_block(); list($x, $y, $w, $h) = $frame->get_border_box(); $this->_set_opacity($frame->get_opacity($style->opacity)); list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h); $has_border_radius = $tl + $tr + $br + $bl > 0; if ($has_border_radius) { $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl); } if (($bg = $style->background_color) !== "transparent") { $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg); } if (($url = $style->background_image) && $url !== "none") { $this->_background_image($url, $x, $y, $w, $h, $style); } if ($has_border_radius) { $this->_canvas->clipping_end(); } $this->_render_border($frame); $this->_render_outline($frame); list($x, $y) = $frame->get_padding_box(); $x += $style->length_in_pt($style->padding_left, $cb["w"]); $y += $style->length_in_pt($style->padding_top, $cb["h"]); $w = $style->length_in_pt($style->width, $cb["w"]); $h = $style->length_in_pt($style->height, $cb["h"]); if ($has_border_radius) { list($wt, $wr, $wb, $wl) = array($style->border_top_width, $style->border_right_width, $style->border_bottom_width, $style->border_left_width); // we have to get the "inner" radius if ($tl > 0) { $tl -= ($wt + $wl) / 2; } if ($tr > 0) { $tr -= ($wt + $wr) / 2; } if ($br > 0) { $br -= ($wb + $wr) / 2; } if ($bl > 0) { $bl -= ($wb + $wl) / 2; } $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl); } $src = $frame->get_image_url(); $alt = null; if (Cache::is_broken($src) && ($alt = $frame->get_node()->getAttribute("alt"))) { $font = $style->font_family; $size = $style->font_size; $spacing = $style->word_spacing; $this->_canvas->text($x, $y, $alt, $font, $size, $style->color, $spacing); } else { $this->_canvas->image($src, $x, $y, $w, $h, $style->image_resolution); } if ($has_border_radius) { $this->_canvas->clipping_end(); } if ($msg = $frame->get_image_msg()) { $parts = preg_split("/\\s*\n\\s*/", $msg); $height = 10; $_y = $alt ? $y + $h - count($parts) * $height : $y; foreach ($parts as $i => $_part) { $this->_canvas->text($x, $_y + $i * $height, $_part, "times", $height * 0.8, array(0.5, 0.5, 0.5)); } } if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutBlocks()) { $this->_debug_layout($frame->get_border_box(), "blue"); if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) { $this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5)); } } }
function render(Frame $frame) { $style = $frame->get_style(); $font_size = $style->get_font_size(); $line_height = $style->length_in_pt($style->line_height, $frame->get_containing_block("w")); $this->_set_opacity($frame->get_opacity($style->opacity)); $li = $frame->get_parent(); // Don't render bullets twice if if was split if ($li->_splitted) { return; } // Handle list-style-image // If list style image is requested but missing, fall back to predefined types if ($style->list_style_image !== "none" && !Cache::is_broken($img = $frame->get_image_url())) { list($x, $y) = $frame->get_position(); //For expected size and aspect, instead of box size, use image natural size scaled to DPI. // Resample the bullet image to be consistent with 'auto' sized images // See also Image::get_min_max_width // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary. //$w = $frame->get_width(); //$h = $frame->get_height(); list($width, $height) = Helpers::dompdf_getimagesize($img, $this->_dompdf->getHttpContext()); $dpi = $this->_dompdf->getOptions()->getDpi(); $w = (double) rtrim($width, "px") * 72 / $dpi; $h = (double) rtrim($height, "px") * 72 / $dpi; $x -= $w; $y -= ($line_height - $font_size) / 2; //Reverse hinting of list_bullet_positioner $this->_canvas->image($img, $x, $y, $w, $h); } else { $bullet_style = $style->list_style_type; $fill = false; switch ($bullet_style) { default: case "disc": $fill = true; case "circle": list($x, $y) = $frame->get_position(); $r = $font_size * ListBulletFrameDecorator::BULLET_SIZE / 2; $x -= $font_size * (ListBulletFrameDecorator::BULLET_SIZE / 2); $y += $font_size * (1 - ListBulletFrameDecorator::BULLET_DESCENT) / 2; $o = $font_size * ListBulletFrameDecorator::BULLET_THICKNESS; $this->_canvas->circle($x, $y, $r, $style->color, $o, null, $fill); break; case "square": list($x, $y) = $frame->get_position(); $w = $font_size * ListBulletFrameDecorator::BULLET_SIZE; $x -= $w; $y += $font_size * (1 - ListBulletFrameDecorator::BULLET_DESCENT - ListBulletFrameDecorator::BULLET_SIZE) / 2; $this->_canvas->filled_rectangle($x, $y, $w, $w, $style->color); break; case "decimal-leading-zero": case "decimal": case "lower-alpha": case "lower-latin": case "lower-roman": case "lower-greek": case "upper-alpha": case "upper-latin": case "upper-roman": case "1": // HTML 4.0 compatibility // HTML 4.0 compatibility case "a": case "i": case "A": case "I": $pad = null; if ($bullet_style === "decimal-leading-zero") { $pad = strlen($li->get_parent()->get_node()->getAttribute("dompdf-children-count")); } $node = $frame->get_node(); if (!$node->hasAttribute("dompdf-counter")) { return; } $index = $node->getAttribute("dompdf-counter"); $text = $this->make_counter($index, $bullet_style, $pad); if (trim($text) == "") { return; } $spacing = 0; $font_family = $style->font_family; $line = $li->get_containing_line(); list($x, $y) = array($frame->get_position("x"), $line->y); $x -= $this->_dompdf->getFontMetrics()->getTextWidth($text, $font_family, $font_size, $spacing); // Take line-height into account $line_height = $style->line_height; $y += ($line_height - $font_size) / 4; // FIXME I thought it should be 2, but 4 gives better results $this->_canvas->text($x, $y, $text, $font_family, $font_size, $style->color, $spacing); case "none": break; } } }
/** * @param integer $i * * @return array|float */ function get_containing_block($i = null) { return $this->_frame->get_containing_block($i); }
/** * @param \Dompdf\FrameDecorator\Text $frame */ function render(Frame $frame) { $text = $frame->get_text(); if (trim($text) === "") { return; } $style = $frame->get_style(); list($x, $y) = $frame->get_position(); $cb = $frame->get_containing_block(); if (($ml = $style->margin_left) === "auto" || $ml === "none") { $ml = 0; } if (($pl = $style->padding_left) === "auto" || $pl === "none") { $pl = 0; } if (($bl = $style->border_left_width) === "auto" || $bl === "none") { $bl = 0; } $x += $style->length_in_pt(array($ml, $pl, $bl), $cb["w"]); $font = $style->font_family; $size = $frame_font_size = $style->font_size; $height = $style->height; $word_spacing = $frame->get_text_spacing() + $style->length_in_pt($style->word_spacing); $char_spacing = $style->length_in_pt($style->letter_spacing); $width = $style->width; /*$text = str_replace( array("{PAGE_NUM}"), array($this->_canvas->get_page_number()), $text );*/ $this->_canvas->text($x, $y, $text, $font, $size, $style->color, $word_spacing, $char_spacing); $line = $frame->get_containing_line(); // FIXME Instead of using the tallest frame to position, // the decoration, the text should be well placed if (false && $line->tallest_frame) { $base_frame = $line->tallest_frame; $style = $base_frame->get_style(); $size = $style->font_size; $height = $line->h * ($size / $style->line_height); } $line_thickness = $size * self::DECO_THICKNESS; $underline_offset = $size * self::UNDERLINE_OFFSET; $overline_offset = $size * self::OVERLINE_OFFSET; $linethrough_offset = $size * self::LINETHROUGH_OFFSET; $underline_position = -0.08; if ($this->_canvas instanceof CPDF) { $cpdf_font = $this->_canvas->get_cpdf()->fonts[$style->font_family]; if (isset($cpdf_font["UnderlinePosition"])) { $underline_position = $cpdf_font["UnderlinePosition"] / 1000; } if (isset($cpdf_font["UnderlineThickness"])) { $line_thickness = $size * ($cpdf_font["UnderlineThickness"] / 1000); } } $descent = $size * $underline_position; $base = $size; // Handle text decoration: // http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration // Draw all applicable text-decorations. Start with the root and work our way down. $p = $frame; $stack = array(); while ($p = $p->get_parent()) { $stack[] = $p; } while (isset($stack[0])) { $f = array_pop($stack); if (($text_deco = $f->get_style()->text_decoration) === "none") { continue; } $deco_y = $y; //$line->y; $color = $f->get_style()->color; switch ($text_deco) { default: continue; case "underline": $deco_y += $base - $descent + $underline_offset + $line_thickness / 2; break; case "overline": $deco_y += $overline_offset + $line_thickness / 2; break; case "line-through": $deco_y += $base * 0.7 + $linethrough_offset; break; } $dx = 0; $x1 = $x - self::DECO_EXTENSION; $x2 = $x + $width + $dx + self::DECO_EXTENSION; $this->_canvas->line($x1, $deco_y, $x2, $deco_y, $color, $line_thickness); } if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines()) { $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $frame_font_size); $this->_debug_layout(array($x, $y, $text_width + ($line->wc - 1) * $word_spacing, $frame_font_size), "orange", array(0.5, 0.5)); } }