PageRenderTime 43ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/application/helpers/dompdf/include/abstract_renderer.cls.php

https://bitbucket.org/hlevine/myclientbase-south-african-version
PHP | 850 lines | 506 code | 162 blank | 182 comment | 127 complexity | d84ebff6b66befb9816445df28ca5a03 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. <?php
  2. /**
  3. * DOMPDF - PHP5 HTML to PDF renderer
  4. *
  5. * File: $RCSfile: abstract_renderer.cls.php,v $
  6. * Created on: 2004-06-01
  7. *
  8. * Copyright (c) 2004 - Benj Carson <benjcarson@digitaljunkies.ca>
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public License
  21. * along with this library in the file LICENSE.LGPL; if not, write to the
  22. * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  23. * 02111-1307 USA
  24. *
  25. * Alternatively, you may distribute this software under the terms of the
  26. * PHP License, version 3.0 or later. A copy of this license should have
  27. * been distributed with this file in the file LICENSE.PHP . If this is not
  28. * the case, you can obtain a copy at http://www.php.net/license/3_0.txt.
  29. *
  30. * The latest version of DOMPDF might be available at:
  31. * http://www.digitaljunkies.ca/dompdf
  32. *
  33. * @link http://www.digitaljunkies.ca/dompdf
  34. * @copyright 2004 Benj Carson
  35. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  36. * @contributor Helmut Tischer <htischer@weihenstephan.org>
  37. * @package dompdf
  38. * @version 0.5.1
  39. *
  40. * Changes
  41. * @contributor Helmut Tischer <htischer@weihenstephan.org>
  42. * @version 0.5.1.htischer.20090507
  43. * - On background image
  44. * - Clip invisible areas from background images, then merge identical
  45. * image/size/offset to a single image.
  46. * - Fix rounding of background image size.
  47. * - Fix background image position given as percent
  48. * - Check if identical image is already cached by cpdf. Then do not create
  49. * duplicates to save memory and CPU time
  50. * - Fix skipping of image repetition if area is too small
  51. * - Do not create temporary files, but pass gd object directly
  52. */
  53. /* $Id: abstract_renderer.cls.php,v 1.6 2006-07-07 21:31:02 benjcarson Exp $ */
  54. /**
  55. * Base renderer class
  56. *
  57. * @access private
  58. * @package dompdf
  59. */
  60. abstract class Abstract_Renderer {
  61. /**
  62. * Rendering backend
  63. *
  64. * @var Canvas
  65. */
  66. protected $_canvas;
  67. /**
  68. * Current dompdf instance
  69. *
  70. * @var DOMPDF
  71. */
  72. protected $_dompdf;
  73. /**
  74. * Class constructor
  75. *
  76. * @param DOMPDF $dompdf The current dompdf instance
  77. */
  78. function __construct(DOMPDF $dompdf) {
  79. $this->_dompdf = $dompdf;
  80. $this->_canvas = $dompdf->get_canvas();
  81. }
  82. /**
  83. * Render a frame.
  84. *
  85. * Specialized in child classes
  86. *
  87. * @param Frame $frame The frame to render
  88. */
  89. abstract function render(Frame $frame);
  90. //........................................................................
  91. /**
  92. * Render a background image over a rectangular area
  93. *
  94. * @param string $img The background image to load
  95. * @param float $x The left edge of the rectangular area
  96. * @param float $y The top edge of the rectangular area
  97. * @param float $width The width of the rectangular area
  98. * @param float $height The height of the rectangular area
  99. * @param Style $style The associated Style object
  100. */
  101. protected function _background_image($url, $x, $y, $width, $height, $style) {
  102. $sheet = $style->get_stylesheet();
  103. // Skip degenerate cases
  104. if ( $width == 0 || $height == 0 )
  105. return;
  106. //debugpng
  107. if (DEBUGPNG) print '[_background_image '.$url.']';
  108. list($img, $ext) = Image_Cache::resolve_url($url,
  109. $sheet->get_protocol(),
  110. $sheet->get_host(),
  111. $sheet->get_base_path());
  112. // Bail if the image is no good
  113. if ( $img == DOMPDF_LIB_DIR . "/res/broken_image.png" )
  114. return;
  115. //Try to optimize away reading and composing of same background multiple times
  116. //Postponing read with imagecreatefrom ...()
  117. //final composition paramters and name not known yet
  118. //Therefore read dimension directly from file, instead of creating gd object first.
  119. //$img_w = imagesx($src); $img_h = imagesy($src);
  120. list($img_w, $img_h) = getimagesize($img);
  121. if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) {
  122. return;
  123. }
  124. $repeat = $style->background_repeat;
  125. $bg_color = $style->background_color;
  126. //Increase background resolution and dependent box size according to image resolution to be placed in
  127. //Then image can be copied in without resize
  128. $bg_width = round((float)($width * DOMPDF_DPI) / 72);
  129. $bg_height = round((float)($height * DOMPDF_DPI) / 72);
  130. //Need %bg_x, $bg_y as background pos, where img starts, converted to pixel
  131. list($bg_x, $bg_y) = $style->background_position;
  132. if ( is_percent($bg_x) ) {
  133. // The point $bg_x % from the left edge of the image is placed
  134. // $bg_x % from the left edge of the background rectangle
  135. $p = ((float)$bg_x)/100.0;
  136. $x1 = $p * $img_w;
  137. $x2 = $p * $bg_width;
  138. $bg_x = round($x2 - $x1);
  139. } else {
  140. $bg_x = round((float)($style->length_in_pt($bg_x)*DOMPDF_DPI) / 72);
  141. }
  142. if ( is_percent($bg_y) ) {
  143. // The point $bg_y % from the left edge of the image is placed
  144. // $bg_y % from the left edge of the background rectangle
  145. $p = ((float)$bg_y)/100.0;
  146. $y1 = $p * $img_h;
  147. $y2 = $p * $bg_height;
  148. $bg_y = round($y2 - $y1);
  149. } else {
  150. $bg_y = round((float)($style->length_in_pt($bg_y)*DOMPDF_DPI) / 72);
  151. }
  152. //clip background to the image area on partial repeat. Nothing to do if img off area
  153. //On repeat, normalize start position to the tile at immediate left/top or 0/0 of area
  154. //On no repeat with positive offset: move size/start to have offset==0
  155. //Handle x/y Dimensions separately
  156. if ( $repeat != "repeat" && $repeat != "repeat-x" ) {
  157. //No repeat x
  158. if ($bg_x < 0) {
  159. $bg_width = $img_w + $bg_x;
  160. } else {
  161. $x += ($bg_x * 72)/DOMPDF_DPI;
  162. $bg_width = $bg_width - $bg_x;
  163. if ($bg_width > $img_w) {
  164. $bg_width = $img_w;
  165. }
  166. $bg_x = 0;
  167. }
  168. if ($bg_width <= 0) {
  169. return;
  170. }
  171. $width = (float)($bg_width * 72)/DOMPDF_DPI;
  172. } else {
  173. //repeat x
  174. if ($bg_x < 0) {
  175. $bg_x = - ((-$bg_x) % $img_w);
  176. } else {
  177. $bg_x = $bg_x % $img_w;
  178. if ($bg_x > 0) {
  179. $bg_x -= $img_w;
  180. }
  181. }
  182. }
  183. if ( $repeat != "repeat" && $repeat != "repeat-y" ) {
  184. //no repeat y
  185. if ($bg_y < 0) {
  186. $bg_height = $img_h + $bg_y;
  187. } else {
  188. $y += ($bg_y * 72)/DOMPDF_DPI;
  189. $bg_height = $bg_height - $bg_y;
  190. if ($bg_height > $img_h) {
  191. $bg_height = $img_h;
  192. }
  193. $bg_y = 0;
  194. }
  195. if ($bg_height <= 0) {
  196. return;
  197. }
  198. $height = (float)($bg_height * 72)/DOMPDF_DPI;
  199. } else {
  200. //repeat y
  201. if ($bg_y < 0) {
  202. $bg_y = - ((-$bg_y) % $img_h);
  203. } else {
  204. $bg_y = $bg_y % $img_h;
  205. if ($bg_y > 0) {
  206. $bg_y -= $img_h;
  207. }
  208. }
  209. }
  210. //Optimization, if repeat has no effect
  211. if ( $repeat == "repeat" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height ) {
  212. $repeat = "repeat-x";
  213. }
  214. if ( $repeat == "repeat" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width ) {
  215. $repeat = "repeat-y";
  216. }
  217. if ( ($repeat == "repeat-x" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width) ||
  218. ($repeat == "repeat-y" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height) ) {
  219. $repeat = "no-repeat";
  220. }
  221. //Use filename as indicator only
  222. //different names for different variants to have different copies in the pdf
  223. //This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color)
  224. //Note: Here, bg_* are the start values, not end values after going through the tile loops!
  225. $filedummy = $img;
  226. /*
  227. //Make shorter strings with limited characters for cache associative array index - needed?
  228. //Strip common base path - server root, explicite temp, default temp; remove unwanted characters;
  229. $filedummy = strtr($filedummy,"\\:","//");
  230. $p = strtr($_SERVER["DOCUMENT_ROOT"],"\\:","//");
  231. $l = strlen($p);
  232. if ( substr($filedummy,0,$l) == $p) {
  233. $filedummy = substr($filedummy,$l);
  234. } else {
  235. $p = strtr(DOMPDF_TEMP_DIR,"\\:","//");
  236. $l = strlen($p);
  237. if ( substr($filedummy,0,$l) == $p) {
  238. $filedummy = substr($filedummy,$l);
  239. } else {
  240. $p = strtr(sys_get_temp_dir(),"\\:","//");
  241. $l = strlen($p);
  242. if ( substr($filedummy,0,$l) == $p) {
  243. $filedummy = substr($filedummy,$l);
  244. }
  245. }
  246. }
  247. */
  248. $filedummy .= '_'.$bg_width.'_'.$bg_height.'_'.$bg_x.'_'.$bg_y.'_'.$repeat;
  249. //debugpng
  250. //if (DEBUGPNG) print '<pre>[_background_image name '.$filedummy.']</pre>';
  251. //Optimization to avoid multiple times rendering the same image.
  252. //If check functions are existing and identical image already cached,
  253. //then skip creation of duplicate, because it is not needed by addImagePng
  254. if ( method_exists( $this->_canvas, "get_cpdf" ) &&
  255. method_exists( $this->_canvas->get_cpdf(), "addImagePng" ) &&
  256. method_exists( $this->_canvas->get_cpdf(), "image_iscached" ) &&
  257. $this->_canvas->get_cpdf()->image_iscached($filedummy) ) {
  258. $bg = null;
  259. //debugpng
  260. //if (DEBUGPNG) print '[_background_image skip]';
  261. } else {
  262. // Create a new image to fit over the background rectangle
  263. $bg = imagecreatetruecolor($bg_width, $bg_height);
  264. //anyway default
  265. //imagealphablending($img, true);
  266. switch (strtolower($ext)) {
  267. case "png":
  268. $src = imagecreatefrompng($img);
  269. break;
  270. case "jpg":
  271. case "jpeg":
  272. $src = imagecreatefromjpeg($img);
  273. break;
  274. case "gif":
  275. $src = imagecreatefromgif($img);
  276. break;
  277. default:
  278. return; // Unsupported image type
  279. }
  280. if ($src == null) {
  281. return;
  282. }
  283. //Background color if box is not relevant here
  284. //Non transparent image: box clipped to real size. Background non relevant.
  285. //Transparent image: The image controls the transparency and lets shine through whatever background.
  286. //However on transparent imaage preset the composed image with the transparency color,
  287. //to keep the transparency when copying over the non transparent parts of the tiles.
  288. $ti = imagecolortransparent($src);
  289. if ($ti >= 0) {
  290. $tc = imagecolorsforindex($src,$ti);
  291. $ti = imagecolorallocate($bg,$tc['red'],$tc['green'],$tc['blue']);
  292. imagefill($bg,0,0,$ti);
  293. imagecolortransparent($bg, $ti);
  294. }
  295. //This has only an effect for the non repeatable dimension.
  296. //compute start of src and dest coordinates of the single copy
  297. if ( $bg_x < 0 ) {
  298. $dst_x = 0;
  299. $src_x = -$bg_x;
  300. } else {
  301. $src_x = 0;
  302. $dst_x = $bg_x;
  303. }
  304. if ( $bg_y < 0 ) {
  305. $dst_y = 0;
  306. $src_y = -$bg_y;
  307. } else {
  308. $src_y = 0;
  309. $dst_y = $bg_y;
  310. }
  311. //For historical reasons exchange meanings of variables:
  312. //start_* will be the start values, while bg_* will be the temporary start values in the loops
  313. $start_x = $bg_x;
  314. $start_y = $bg_y;
  315. // Copy regions from the source image to the background
  316. if ( $repeat == "no-repeat" ) {
  317. // Simply place the image on the background
  318. imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h);
  319. } else if ( $repeat == "repeat-x" ) {
  320. for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
  321. if ( $bg_x < 0 ) {
  322. $dst_x = 0;
  323. $src_x = -$bg_x;
  324. $w = $img_w + $bg_x;
  325. } else {
  326. $dst_x = $bg_x;
  327. $src_x = 0;
  328. $w = $img_w;
  329. }
  330. imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h);
  331. }
  332. } else if ( $repeat == "repeat-y" ) {
  333. for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
  334. if ( $bg_y < 0 ) {
  335. $dst_y = 0;
  336. $src_y = -$bg_y;
  337. $h = $img_h + $bg_y;
  338. } else {
  339. $dst_y = $bg_y;
  340. $src_y = 0;
  341. $h = $img_h;
  342. }
  343. imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h);
  344. }
  345. } else if ( $repeat == "repeat" ) {
  346. for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) {
  347. for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) {
  348. if ( $bg_x < 0 ) {
  349. $dst_x = 0;
  350. $src_x = -$bg_x;
  351. $w = $img_w + $bg_x;
  352. } else {
  353. $dst_x = $bg_x;
  354. $src_x = 0;
  355. $w = $img_w;
  356. }
  357. if ( $bg_y < 0 ) {
  358. $dst_y = 0;
  359. $src_y = -$bg_y;
  360. $h = $img_h + $bg_y;
  361. } else {
  362. $dst_y = $bg_y;
  363. $src_y = 0;
  364. $h = $img_h;
  365. }
  366. imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h);
  367. }
  368. }
  369. } else {
  370. print 'Unknown repeat!';
  371. }
  372. } /* End optimize away creation of duplicates */
  373. //img: image url string
  374. //img_w, img_h: original image size in px
  375. //width, height: box size in pt
  376. //bg_width, bg_height: box size in px
  377. //x, y: left/top edge of box on page in pt
  378. //start_x, start_y: placement of image relativ to pattern
  379. //$repeat: repeat mode
  380. //$bg: GD object of result image
  381. //$src: GD object of original image
  382. //When using cpdf and optimization to direct png creation from gd object is available,
  383. //don't create temp file, but place gd object directly into the pdf
  384. if ( method_exists( $this->_canvas, "get_cpdf" ) && method_exists( $this->_canvas->get_cpdf(), "addImagePng" ) ) {
  385. //Note: CPDF_Adapter image converts y position
  386. $this->_canvas->get_cpdf()->addImagePng(
  387. $filedummy,
  388. $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg);
  389. } else {
  390. $tmp_file = tempnam(DOMPDF_TEMP_DIR, "bg_dompdf_img_").'.png';
  391. //debugpng
  392. if (DEBUGPNG) print '[_background_image '.$tmp_file.']';
  393. imagepng($bg, $tmp_file);
  394. $this->_canvas->image($tmp_file, "png", $x, $y, $width, $height);
  395. //debugpng
  396. if (DEBUGPNG) print '[_background_image unlink '.$tmp_file.']';
  397. if (!DEBUGKEEPTEMP)
  398. unlink($tmp_file);
  399. }
  400. }
  401. protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  402. return;
  403. }
  404. // Border rendering functions
  405. protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  406. list($top, $right, $bottom, $left) = $widths;
  407. if ( $$side < 2 )
  408. $dash = array($$side, 2);
  409. else
  410. $dash = array($$side);
  411. switch ($side) {
  412. case "top":
  413. $delta = $top / 2;
  414. case "bottom":
  415. $delta = isset($delta) ? $delta : -$bottom / 2;
  416. $this->_canvas->line($x, $y + $delta, $x + $length, $y + $delta, $color, $$side, $dash);
  417. break;
  418. case "left":
  419. $delta = $left / 2;
  420. case "right":
  421. $delta = isset($delta) ? $delta : - $right / 2;
  422. $this->_canvas->line($x + $delta, $y, $x + $delta, $y + $length, $color, $$side, $dash);
  423. break;
  424. default:
  425. return;
  426. }
  427. }
  428. protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  429. list($top, $right, $bottom, $left) = $widths;
  430. switch ($side) {
  431. case "top":
  432. $delta = $top / 2;
  433. case "bottom":
  434. $delta = isset($delta) ? $delta : -$bottom / 2;
  435. $this->_canvas->line($x, $y + $delta, $x + $length, $y + $delta, $color, $$side, array(3 * $$side));
  436. break;
  437. case "left":
  438. $delta = $left / 2;
  439. case "right":
  440. $delta = isset($delta) ? $delta : - $right / 2;
  441. $this->_canvas->line($x + $delta, $y, $x + $delta, $y + $length, $color, $$side, array(3 * $$side));
  442. break;
  443. default:
  444. return;
  445. }
  446. }
  447. protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  448. list($top, $right, $bottom, $left) = $widths;
  449. // All this polygon business is for beveled corners...
  450. switch ($side) {
  451. case "top":
  452. if ( $corner_style == "bevel" ) {
  453. $points = array($x, $y,
  454. $x + $length, $y,
  455. $x + $length - $right, $y + $top,
  456. $x + $left, $y + $top);
  457. $this->_canvas->polygon($points, $color, null, null, true);
  458. } else
  459. $this->_canvas->filled_rectangle($x, $y, $length, $top, $color);
  460. break;
  461. case "bottom":
  462. if ( $corner_style == "bevel" ) {
  463. $points = array($x, $y,
  464. $x + $length, $y,
  465. $x + $length - $right, $y - $bottom,
  466. $x + $left, $y - $bottom);
  467. $this->_canvas->polygon($points, $color, null, null, true);
  468. } else
  469. $this->_canvas->filled_rectangle($x, $y - $bottom, $length, $bottom, $color);
  470. break;
  471. case "left":
  472. if ( $corner_style == "bevel" ) {
  473. $points = array($x, $y,
  474. $x, $y + $length,
  475. $x + $left, $y + $length - $bottom,
  476. $x + $left, $y + $top);
  477. $this->_canvas->polygon($points, $color, null, null, true);
  478. } else
  479. $this->_canvas->filled_rectangle($x, $y, $left, $length, $color);
  480. break;
  481. case "right":
  482. if ( $corner_style == "bevel" ) {
  483. $points = array($x, $y,
  484. $x, $y + $length,
  485. $x - $right, $y + $length - $bottom,
  486. $x - $right, $y + $top);
  487. $this->_canvas->polygon($points, $color, null, null, true);
  488. } else
  489. $this->_canvas->filled_rectangle($x - $right, $y, $right, $length, $color);
  490. break;
  491. default:
  492. return;
  493. }
  494. }
  495. protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  496. list($top, $right, $bottom, $left) = $widths;
  497. $line_width = $$side / 4;
  498. // We draw the outermost edge first. Points are ordered: outer left,
  499. // outer right, inner right, inner left, or outer top, outer bottom,
  500. // inner bottom, inner top.
  501. switch ($side) {
  502. case "top":
  503. if ( $corner_style == "bevel" ) {
  504. $left_line_width = $left / 4;
  505. $right_line_width = $right / 4;
  506. $points = array($x, $y,
  507. $x + $length, $y,
  508. $x + $length - $right_line_width, $y + $line_width,
  509. $x + $left_line_width, $y + $line_width,);
  510. $this->_canvas->polygon($points, $color, null, null, true);
  511. $points = array($x + $left - $left_line_width, $y + $top - $line_width,
  512. $x + $length - $right + $right_line_width, $y + $top - $line_width,
  513. $x + $length - $right, $y + $top,
  514. $x + $left, $y + $top);
  515. $this->_canvas->polygon($points, $color, null, null, true);
  516. } else {
  517. $this->_canvas->filled_rectangle($x, $y, $length, $line_width, $color);
  518. $this->_canvas->filled_rectangle($x, $y + $top - $line_width, $length, $line_width, $color);
  519. }
  520. break;
  521. case "bottom":
  522. if ( $corner_style == "bevel" ) {
  523. $left_line_width = $left / 4;
  524. $right_line_width = $right / 4;
  525. $points = array($x, $y,
  526. $x + $length, $y,
  527. $x + $length - $right_line_width, $y - $line_width,
  528. $x + $left_line_width, $y - $line_width);
  529. $this->_canvas->polygon($points, $color, null, null, true);
  530. $points = array($x + $left - $left_line_width, $y - $bottom + $line_width,
  531. $x + $length - $right + $right_line_width, $y - $bottom + $line_width,
  532. $x + $length - $right, $y - $bottom,
  533. $x + $left, $y - $bottom);
  534. $this->_canvas->polygon($points, $color, null, null, true);
  535. } else {
  536. $this->_canvas->filled_rectangle($x, $y - $line_width, $length, $line_width, $color);
  537. $this->_canvas->filled_rectangle($x, $y - $bottom, $length, $line_width, $color);
  538. }
  539. break;
  540. case "left":
  541. if ( $corner_style == "bevel" ) {
  542. $top_line_width = $top / 4;
  543. $bottom_line_width = $bottom / 4;
  544. $points = array($x, $y,
  545. $x, $y + $length,
  546. $x + $line_width, $y + $length - $bottom_line_width,
  547. $x + $line_width, $y + $top_line_width);
  548. $this->_canvas->polygon($points, $color, null, null, true);
  549. $points = array($x + $left - $line_width, $y + $top - $top_line_width,
  550. $x + $left - $line_width, $y + $length - $bottom + $bottom_line_width,
  551. $x + $left, $y + $length - $bottom,
  552. $x + $left, $y + $top);
  553. $this->_canvas->polygon($points, $color, null, null, true);
  554. } else {
  555. $this->_canvas->filled_rectangle($x, $y, $line_width, $length, $color);
  556. $this->_canvas->filled_rectangle($x + $left - $line_width, $y, $line_width, $length, $color);
  557. }
  558. break;
  559. case "right":
  560. if ( $corner_style == "bevel" ) {
  561. $top_line_width = $top / 4;
  562. $bottom_line_width = $bottom / 4;
  563. $points = array($x, $y,
  564. $x, $y + $length,
  565. $x - $line_width, $y + $length - $bottom_line_width,
  566. $x - $line_width, $y + $top_line_width);
  567. $this->_canvas->polygon($points, $color, null, null, true);
  568. $points = array($x - $right + $line_width, $y + $top - $top_line_width,
  569. $x - $right + $line_width, $y + $length - $bottom + $bottom_line_width,
  570. $x - $right, $y + $length - $bottom,
  571. $x - $right, $y + $top);
  572. $this->_canvas->polygon($points, $color, null, null, true);
  573. } else {
  574. $this->_canvas->filled_rectangle($x - $line_width, $y, $line_width, $length, $color);
  575. $this->_canvas->filled_rectangle($x - $right, $y, $line_width, $length, $color);
  576. }
  577. break;
  578. default:
  579. return;
  580. }
  581. }
  582. protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  583. list($top, $right, $bottom, $left) = $widths;
  584. $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
  585. $this->_border_inset($x, $y, $length, $color, $half_widths, $side);
  586. switch ($side) {
  587. case "top":
  588. $x += $left / 2;
  589. $y += $top / 2;
  590. $length -= $left / 2 + $right / 2;
  591. break;
  592. case "bottom":
  593. $x += $left / 2;
  594. $y -= $bottom / 2;
  595. $length -= $left / 2 + $right / 2;
  596. break;
  597. case "left":
  598. $x += $left / 2;
  599. $y += $top / 2;
  600. $length -= $top / 2 + $bottom / 2;
  601. break;
  602. case "right":
  603. $x -= $right / 2;
  604. $y += $top / 2;
  605. $length -= $top / 2 + $bottom / 2;
  606. break;
  607. default:
  608. return;
  609. }
  610. $this->_border_outset($x, $y, $length, $color, $half_widths, $side);
  611. }
  612. protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  613. list($top, $right, $bottom, $left) = $widths;
  614. $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2);
  615. $this->_border_outset($x, $y, $length, $color, $half_widths, $side);
  616. switch ($side) {
  617. case "top":
  618. $x += $left / 2;
  619. $y += $top / 2;
  620. $length -= $left / 2 + $right / 2;
  621. break;
  622. case "bottom":
  623. $x += $left / 2;
  624. $y -= $bottom / 2;
  625. $length -= $left / 2 + $right / 2;
  626. break;
  627. case "left":
  628. $x += $left / 2;
  629. $y += $top / 2;
  630. $length -= $top / 2 + $bottom / 2;
  631. break;
  632. case "right":
  633. $x -= $right / 2;
  634. $y += $top / 2;
  635. $length -= $top / 2 + $bottom / 2;
  636. break;
  637. default:
  638. return;
  639. }
  640. $this->_border_inset($x, $y, $length, $color, $half_widths, $side);
  641. }
  642. protected function _tint($c) {
  643. if ( !is_numeric($c) )
  644. return $c;
  645. return min(1, $c + 0.66);
  646. }
  647. protected function _shade($c) {
  648. if ( !is_numeric($c) )
  649. return $c;
  650. return max(0, $c - 0.66);
  651. }
  652. protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  653. list($top, $right, $bottom, $left) = $widths;
  654. switch ($side) {
  655. case "top":
  656. case "left":
  657. $shade = array_map(array($this, "_shade"), $color);
  658. $this->_border_solid($x, $y, $length, $shade, $widths, $side);
  659. break;
  660. case "bottom":
  661. case "right":
  662. $tint = array_map(array($this, "_tint"), $color);
  663. $this->_border_solid($x, $y, $length, $tint, $widths, $side);
  664. break;
  665. default:
  666. return;
  667. }
  668. }
  669. protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel") {
  670. list($top, $right, $bottom, $left) = $widths;
  671. switch ($side) {
  672. case "top":
  673. case "left":
  674. $tint = array_map(array($this, "_tint"), $color);
  675. $this->_border_solid($x, $y, $length, $tint, $widths, $side);
  676. break;
  677. case "bottom":
  678. case "right":
  679. $shade = array_map(array($this, "_shade"), $color);
  680. $this->_border_solid($x, $y, $length, $shade, $widths, $side);
  681. break;
  682. default:
  683. return;
  684. }
  685. }
  686. //........................................................................
  687. }
  688. ?>