From 91b18d032f0ce4123ce55398499150df7a798134 Mon Sep 17 00:00:00 2001 From: jekkos Date: Wed, 7 Sep 2016 08:47:46 +0200 Subject: [PATCH] Replace DOMPDF, GaTracking with composer managed dependencies (#624) Fix trim on search bug (#838) --- Gruntfile.js | 2 +- application/helpers/dompdf/README.md | 131 - application/helpers/dompdf/composer.json | 23 - application/helpers/dompdf/dompdf.php | 289 - .../dompdf/dompdf_config.custom.inc.php | 31 - .../helpers/dompdf/dompdf_config.inc.php | 393 - .../include/absolute_positioner.cls.php | 125 - .../dompdf/include/abstract_renderer.cls.php | 759 -- .../include/attribute_translator.cls.php | 592 -- .../helpers/dompdf/include/autoload.inc.php | 86 - .../include/block_frame_decorator.cls.php | 234 - .../include/block_frame_reflower.cls.php | 805 -- .../dompdf/include/block_positioner.cls.php | 57 - .../dompdf/include/block_renderer.cls.php | 230 - .../include/cached_pdf_decorator.cls.php | 164 - .../helpers/dompdf/include/canvas.cls.php | 385 - .../dompdf/include/canvas_factory.cls.php | 63 - .../helpers/dompdf/include/cellmap.cls.php | 790 -- .../dompdf/include/cpdf_adapter.cls.php | 877 -- .../helpers/dompdf/include/css_color.cls.php | 287 - .../helpers/dompdf/include/dompdf.cls.php | 1077 --- .../dompdf/include/dompdf_exception.cls.php | 26 - .../include/dompdf_image_exception.cls.php | 26 - application/helpers/dompdf/include/file.skel | 8 - .../dompdf/include/fixed_positioner.cls.php | 88 - .../dompdf/include/font_metrics.cls.php | 363 - .../helpers/dompdf/include/frame.cls.php | 1191 --- .../dompdf/include/frame_decorator.cls.php | 717 -- .../dompdf/include/frame_factory.cls.php | 252 - .../dompdf/include/frame_reflower.cls.php | 458 - .../helpers/dompdf/include/frame_tree.cls.php | 241 - .../helpers/dompdf/include/functions.inc.php | 1054 --- .../helpers/dompdf/include/gd_adapter.cls.php | 840 -- .../dompdf/include/image_cache.cls.php | 183 - .../include/image_frame_decorator.cls.php | 80 - .../include/image_frame_reflower.cls.php | 186 - .../dompdf/include/image_renderer.cls.php | 119 - .../include/inline_frame_decorator.cls.php | 74 - .../include/inline_frame_reflower.cls.php | 66 - .../dompdf/include/inline_positioner.cls.php | 70 - .../dompdf/include/inline_renderer.cls.php | 190 - .../include/javascript_embedder.cls.php | 37 - .../helpers/dompdf/include/line_box.cls.php | 252 - .../list_bullet_frame_decorator.cls.php | 65 - .../list_bullet_frame_reflower.cls.php | 33 - .../list_bullet_image_frame_decorator.cls.php | 143 - .../include/list_bullet_positioner.cls.php | 73 - .../include/list_bullet_renderer.cls.php | 236 - .../include/null_frame_decorator.cls.php | 26 - .../include/null_frame_reflower.cls.php | 21 - .../dompdf/include/null_positioner.cls.php | 23 - .../helpers/dompdf/include/page_cache.cls.php | 126 - .../include/page_frame_decorator.cls.php | 592 -- .../include/page_frame_reflower.cls.php | 186 - .../dompdf/include/pdflib_adapter.cls.php | 1085 --- .../dompdf/include/php_evaluator.cls.php | 48 - .../helpers/dompdf/include/positioner.cls.php | 51 - .../helpers/dompdf/include/renderer.cls.php | 290 - .../helpers/dompdf/include/style.cls.php | 2435 ------ .../helpers/dompdf/include/stylesheet.cls.php | 1418 --- .../table_cell_frame_decorator.cls.php | 102 - .../include/table_cell_frame_reflower.cls.php | 119 - .../include/table_cell_positioner.cls.php | 28 - .../include/table_cell_renderer.cls.php | 155 - .../include/table_frame_decorator.cls.php | 334 - .../include/table_frame_reflower.cls.php | 578 -- .../include/table_row_frame_decorator.cls.php | 48 - .../include/table_row_frame_reflower.cls.php | 61 - .../table_row_group_frame_decorator.cls.php | 66 - .../table_row_group_frame_reflower.cls.php | 59 - .../include/table_row_group_renderer.cls.php | 40 - .../include/table_row_positioner.cls.php | 35 - .../dompdf/include/tcpdf_adapter.cls.php | 628 -- .../include/text_frame_decorator.cls.php | 173 - .../include/text_frame_reflower.cls.php | 441 - .../dompdf/include/text_renderer.cls.php | 152 - application/helpers/dompdf/lib/class.pdf.php | 4617 ---------- .../dompdf/lib/fonts/DejaVuSans-Bold.ufm | 5734 ------------- .../lib/fonts/DejaVuSans-BoldOblique.ufm | 5434 ------------ .../lib/fonts/DejaVuSans-ExtraLight.ttf | Bin 338436 -> 0 bytes .../lib/fonts/DejaVuSans-ExtraLight.ufm | 7580 ----------------- .../dompdf/lib/fonts/DejaVuSans-Oblique.ufm | 5073 ----------- .../helpers/dompdf/lib/fonts/DejaVuSans.ufm | 6454 -------------- .../lib/fonts/DejaVuSansCondensed-Bold.ttf | Bin 595416 -> 0 bytes .../lib/fonts/DejaVuSansCondensed-Bold.ufm | 5734 ------------- .../fonts/DejaVuSansCondensed-BoldOblique.ttf | Bin 543704 -> 0 bytes .../fonts/DejaVuSansCondensed-BoldOblique.ufm | 5434 ------------ .../lib/fonts/DejaVuSansCondensed-Oblique.ttf | Bin 539024 -> 0 bytes .../lib/fonts/DejaVuSansCondensed-Oblique.ufm | 5073 ----------- .../dompdf/lib/fonts/DejaVuSansCondensed.ttf | Bin 605792 -> 0 bytes .../dompdf/lib/fonts/DejaVuSansCondensed.ufm | 6454 -------------- .../dompdf/lib/fonts/DejaVuSansMono-Bold.ufm | 2974 ------- .../lib/fonts/DejaVuSansMono-BoldOblique.ufm | 2396 ------ .../lib/fonts/DejaVuSansMono-Oblique.ufm | 2524 ------ .../dompdf/lib/fonts/DejaVuSansMono.ufm | 3101 ------- .../dompdf/lib/fonts/DejaVuSerif-Bold.ufm | 3636 -------- .../lib/fonts/DejaVuSerif-BoldItalic.ufm | 3515 -------- .../dompdf/lib/fonts/DejaVuSerif-Italic.ufm | 3634 -------- .../helpers/dompdf/lib/fonts/DejaVuSerif.ufm | 3762 -------- .../lib/fonts/DejaVuSerifCondensed-Bold.ttf | Bin 290556 -> 0 bytes .../lib/fonts/DejaVuSerifCondensed-Bold.ufm | 3636 -------- .../fonts/DejaVuSerifCondensed-BoldItalic.ttf | Bin 302120 -> 0 bytes .../fonts/DejaVuSerifCondensed-BoldItalic.ufm | 3515 -------- .../lib/fonts/DejaVuSerifCondensed-Italic.ttf | Bin 310024 -> 0 bytes .../lib/fonts/DejaVuSerifCondensed-Italic.ufm | 3634 -------- .../dompdf/lib/fonts/DejaVuSerifCondensed.ttf | Bin 304328 -> 0 bytes .../dompdf/lib/fonts/DejaVuSerifCondensed.ufm | 3762 -------- .../dompdf/lib/fonts/Helvetica-Bold.afm.php | 570 -- .../dompdf/lib/fonts/Helvetica.afm.php | 570 -- .../fonts/dompdf_font_family_cache.dist.php | 111 - application/helpers/dompdf/lib/fonts/log.htm | 1 - .../php-font-lib/classes/Font_Table_kern.php | 72 - .../lib/php-font-lib/classes/font.cls.php | 4 - .../helpers/dompdf/lib/php-font-lib/index.php | 1 - application/helpers/dompdf/load_font.php | 172 - application/helpers/dompdf_helper.php | 5 +- application/hooks/load_config.php | 2 +- application/libraries/Tracking_lib.php | 2 - application/views/partial/header.php | 2 +- composer.json | 4 +- js/manage_tables.js | 1 + public/dist/opensourcepos.min.js | 4 +- public/phpinfo.php | 1 + vendor/composer/autoload_classmap.php | 6 + vendor/composer/autoload_namespaces.php | 3 + vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_static.php | 47 + vendor/composer/installed.json | 190 + vendor/dompdf/dompdf/.gitattributes | 14 + vendor/dompdf/dompdf/.gitignore | 10 + vendor/dompdf/dompdf/.travis.yml | 18 + .../dompdf}/dompdf/CONTRIBUTING.md | 13 +- .../dompdf}/dompdf/LICENSE.LGPL | 0 vendor/dompdf/dompdf/README.md | 207 + vendor/dompdf/dompdf/VERSION | 1 + vendor/dompdf/dompdf/autoload.inc.php | 28 + vendor/dompdf/dompdf/composer.json | 43 + vendor/dompdf/dompdf/lib/Cpdf.php | 5122 +++++++++++ .../dompdf}/dompdf/lib/fonts/Courier-Bold.afm | 0 .../dompdf/lib/fonts/Courier-BoldOblique.afm | 0 .../dompdf/lib/fonts/Courier-Oblique.afm | 0 .../dompdf}/dompdf/lib/fonts/Courier.afm | 0 .../dompdf/lib/fonts/DejaVuSans-Bold.ttf | Bin 634184 -> 693876 bytes .../dompdf/lib/fonts/DejaVuSans-Bold.ufm | 5917 +++++++++++++ .../lib/fonts/DejaVuSans-BoldOblique.ttf | Bin 574636 -> 632168 bytes .../lib/fonts/DejaVuSans-BoldOblique.ufm | 5576 ++++++++++++ .../dompdf/lib/fonts/DejaVuSans-Oblique.ttf | Bin 574456 -> 632416 bytes .../dompdf/lib/fonts/DejaVuSans-Oblique.ufm | 5260 ++++++++++++ .../dompdf}/dompdf/lib/fonts/DejaVuSans.ttf | Bin 683528 -> 741536 bytes vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ufm | 6639 +++++++++++++++ .../dompdf/lib/fonts/DejaVuSansMono-Bold.ttf | Bin 303644 -> 318392 bytes .../dompdf/lib/fonts/DejaVuSansMono-Bold.ufm | 3093 +++++++ .../lib/fonts/DejaVuSansMono-BoldOblique.ttf | Bin 224936 -> 239876 bytes .../lib/fonts/DejaVuSansMono-BoldOblique.ufm | 2515 ++++++ .../lib/fonts/DejaVuSansMono-Oblique.ttf | Bin 231000 -> 245948 bytes .../lib/fonts/DejaVuSansMono-Oblique.ufm | 2643 ++++++ .../dompdf/lib/fonts/DejaVuSansMono.ttf | Bin 323288 -> 335068 bytes .../dompdf/lib/fonts/DejaVuSansMono.ufm | 3220 +++++++ .../dompdf/lib/fonts/DejaVuSerif-Bold.ttf | Bin 315052 -> 345364 bytes .../dompdf/lib/fonts/DejaVuSerif-Bold.ufm | 3876 +++++++++ .../lib/fonts/DejaVuSerif-BoldItalic.ttf | Bin 302940 -> 336884 bytes .../lib/fonts/DejaVuSerif-BoldItalic.ufm | 3755 ++++++++ .../dompdf/lib/fonts/DejaVuSerif-Italic.ttf | Bin 310604 -> 343388 bytes .../dompdf/lib/fonts/DejaVuSerif-Italic.ufm | 3874 +++++++++ .../dompdf}/dompdf/lib/fonts/DejaVuSerif.ttf | Bin 337444 -> 367260 bytes .../dompdf/dompdf/lib/fonts/DejaVuSerif.ufm | 4002 +++++++++ .../dompdf/lib/fonts/Helvetica-Bold.afm | 0 .../lib/fonts/Helvetica-BoldOblique.afm | 0 .../dompdf/lib/fonts/Helvetica-Oblique.afm | 0 .../dompdf}/dompdf/lib/fonts/Helvetica.afm | 0 .../dompdf}/dompdf/lib/fonts/Symbol.afm | 0 .../dompdf}/dompdf/lib/fonts/Times-Bold.afm | 0 .../dompdf/lib/fonts/Times-BoldItalic.afm | 0 .../dompdf}/dompdf/lib/fonts/Times-Italic.afm | 0 .../dompdf}/dompdf/lib/fonts/Times-Roman.afm | 0 .../dompdf}/dompdf/lib/fonts/ZapfDingbats.afm | 0 .../fonts/dompdf_font_family_cache.dist.php | 96 + .../dompdf}/dompdf/lib/fonts/mustRead.html | 0 .../dompdf}/dompdf/lib/html5lib/Data.php | 0 .../dompdf/lib/html5lib/InputStream.php | 0 .../dompdf}/dompdf/lib/html5lib/Parser.php | 0 .../dompdf}/dompdf/lib/html5lib/Tokenizer.php | 0 .../dompdf/lib/html5lib/TreeBuilder.php | 0 .../html5lib/named-character-references.ser | 0 .../dompdf}/dompdf/lib/res/broken_image.png | Bin .../dompdf}/dompdf/lib/res/html.css | 0 vendor/dompdf/dompdf/phpunit.xml.dist | 16 + vendor/dompdf/dompdf/src/Adapter/CPDF.php | 954 +++ vendor/dompdf/dompdf/src/Adapter/GD.php | 1055 +++ vendor/dompdf/dompdf/src/Adapter/PDFLib.php | 1168 +++ vendor/dompdf/dompdf/src/Autoloader.php | 42 + vendor/dompdf/dompdf/src/Canvas.php | 388 + vendor/dompdf/dompdf/src/CanvasFactory.php | 59 + vendor/dompdf/dompdf/src/Cellmap.php | 912 ++ .../dompdf/src/Css/AttributeTranslator.php | 618 ++ vendor/dompdf/dompdf/src/Css/Color.php | 286 + vendor/dompdf/dompdf/src/Css/Style.php | 2582 ++++++ vendor/dompdf/dompdf/src/Css/Stylesheet.php | 1475 ++++ vendor/dompdf/dompdf/src/Dompdf.php | 1480 ++++ vendor/dompdf/dompdf/src/Exception.php | 30 + .../dompdf/src/Exception/ImageException.php | 31 + vendor/dompdf/dompdf/src/FontMetrics.php | 603 ++ vendor/dompdf/dompdf/src/Frame.php | 1109 +++ vendor/dompdf/dompdf/src/Frame/Factory.php | 262 + vendor/dompdf/dompdf/src/Frame/FrameList.php | 34 + .../dompdf/src/Frame/FrameListIterator.php | 91 + vendor/dompdf/dompdf/src/Frame/FrameTree.php | 300 + .../dompdf/src/Frame/FrameTreeIterator.php | 96 + .../dompdf/dompdf/src/Frame/FrameTreeList.php | 35 + .../FrameDecorator/AbstractFrameDecorator.php | 808 ++ .../dompdf/src/FrameDecorator/Block.php | 252 + .../dompdf/src/FrameDecorator/Image.php | 90 + .../dompdf/src/FrameDecorator/Inline.php | 92 + .../dompdf/src/FrameDecorator/ListBullet.php | 75 + .../src/FrameDecorator/ListBulletImage.php | 155 + .../src/FrameDecorator/NullFrameDecorator.php | 31 + .../dompdf/dompdf/src/FrameDecorator/Page.php | 658 ++ .../dompdf/src/FrameDecorator/Table.php | 370 + .../dompdf/src/FrameDecorator/TableCell.php | 117 + .../dompdf/src/FrameDecorator/TableRow.php | 52 + .../src/FrameDecorator/TableRowGroup.php | 72 + .../dompdf/dompdf/src/FrameDecorator/Text.php | 182 + .../FrameReflower/AbstractFrameReflower.php | 460 + .../dompdf/dompdf/src/FrameReflower/Block.php | 793 ++ .../dompdf/dompdf/src/FrameReflower/Image.php | 195 + .../dompdf/src/FrameReflower/Inline.php | 76 + .../dompdf/src/FrameReflower/ListBullet.php | 41 + .../src/FrameReflower/NullFrameReflower.php | 32 + .../dompdf/dompdf/src/FrameReflower/Page.php | 199 + .../dompdf/dompdf/src/FrameReflower/Table.php | 587 ++ .../dompdf/src/FrameReflower/TableCell.php | 120 + .../dompdf/src/FrameReflower/TableRow.php | 68 + .../src/FrameReflower/TableRowGroup.php | 65 + .../dompdf/dompdf/src/FrameReflower/Text.php | 487 ++ vendor/dompdf/dompdf/src/Helpers.php | 733 ++ vendor/dompdf/dompdf/src/Image/Cache.php | 186 + .../dompdf/dompdf/src/JavascriptEmbedder.php | 43 + vendor/dompdf/dompdf/src/LineBox.php | 260 + vendor/dompdf/dompdf/src/Options.php | 974 +++ vendor/dompdf/dompdf/src/PhpEvaluator.php | 55 + .../dompdf/dompdf/src/Positioner/Absolute.php | 123 + .../src/Positioner/AbstractPositioner.php | 52 + vendor/dompdf/dompdf/src/Positioner/Block.php | 63 + vendor/dompdf/dompdf/src/Positioner/Fixed.php | 95 + .../dompdf/dompdf/src/Positioner/Inline.php | 82 + .../dompdf/src/Positioner/ListBullet.php | 81 + .../dompdf/src/Positioner/NullPositioner.php | 31 + .../dompdf/src/Positioner/TableCell.php | 37 + .../dompdf/dompdf/src/Positioner/TableRow.php | 43 + vendor/dompdf/dompdf/src/Renderer.php | 296 + .../dompdf/src/Renderer/AbstractRenderer.php | 768 ++ vendor/dompdf/dompdf/src/Renderer/Block.php | 240 + vendor/dompdf/dompdf/src/Renderer/Image.php | 125 + vendor/dompdf/dompdf/src/Renderer/Inline.php | 198 + .../dompdf/dompdf/src/Renderer/ListBullet.php | 248 + .../dompdf/dompdf/src/Renderer/TableCell.php | 160 + .../dompdf/src/Renderer/TableRowGroup.php | 44 + vendor/dompdf/dompdf/src/Renderer/Text.php | 158 + .../tests/Dompdf/Tests/AutoloaderTest.php | 20 + .../dompdf/tests/Dompdf/Tests/DompdfTest.php | 70 + .../dompdf/tests/Dompdf/Tests/HelpersTest.php | 24 + .../dompdf/tests/Dompdf/Tests/OptionsTest.php | 99 + .../tests/Dompdf/Tests/_files/jamaica.jpg | Bin 0 -> 1377280 bytes vendor/dompdf/dompdf/tests/bootstrap.php | 20 + .../google-measurement-php-client/.gitignore | 3 + .../google-measurement-php-client/.travis.yml | 18 + .../google-measurement-php-client/LICENSE | 21 + .../google-measurement-php-client/README.md | 70 + .../composer.json | 37 + .../composer.lock | 948 +++ .../examples/EventTracking.php | 43 + .../examples/FactoryTracking.php | 36 + .../google-measurement-php-client/phpcs.xml | 5 + .../google-measurement-php-client/phpunit.xml | 17 + .../src/Racecore/GATracking/Autoloader.php | 0 .../Client/AbstractClientAdapter.php | 0 .../GATracking/Client/Adapter/Socket.php | 0 .../Client/ClientAdapterInterface.php | 0 .../src/Racecore/GATracking/Exception.php | 0 .../Exception/EndpointServerException.php | 0 .../Exception/InvalidArgumentException.php | 0 .../Exception/InvalidOptionException.php | 0 .../MissingConfigurationException.php | 0 .../MissingTrackingParameterException.php | 0 .../src/Racecore/GATracking/GATracking.php | 0 .../GATracking/Request/TrackingRequest.php | 0 .../Request/TrackingRequestCollection.php | 0 .../GATracking/Tracking/AbstractTracking.php | 0 .../GATracking/Tracking/App/Event.php | 0 .../GATracking/Tracking/App/Screen.php | 0 .../GATracking/Tracking/Ecommerce/Item.php | 0 .../Tracking/Ecommerce/Transaction.php | 0 .../Racecore/GATracking/Tracking/Event.php | 0 .../GATracking/Tracking/Exception.php | 0 .../Racecore/GATracking/Tracking/Factory.php | 0 .../src/Racecore/GATracking/Tracking/Page.php | 0 .../Racecore/GATracking/Tracking/Social.php | 0 .../GATracking/Tracking/User/Timing.php | 0 .../GATracking/AbstractGATrackingTest.php | 12 + .../Racecore/GATracking/GATrackingTest.php | 242 + .../GATracking/Tracking/App/EventTest.php | 35 + .../GATracking/Tracking/App/ScreenTest.php | 35 + .../Tracking/Ecommerce/ItemTest.php | 45 + .../Tracking/Ecommerce/TransactionTest.php | 43 + .../GATracking/Tracking/EventTest.php | 36 + .../GATracking/Tracking/ExceptionTest.php | 32 + .../Racecore/GATracking/Tracking/PageTest.php | 34 + .../GATracking/Tracking/SocialTest.php | 34 + .../GATracking/Tracking/TrackingTest.php | 26 + .../GATracking/Tracking/User/TimingTest.php | 47 + .../test/bootstrap.php | 4 + vendor/phenx/php-font-lib/.gitattributes | 12 + vendor/phenx/php-font-lib/.gitignore | 5 + .../phenx}/php-font-lib/.htaccess | 0 .../lib => vendor/phenx}/php-font-lib/LICENSE | 0 .../phenx}/php-font-lib/README.md | 0 vendor/phenx/php-font-lib/bower.json | 23 + .../phenx}/php-font-lib/composer.json | 6 +- .../phenx/php-font-lib}/index.php | 0 .../maps/adobe-standard-encoding.map | 0 .../phenx}/php-font-lib/maps/cp1250.map | 0 .../phenx}/php-font-lib/maps/cp1251.map | 0 .../phenx}/php-font-lib/maps/cp1252.map | 0 .../phenx}/php-font-lib/maps/cp1253.map | 0 .../phenx}/php-font-lib/maps/cp1254.map | 0 .../phenx}/php-font-lib/maps/cp1255.map | 0 .../phenx}/php-font-lib/maps/cp1257.map | 0 .../phenx}/php-font-lib/maps/cp1258.map | 0 .../phenx}/php-font-lib/maps/cp874.map | 0 .../phenx}/php-font-lib/maps/iso-8859-1.map | 0 .../phenx}/php-font-lib/maps/iso-8859-11.map | 0 .../phenx}/php-font-lib/maps/iso-8859-15.map | 0 .../phenx}/php-font-lib/maps/iso-8859-16.map | 0 .../phenx}/php-font-lib/maps/iso-8859-2.map | 0 .../phenx}/php-font-lib/maps/iso-8859-4.map | 0 .../phenx}/php-font-lib/maps/iso-8859-5.map | 0 .../phenx}/php-font-lib/maps/iso-8859-7.map | 0 .../phenx}/php-font-lib/maps/iso-8859-9.map | 0 .../phenx}/php-font-lib/maps/koi8-r.map | 0 .../phenx}/php-font-lib/maps/koi8-u.map | 0 .../src/FontLib/AdobeFontMetrics.php | 191 +- .../php-font-lib/src/FontLib/Autoloader.php | 43 + .../php-font-lib/src/FontLib/BinaryStream.php | 251 +- .../php-font-lib/src/FontLib/EOT/File.php | 50 +- .../php-font-lib/src/FontLib/EOT/Header.php | 63 +- .../php-font-lib/src/FontLib/EncodingMap.php | 22 +- .../phenx/php-font-lib/src/FontLib}/Font.php | 68 +- .../src/FontLib/Glyph/Outline.php | 45 +- .../src/FontLib/Glyph/OutlineComponent.php | 7 +- .../src/FontLib/Glyph/OutlineComposite.php | 56 +- .../src/FontLib/Glyph/OutlineSimple.php | 235 +- .../phenx/php-font-lib/src/FontLib/Header.php | 23 +- .../src/FontLib/OpenType/File.php | 9 +- .../FontLib/OpenType/TableDirectoryEntry.php | 8 +- .../src/FontLib/Table/DirectoryEntry.php | 85 +- .../php-font-lib/src/FontLib/Table/Table.php | 66 +- .../src/FontLib/Table/Type/cmap.php | 196 +- .../src/FontLib/Table/Type/glyf.php | 74 +- .../src/FontLib/Table/Type/head.php | 18 +- .../src/FontLib/Table/Type/hhea.php | 23 +- .../src/FontLib/Table/Type/hmtx.php | 47 +- .../src/FontLib/Table/Type/kern.php | 75 + .../src/FontLib/Table/Type/loca.php | 69 +- .../src/FontLib/Table/Type/maxp.php | 15 +- .../src/FontLib/Table/Type/name.php | 127 +- .../src/FontLib/Table/Type/nameRecord.php | 32 +- .../src/FontLib/Table/Type/os2.php | 9 +- .../src/FontLib/Table/Type/post.php | 103 +- .../src/FontLib/TrueType/Collection.php | 54 +- .../src/FontLib/TrueType/File.php | 159 +- .../src/FontLib/TrueType/Header.php | 14 +- .../FontLib/TrueType/TableDirectoryEntry.php | 18 +- .../php-font-lib/src/FontLib/WOFF/File.php | 56 +- .../php-font-lib/src/FontLib/WOFF/Header.php | 8 +- .../src/FontLib/WOFF/TableDirectoryEntry.php | 18 +- vendor/phenx/php-svg-lib/.gitattributes | 9 + vendor/phenx/php-svg-lib/.gitignore | 3 + vendor/phenx/php-svg-lib/.travis.yml | 21 + vendor/phenx/php-svg-lib/README.md | 14 + vendor/phenx/php-svg-lib/composer.json | 18 + vendor/phenx/php-svg-lib/phpunit.xml | 19 + .../php-svg-lib/src/Svg/DefaultStyle.php | 28 + vendor/phenx/php-svg-lib/src/Svg/Document.php | 353 + vendor/phenx/php-svg-lib/src/Svg/Style.php | 485 ++ .../php-svg-lib/src/Svg/Surface/CPdf.php | 4768 +++++++++++ .../src/Svg/Surface/SurfaceCpdf.php | 425 + .../src/Svg/Surface/SurfaceGmagick.php | 303 + .../src/Svg/Surface/SurfaceInterface.php | 88 + .../src/Svg/Surface/SurfacePDFLib.php | 417 + .../php-svg-lib/src/Svg/Tag/AbstractTag.php | 153 + .../phenx/php-svg-lib/src/Svg/Tag/Anchor.php | 14 + .../phenx/php-svg-lib/src/Svg/Tag/Circle.php | 31 + .../phenx/php-svg-lib/src/Svg/Tag/Ellipse.php | 37 + .../phenx/php-svg-lib/src/Svg/Tag/Group.php | 36 + .../phenx/php-svg-lib/src/Svg/Tag/Image.php | 62 + vendor/phenx/php-svg-lib/src/Svg/Tag/Line.php | 38 + .../src/Svg/Tag/LinearGradient.php | 18 + vendor/phenx/php-svg-lib/src/Svg/Tag/Path.php | 529 ++ .../phenx/php-svg-lib/src/Svg/Tag/Polygon.php | 33 + .../php-svg-lib/src/Svg/Tag/Polyline.php | 31 + .../src/Svg/Tag/RadialGradient.php | 17 + vendor/phenx/php-svg-lib/src/Svg/Tag/Rect.php | 45 + .../phenx/php-svg-lib/src/Svg/Tag/Shape.php | 58 + vendor/phenx/php-svg-lib/src/Svg/Tag/Stop.php | 17 + vendor/phenx/php-svg-lib/src/Svg/Tag/Text.php | 56 + vendor/phenx/php-svg-lib/src/autoload.php | 17 + .../phenx/php-svg-lib/tests/Svg/StyleTest.php | 46 + 407 files changed, 92560 insertions(+), 124024 deletions(-) delete mode 100755 application/helpers/dompdf/README.md delete mode 100755 application/helpers/dompdf/composer.json delete mode 100755 application/helpers/dompdf/dompdf.php delete mode 100755 application/helpers/dompdf/dompdf_config.custom.inc.php delete mode 100755 application/helpers/dompdf/dompdf_config.inc.php delete mode 100755 application/helpers/dompdf/include/absolute_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/abstract_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/attribute_translator.cls.php delete mode 100755 application/helpers/dompdf/include/autoload.inc.php delete mode 100755 application/helpers/dompdf/include/block_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/block_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/block_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/block_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/cached_pdf_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/canvas.cls.php delete mode 100755 application/helpers/dompdf/include/canvas_factory.cls.php delete mode 100755 application/helpers/dompdf/include/cellmap.cls.php delete mode 100755 application/helpers/dompdf/include/cpdf_adapter.cls.php delete mode 100755 application/helpers/dompdf/include/css_color.cls.php delete mode 100755 application/helpers/dompdf/include/dompdf.cls.php delete mode 100755 application/helpers/dompdf/include/dompdf_exception.cls.php delete mode 100755 application/helpers/dompdf/include/dompdf_image_exception.cls.php delete mode 100755 application/helpers/dompdf/include/file.skel delete mode 100755 application/helpers/dompdf/include/fixed_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/font_metrics.cls.php delete mode 100755 application/helpers/dompdf/include/frame.cls.php delete mode 100755 application/helpers/dompdf/include/frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/frame_factory.cls.php delete mode 100755 application/helpers/dompdf/include/frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/frame_tree.cls.php delete mode 100755 application/helpers/dompdf/include/functions.inc.php delete mode 100755 application/helpers/dompdf/include/gd_adapter.cls.php delete mode 100755 application/helpers/dompdf/include/image_cache.cls.php delete mode 100755 application/helpers/dompdf/include/image_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/image_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/image_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/inline_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/inline_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/inline_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/inline_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/javascript_embedder.cls.php delete mode 100755 application/helpers/dompdf/include/line_box.cls.php delete mode 100755 application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/list_bullet_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/list_bullet_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/null_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/null_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/null_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/page_cache.cls.php delete mode 100755 application/helpers/dompdf/include/page_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/page_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/pdflib_adapter.cls.php delete mode 100755 application/helpers/dompdf/include/php_evaluator.cls.php delete mode 100755 application/helpers/dompdf/include/positioner.cls.php delete mode 100755 application/helpers/dompdf/include/renderer.cls.php delete mode 100755 application/helpers/dompdf/include/style.cls.php delete mode 100755 application/helpers/dompdf/include/stylesheet.cls.php delete mode 100755 application/helpers/dompdf/include/table_cell_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/table_cell_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/table_cell_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/table_cell_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/table_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/table_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_group_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_group_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_group_renderer.cls.php delete mode 100755 application/helpers/dompdf/include/table_row_positioner.cls.php delete mode 100755 application/helpers/dompdf/include/tcpdf_adapter.cls.php delete mode 100755 application/helpers/dompdf/include/text_frame_decorator.cls.php delete mode 100755 application/helpers/dompdf/include/text_frame_reflower.cls.php delete mode 100755 application/helpers/dompdf/include/text_renderer.cls.php delete mode 100755 application/helpers/dompdf/lib/class.pdf.php delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans-Bold.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans-ExtraLight.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans-ExtraLight.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans-Oblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSans.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-Bold.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-Bold.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-BoldOblique.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-BoldOblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-Oblique.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed-Oblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansCondensed.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSansMono.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerif-Bold.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerif-Italic.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerif.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-Bold.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-Bold.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-BoldItalic.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-BoldItalic.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-Italic.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed-Italic.ufm delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed.ttf delete mode 100755 application/helpers/dompdf/lib/fonts/DejaVuSerifCondensed.ufm delete mode 100644 application/helpers/dompdf/lib/fonts/Helvetica-Bold.afm.php delete mode 100644 application/helpers/dompdf/lib/fonts/Helvetica.afm.php delete mode 100755 application/helpers/dompdf/lib/fonts/dompdf_font_family_cache.dist.php delete mode 100644 application/helpers/dompdf/lib/fonts/log.htm delete mode 100755 application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_kern.php delete mode 100755 application/helpers/dompdf/lib/php-font-lib/classes/font.cls.php delete mode 100755 application/helpers/dompdf/lib/php-font-lib/index.php delete mode 100755 application/helpers/dompdf/load_font.php create mode 100644 public/phpinfo.php create mode 100644 vendor/dompdf/dompdf/.gitattributes create mode 100644 vendor/dompdf/dompdf/.gitignore create mode 100644 vendor/dompdf/dompdf/.travis.yml rename {application/helpers => vendor/dompdf}/dompdf/CONTRIBUTING.md (93%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/LICENSE.LGPL (100%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/README.md create mode 100644 vendor/dompdf/dompdf/VERSION create mode 100644 vendor/dompdf/dompdf/autoload.inc.php create mode 100644 vendor/dompdf/dompdf/composer.json create mode 100644 vendor/dompdf/dompdf/lib/Cpdf.php rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Courier-Bold.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Courier-BoldOblique.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Courier-Oblique.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Courier.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSans-Bold.ttf (65%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Bold.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSans-BoldOblique.ttf (66%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSans-BoldOblique.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSans-Oblique.ttf (66%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSans-Oblique.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSans.ttf (65%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSans.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSansMono-Bold.ttf (72%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ttf (69%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-BoldOblique.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSansMono-Oblique.ttf (67%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono-Oblique.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSansMono.ttf (72%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSansMono.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSerif-Bold.ttf (58%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Bold.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ttf (58%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-BoldItalic.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSerif-Italic.ttf (55%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSerif-Italic.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/DejaVuSerif.ttf (60%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/DejaVuSerif.ufm rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Helvetica-Bold.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Helvetica-BoldOblique.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Helvetica-Oblique.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Helvetica.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Symbol.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Times-Bold.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Times-BoldItalic.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Times-Italic.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/Times-Roman.afm (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/ZapfDingbats.afm (100%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/lib/fonts/dompdf_font_family_cache.dist.php rename {application/helpers => vendor/dompdf}/dompdf/lib/fonts/mustRead.html (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/Data.php (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/InputStream.php (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/Parser.php (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/Tokenizer.php (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/TreeBuilder.php (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/html5lib/named-character-references.ser (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/res/broken_image.png (100%) mode change 100755 => 100644 rename {application/helpers => vendor/dompdf}/dompdf/lib/res/html.css (100%) mode change 100755 => 100644 create mode 100644 vendor/dompdf/dompdf/phpunit.xml.dist create mode 100644 vendor/dompdf/dompdf/src/Adapter/CPDF.php create mode 100644 vendor/dompdf/dompdf/src/Adapter/GD.php create mode 100644 vendor/dompdf/dompdf/src/Adapter/PDFLib.php create mode 100644 vendor/dompdf/dompdf/src/Autoloader.php create mode 100644 vendor/dompdf/dompdf/src/Canvas.php create mode 100644 vendor/dompdf/dompdf/src/CanvasFactory.php create mode 100644 vendor/dompdf/dompdf/src/Cellmap.php create mode 100644 vendor/dompdf/dompdf/src/Css/AttributeTranslator.php create mode 100644 vendor/dompdf/dompdf/src/Css/Color.php create mode 100644 vendor/dompdf/dompdf/src/Css/Style.php create mode 100644 vendor/dompdf/dompdf/src/Css/Stylesheet.php create mode 100644 vendor/dompdf/dompdf/src/Dompdf.php create mode 100644 vendor/dompdf/dompdf/src/Exception.php create mode 100644 vendor/dompdf/dompdf/src/Exception/ImageException.php create mode 100644 vendor/dompdf/dompdf/src/FontMetrics.php create mode 100644 vendor/dompdf/dompdf/src/Frame.php create mode 100644 vendor/dompdf/dompdf/src/Frame/Factory.php create mode 100644 vendor/dompdf/dompdf/src/Frame/FrameList.php create mode 100644 vendor/dompdf/dompdf/src/Frame/FrameListIterator.php create mode 100644 vendor/dompdf/dompdf/src/Frame/FrameTree.php create mode 100644 vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php create mode 100644 vendor/dompdf/dompdf/src/Frame/FrameTreeList.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Block.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Image.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Inline.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Page.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Table.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/TableRowGroup.php create mode 100644 vendor/dompdf/dompdf/src/FrameDecorator/Text.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Block.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Image.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Inline.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Page.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Table.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/TableCell.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/TableRow.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php create mode 100644 vendor/dompdf/dompdf/src/FrameReflower/Text.php create mode 100644 vendor/dompdf/dompdf/src/Helpers.php create mode 100644 vendor/dompdf/dompdf/src/Image/Cache.php create mode 100644 vendor/dompdf/dompdf/src/JavascriptEmbedder.php create mode 100644 vendor/dompdf/dompdf/src/LineBox.php create mode 100644 vendor/dompdf/dompdf/src/Options.php create mode 100644 vendor/dompdf/dompdf/src/PhpEvaluator.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/Absolute.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/Block.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/Fixed.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/Inline.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/ListBullet.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/NullPositioner.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/TableCell.php create mode 100644 vendor/dompdf/dompdf/src/Positioner/TableRow.php create mode 100644 vendor/dompdf/dompdf/src/Renderer.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/Block.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/Image.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/Inline.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/ListBullet.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/TableCell.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php create mode 100644 vendor/dompdf/dompdf/src/Renderer/Text.php create mode 100644 vendor/dompdf/dompdf/tests/Dompdf/Tests/AutoloaderTest.php create mode 100644 vendor/dompdf/dompdf/tests/Dompdf/Tests/DompdfTest.php create mode 100644 vendor/dompdf/dompdf/tests/Dompdf/Tests/HelpersTest.php create mode 100644 vendor/dompdf/dompdf/tests/Dompdf/Tests/OptionsTest.php create mode 100644 vendor/dompdf/dompdf/tests/Dompdf/Tests/_files/jamaica.jpg create mode 100644 vendor/dompdf/dompdf/tests/bootstrap.php create mode 100755 vendor/ins0/google-measurement-php-client/.gitignore create mode 100755 vendor/ins0/google-measurement-php-client/.travis.yml create mode 100644 vendor/ins0/google-measurement-php-client/LICENSE create mode 100755 vendor/ins0/google-measurement-php-client/README.md create mode 100755 vendor/ins0/google-measurement-php-client/composer.json create mode 100644 vendor/ins0/google-measurement-php-client/composer.lock create mode 100644 vendor/ins0/google-measurement-php-client/examples/EventTracking.php create mode 100644 vendor/ins0/google-measurement-php-client/examples/FactoryTracking.php create mode 100644 vendor/ins0/google-measurement-php-client/phpcs.xml create mode 100755 vendor/ins0/google-measurement-php-client/phpunit.xml rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Autoloader.php (100%) mode change 100644 => 100755 rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Client/AbstractClientAdapter.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Client/Adapter/Socket.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Client/ClientAdapterInterface.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception/EndpointServerException.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception/InvalidArgumentException.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception/InvalidOptionException.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception/MissingConfigurationException.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Exception/MissingTrackingParameterException.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/GATracking.php (100%) mode change 100644 => 100755 rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Request/TrackingRequest.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Request/TrackingRequestCollection.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/AbstractTracking.php (100%) mode change 100644 => 100755 rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/App/Event.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/App/Screen.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Ecommerce/Item.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Ecommerce/Transaction.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Event.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Exception.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Factory.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Page.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/Social.php (100%) rename {application/libraries => vendor/ins0/google-measurement-php-client}/src/Racecore/GATracking/Tracking/User/Timing.php (100%) create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/AbstractGATrackingTest.php create mode 100755 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/GATrackingTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/App/EventTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/App/ScreenTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/Ecommerce/ItemTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/Ecommerce/TransactionTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/EventTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/ExceptionTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/PageTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/SocialTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/TrackingTest.php create mode 100644 vendor/ins0/google-measurement-php-client/test/Racecore/GATracking/Tracking/User/TimingTest.php create mode 100755 vendor/ins0/google-measurement-php-client/test/bootstrap.php create mode 100644 vendor/phenx/php-font-lib/.gitattributes create mode 100644 vendor/phenx/php-font-lib/.gitignore rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/.htaccess (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/LICENSE (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/README.md (100%) mode change 100755 => 100644 create mode 100644 vendor/phenx/php-font-lib/bower.json rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/composer.json (81%) mode change 100755 => 100644 rename {application/helpers/dompdf => vendor/phenx/php-font-lib}/index.php (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/adobe-standard-encoding.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1250.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1251.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1252.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1253.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1254.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1255.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1257.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp1258.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/cp874.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-1.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-11.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-15.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-16.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-2.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-4.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-5.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-7.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/iso-8859-9.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/koi8-r.map (100%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib => vendor/phenx}/php-font-lib/maps/koi8-u.map (100%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Adobe_Font_Metrics.php => vendor/phenx/php-font-lib/src/FontLib/AdobeFontMetrics.php (55%) mode change 100755 => 100644 create mode 100644 vendor/phenx/php-font-lib/src/FontLib/Autoloader.php rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Binary_Stream.php => vendor/phenx/php-font-lib/src/FontLib/BinaryStream.php (65%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_EOT.php => vendor/phenx/php-font-lib/src/FontLib/EOT/File.php (79%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_EOT_Header.php => vendor/phenx/php-font-lib/src/FontLib/EOT/Header.php (59%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Encoding_Map.php => vendor/phenx/php-font-lib/src/FontLib/EncodingMap.php (73%) mode change 100755 => 100644 rename {application/helpers/dompdf/lib/php-font-lib/classes => vendor/phenx/php-font-lib/src/FontLib}/Font.php (63%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Glyph_Outline.php => vendor/phenx/php-font-lib/src/FontLib/Glyph/Outline.php (60%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Glyph_Outline_Component.php => vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComponent.php (88%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Glyph_Outline_Composite.php => vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineComposite.php (84%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Glyph_Outline_Simple.php => vendor/phenx/php-font-lib/src/FontLib/Glyph/OutlineSimple.php (68%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Header.php => vendor/phenx/php-font-lib/src/FontLib/Header.php (70%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_OpenType.php => vendor/phenx/php-font-lib/src/FontLib/OpenType/File.php (62%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_OpenType_Table_Directory_Entry.php => vendor/phenx/php-font-lib/src/FontLib/OpenType/TableDirectoryEntry.php (65%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_Directory_Entry.php => vendor/phenx/php-font-lib/src/FontLib/Table/DirectoryEntry.php (77%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table.php => vendor/phenx/php-font-lib/src/FontLib/Table/Table.php (67%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_cmap.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/cmap.php (69%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_glyf.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/glyf.php (62%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_head.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/head.php (78%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_hhea.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/hhea.php (77%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_hmtx.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/hmtx.php (56%) mode change 100755 => 100644 create mode 100644 vendor/phenx/php-font-lib/src/FontLib/Table/Type/kern.php rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_loca.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/loca.php (54%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_maxp.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/maxp.php (87%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_name.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/name.php (75%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_name_Record.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/nameRecord.php (65%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_os2.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/os2.php (91%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_Table_post.php => vendor/phenx/php-font-lib/src/FontLib/Table/Type/post.php (76%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_TrueType_Collection.php => vendor/phenx/php-font-lib/src/FontLib/TrueType/Collection.php (80%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_TrueType.php => vendor/phenx/php-font-lib/src/FontLib/TrueType/File.php (72%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_TrueType_Header.php => vendor/phenx/php-font-lib/src/FontLib/TrueType/Header.php (77%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_TrueType_Table_Directory_Entry.php => vendor/phenx/php-font-lib/src/FontLib/TrueType/TableDirectoryEntry.php (67%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_WOFF.php => vendor/phenx/php-font-lib/src/FontLib/WOFF/File.php (60%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_WOFF_Header.php => vendor/phenx/php-font-lib/src/FontLib/WOFF/Header.php (83%) mode change 100755 => 100644 rename application/helpers/dompdf/lib/php-font-lib/classes/Font_WOFF_Table_Directory_Entry.php => vendor/phenx/php-font-lib/src/FontLib/WOFF/TableDirectoryEntry.php (70%) mode change 100755 => 100644 create mode 100644 vendor/phenx/php-svg-lib/.gitattributes create mode 100644 vendor/phenx/php-svg-lib/.gitignore create mode 100644 vendor/phenx/php-svg-lib/.travis.yml create mode 100644 vendor/phenx/php-svg-lib/README.md create mode 100644 vendor/phenx/php-svg-lib/composer.json create mode 100644 vendor/phenx/php-svg-lib/phpunit.xml create mode 100644 vendor/phenx/php-svg-lib/src/Svg/DefaultStyle.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Document.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Style.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Surface/CPdf.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceCpdf.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceGmagick.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Surface/SurfaceInterface.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Surface/SurfacePDFLib.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/AbstractTag.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Anchor.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Circle.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Ellipse.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Group.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Image.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Line.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/LinearGradient.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Path.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Polygon.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Polyline.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/RadialGradient.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Rect.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Shape.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Stop.php create mode 100644 vendor/phenx/php-svg-lib/src/Svg/Tag/Text.php create mode 100644 vendor/phenx/php-svg-lib/src/autoload.php create mode 100644 vendor/phenx/php-svg-lib/tests/Svg/StyleTest.php diff --git a/Gruntfile.js b/Gruntfile.js index 806b3fcc6..939980328 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -75,7 +75,7 @@ module.exports = function(grunt) { srcPrefix: './' }, files: { - 'public/license': 'COPYING' + 'public/license': 'public/license/COPYING' } }, }, diff --git a/application/helpers/dompdf/README.md b/application/helpers/dompdf/README.md deleted file mode 100755 index 68e4af5d6..000000000 --- a/application/helpers/dompdf/README.md +++ /dev/null @@ -1,131 +0,0 @@ -**dompdf is an HTML to PDF converter**. -At its heart, dompdf is (mostly) [CSS 2.1](http://www.w3.org/TR/CSS2/) compliant -HTML layout and rendering engine written in PHP. It is a style-driven renderer: -it will download and read external stylesheets, inline style tags, and the style -attributes of individual HTML elements. It also supports most presentational -HTML attributes. - ----- - -**Check out the [Demo](http://pxd.me/dompdf/www/examples.php) and ask any -question on [StackOverflow](http://stackoverflow.com/questions/tagged/dompdf) or -on the [Google Groups](http://groups.google.com/group/dompdf)** - ----- - -[![Follow us on Twitter](http://twitter-badges.s3.amazonaws.com/twitter-a.png)](http://www.twitter.com/dompdf) -[![Follow us on Google+](https://ssl.gstatic.com/images/icons/gplus-32.png)](https://plus.google.com/108710008521858993320?prsrc=3) - -Features -======== - * handles most CSS 2.1 and a few CSS3 properties, including @import, @media & - @page rules - * supports most presentational HTML 4.0 attributes - * supports external stylesheets, either local or through http/ftp (via - fopen-wrappers) - * supports complex tables, including row & column spans, separate & collapsed - border models, individual cell styling - * image support (gif, png (8, 24 and 32 bit with alpha channel), bmp & jpeg) - * no dependencies on external PDF libraries, thanks to the R&OS PDF class - * inline PHP support - -Requirements -============ - * PHP 5.0+ (5.3+ recommended) - * DOM extension - * GD extension - -Recommendations -============ - * MBString extension: provides internationalization support. This extension is - *not* enabled by default. dompdf has limited internationalization support - when this extension is not enabled. - * opcache (OPcache, XCache, APC, etc.): improves performance - -About Fonts & Character Encoding -============ -PDF documents internally support the following fonts: Helvetica, Times-Roman, -Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI -encoding. In order for a PDF to display characters that are not available in -Windows ANSI you must supply an external font. dompdf will embed any referenced -font in the PDF so long as it has been pre-loaded or is accessible to dompdf and -reference in CSS @font-face rules. See the -[font overview](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding) -for more information on how to use fonts. - -The [DejaVu TrueType fonts](http://dejavu-fonts.org) have been pre-installed to -give dompdf decent Unicode character coverage by default. To use the DejaVu -fonts reference the font in your stylesheet, e.g. `body { font-family: Deja Vu -Sans; }` (for DejaVu Sans). - -Easy Installation -============ -Install with git ---- -From the command line switch to the directory where dompdf will reside and run -the following commands: - -```sh -git clone https://github.com/dompdf/dompdf.git -git submodule init -git submodule update -``` - -Install with composer ---- -To install with Composer, simply add the requirement to your `composer.json` -file: - -```json -{ - "require" : { - "dompdf/dompdf" : "0.6.*" - } -} -``` - -And run Composer to update your dependencies: - -```bash -$ curl -sS http://getcomposer.org/installer | php -$ php composer.phar update -``` - -Before you can use the Composer installation of DOMPDF in your application you -must disable dompdf's default auto-loader, include the Composer autoloader, and -load the dompdf configuration file: - -```php -// somewhere early in your project's loading, require the Composer autoloader -// see: http://getcomposer.org/doc/00-intro.md -require 'vendor/autoload.php'; - -// disable DOMPDF's internal autoloader if you are using Composer -define('DOMPDF_ENABLE_AUTOLOAD', false); - -// include DOMPDF's default configuration -require_once '/path/to/vendor/dompdf/dompdf/dompdf_config.inc.php'; -``` - -Download and install ---- -Download an archive of dompdf and extract it into the directory where dompdf -will reside - * You can download stable copies of dompdf from - https://github.com/dompdf/dompdf/tags - * Or download a nightly (the latest, unreleased code) from - http://eclecticgeek.com/dompdf - -Limitations (Known Issues) -========================== - * not particularly tolerant to poorly-formed HTML input. To avoid any - unexpected rendering issues you should either enable the built-in HTML5 - parser (via the `DOMPDF_ENABLE_HTML5PARSER` configuration constant) or run - your HTML through a HTML validator/cleaner (such as Tidy). - * large files or large tables can take a while to render - * CSS float is not supported (but is in the works, enable it through the - `DOMPDF_ENABLE_CSS_FLOAT` configuration constant). - * If you find this project useful, please consider making a donation. - -(Any funds donated will be used to help further development on this project.) -[![Donate button](https://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](http://goo.gl/DSvWf) diff --git a/application/helpers/dompdf/composer.json b/application/helpers/dompdf/composer.json deleted file mode 100755 index 565a394d0..000000000 --- a/application/helpers/dompdf/composer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "dompdf/dompdf", - "type": "library", - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "license": "LGPL", - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - }, - { - "name": "Brian Sweeney", - "email": "eclecticgeek@gmail.com" - } - ], - "autoload": { - "classmap": ["include/"] - }, - "require": { - "phenx/php-font-lib": "0.2.*" - } -} diff --git a/application/helpers/dompdf/dompdf.php b/application/helpers/dompdf/dompdf.php deleted file mode 100755 index a9052fa46..000000000 --- a/application/helpers/dompdf/dompdf.php +++ /dev/null @@ -1,289 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Display command line usage - */ -function dompdf_usage() { - $default_paper_size = DOMPDF_DEFAULT_PAPER_SIZE; - - echo <<load_html($str); - -} else - $dompdf->load_html_file($file); - -if ( isset($base_path) ) { - $dompdf->set_base_path($base_path); -} - -$dompdf->set_paper($paper, $orientation); - -$dompdf->render(); - -if ( $_dompdf_show_warnings ) { - global $_dompdf_warnings; - foreach ($_dompdf_warnings as $msg) - echo $msg . "\n"; - echo $dompdf->get_canvas()->get_cpdf()->messages; - flush(); -} - -if ( $save_file ) { -// if ( !is_writable($outfile) ) -// throw new DOMPDF_Exception("'$outfile' is not writable."); - if ( strtolower(DOMPDF_PDF_BACKEND) === "gd" ) - $outfile = str_replace(".pdf", ".png", $outfile); - - list($proto, $host, $path, $file) = explode_url($outfile); - if ( $proto != "" ) // i.e. not file:// - $outfile = $file; // just save it locally, FIXME? could save it like wget: ./host/basepath/file - - $outfile = realpath(dirname($outfile)) . DIRECTORY_SEPARATOR . basename($outfile); - - if ( strpos($outfile, DOMPDF_CHROOT) !== 0 ) - throw new DOMPDF_Exception("Permission denied."); - - file_put_contents($outfile, $dompdf->output( array("compress" => 0) )); - exit(0); -} - -if ( !headers_sent() ) { - $dompdf->stream($outfile, $options); -} diff --git a/application/helpers/dompdf/dompdf_config.custom.inc.php b/application/helpers/dompdf/dompdf_config.custom.inc.php deleted file mode 100755 index 4e58b4a92..000000000 --- a/application/helpers/dompdf/dompdf_config.custom.inc.php +++ /dev/null @@ -1,31 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @autho Brian Sweeney - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -if ( class_exists( 'DOMPDF' , false ) ) { return; } - -PHP_VERSION >= 5.0 or die("DOMPDF requires PHP 5.0+"); - -/** - * The root of your DOMPDF installation - */ -define("DOMPDF_DIR", str_replace(DIRECTORY_SEPARATOR, '/', realpath(dirname(__FILE__)))); - -/** - * The location of the DOMPDF include directory - */ -define("DOMPDF_INC_DIR", DOMPDF_DIR . "/include"); - -/** - * The location of the DOMPDF lib directory - */ -define("DOMPDF_LIB_DIR", DOMPDF_DIR . "/lib"); - -/** - * Some installations don't have $_SERVER['DOCUMENT_ROOT'] - * http://fyneworks.blogspot.com/2007/08/php-documentroot-in-iis-windows-servers.html - */ -if( !isset($_SERVER['DOCUMENT_ROOT']) ) { - $path = ""; - - if ( isset($_SERVER['SCRIPT_FILENAME']) ) - $path = $_SERVER['SCRIPT_FILENAME']; - elseif ( isset($_SERVER['PATH_TRANSLATED']) ) - $path = str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']); - - $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($path, 0, 0-strlen($_SERVER['PHP_SELF']))); -} - -/** Include the custom config file if it exists */ -if ( file_exists(DOMPDF_DIR . "/dompdf_config.custom.inc.php") ){ - require_once(DOMPDF_DIR . "/dompdf_config.custom.inc.php"); -} - -//FIXME: Some function definitions rely on the constants defined by DOMPDF. However, might this location prove problematic? -require_once(DOMPDF_INC_DIR . "/functions.inc.php"); - -/** - * Username and password used by the configuration utility in www/ - */ -def("DOMPDF_ADMIN_USERNAME", "user"); -def("DOMPDF_ADMIN_PASSWORD", "password"); - -/** - * The location of the DOMPDF font directory - * - * The location of the directory where DOMPDF will store fonts and font metrics - * Note: This directory must exist and be writable by the webserver process. - * *Please note the trailing slash.* - * - * Notes regarding fonts: - * Additional .afm font metrics can be added by executing load_font.php from command line. - * - * Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must - * be embedded in the pdf file or the PDF may not display correctly. This can significantly - * increase file size unless font subsetting is enabled. Before embedding a font please - * review your rights under the font license. - * - * Any font specification in the source HTML is translated to the closest font available - * in the font directory. - * - * The pdf standard "Base 14 fonts" are: - * Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique, - * Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique, - * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic, - * Symbol, ZapfDingbats. - */ -def("DOMPDF_FONT_DIR", DOMPDF_DIR . "/lib/fonts/"); - -/** - * The location of the DOMPDF font cache directory - * - * This directory contains the cached font metrics for the fonts used by DOMPDF. - * This directory can be the same as DOMPDF_FONT_DIR - * - * Note: This directory must exist and be writable by the webserver process. - */ -def("DOMPDF_FONT_CACHE", DOMPDF_FONT_DIR); - -/** - * The location of a temporary directory. - * - * The directory specified must be writeable by the webserver process. - * The temporary directory is required to download remote images and when - * using the PFDLib back end. - */ -def("DOMPDF_TEMP_DIR", sys_get_temp_dir()); - -/** - * ==== IMPORTANT ==== - * - * dompdf's "chroot": Prevents dompdf from accessing system files or other - * files on the webserver. All local files opened by dompdf must be in a - * subdirectory of this directory. DO NOT set it to '/' since this could - * allow an attacker to use dompdf to read any files on the server. This - * should be an absolute path. - * This is only checked on command line call by dompdf.php, but not by - * direct class use like: - * $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output(); - */ -def("DOMPDF_CHROOT", realpath(DOMPDF_DIR)); - -/** - * Whether to use Unicode fonts or not. - * - * When set to true the PDF backend must be set to "CPDF" and fonts must be - * loaded via load_font.php. - * - * When enabled, dompdf can support all Unicode glyphs. Any glyphs used in a - * document must be present in your fonts, however. - */ -def("DOMPDF_UNICODE_ENABLED", true); - -/** - * Whether to enable font subsetting or not. - */ -def("DOMPDF_ENABLE_FONTSUBSETTING", true); - -/** - * The PDF rendering backend to use - * - * Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and - * 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will - * fall back on CPDF. 'GD' renders PDFs to graphic files. {@link - * Canvas_Factory} ultimately determines which rendering class to instantiate - * based on this setting. - * - * Both PDFLib & CPDF rendering backends provide sufficient rendering - * capabilities for dompdf, however additional features (e.g. object, - * image and font support, etc.) differ between backends. Please see - * {@link PDFLib_Adapter} for more information on the PDFLib backend - * and {@link CPDF_Adapter} and lib/class.pdf.php for more information - * on CPDF. Also see the documentation for each backend at the links - * below. - * - * The GD rendering backend is a little different than PDFLib and - * CPDF. Several features of CPDF and PDFLib are not supported or do - * not make any sense when creating image files. For example, - * multiple pages are not supported, nor are PDF 'objects'. Have a - * look at {@link GD_Adapter} for more information. GD support is - * experimental, so use it at your own risk. - * - * @link http://www.pdflib.com - * @link http://www.ros.co.nz/pdf - * @link http://www.php.net/image - */ -def("DOMPDF_PDF_BACKEND", "CPDF"); - -/** - * PDFlib license key - * - * If you are using a licensed, commercial version of PDFlib, specify - * your license key here. If you are using PDFlib-Lite or are evaluating - * the commercial version of PDFlib, comment out this setting. - * - * @link http://www.pdflib.com - * - * If pdflib present in web server and auto or selected explicitely above, - * a real license code must exist! - */ -//def("DOMPDF_PDFLIB_LICENSE", "your license key here"); - -/** - * html target media view which should be rendered into pdf. - * List of types and parsing rules for future extensions: - * http://www.w3.org/TR/REC-html40/types.html - * screen, tty, tv, projection, handheld, print, braille, aural, all - * Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3. - * Note, even though the generated pdf file is intended for print output, - * the desired content might be different (e.g. screen or projection view of html file). - * Therefore allow specification of content here. - */ -def("DOMPDF_DEFAULT_MEDIA_TYPE", "screen"); - -/** - * The default paper size. - * - * North America standard is "letter"; other countries generally "a4" - * - * @see CPDF_Adapter::PAPER_SIZES for valid sizes - */ -def("DOMPDF_DEFAULT_PAPER_SIZE", "letter"); - -/** - * The default font family - * - * Used if no suitable fonts can be found. This must exist in the font folder. - * @var string - */ -def("DOMPDF_DEFAULT_FONT", "Helvetica"); - -/** - * Image DPI setting - * - * This setting determines the default DPI setting for images and fonts. The - * DPI may be overridden for inline images by explictly setting the - * image's width & height style attributes (i.e. if the image's native - * width is 600 pixels and you specify the image's width as 72 points, - * the image will have a DPI of 600 in the rendered PDF. The DPI of - * background images can not be overridden and is controlled entirely - * via this parameter. - * - * For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI). - * If a size in html is given as px (or without unit as image size), - * this tells the corresponding size in pt at 72 DPI. - * This adjusts the relative sizes to be similar to the rendering of the - * html page in a reference browser. - * - * In pdf, always 1 pt = 1/72 inch - * - * Rendering resolution of various browsers in px per inch: - * Windows Firefox and Internet Explorer: - * SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:? - * Linux Firefox: - * about:config *resolution: Default:96 - * (xorg screen dimension in mm and Desktop font dpi settings are ignored) - * - * Take care about extra font/image zoom factor of browser. - * - * In images, size in pixel attribute, img css style, are overriding - * the real image dimension in px for rendering. - * - * @var int - */ -def("DOMPDF_DPI", 96); - -/** - * Enable inline PHP - * - * If this setting is set to true then DOMPDF will automatically evaluate - * inline PHP contained within tags. - * - * Enabling this for documents you do not trust (e.g. arbitrary remote html - * pages) is a security risk. Set this option to false if you wish to process - * untrusted documents. - * - * @var bool - */ -def("DOMPDF_ENABLE_PHP", false); - -/** - * Enable inline Javascript - * - * If this setting is set to true then DOMPDF will automatically insert - * JavaScript code contained within tags. - * - * @var bool - */ -def("DOMPDF_ENABLE_JAVASCRIPT", true); - -/** - * Enable remote file access - * - * If this setting is set to true, DOMPDF will access remote sites for - * images and CSS files as required. - * This is required for part of test case www/test/image_variants.html through www/examples.php - * - * Attention! - * This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and - * allowing remote access to dompdf.php or on allowing remote html code to be passed to - * $dompdf = new DOMPDF(); $dompdf->load_html(...); - * This allows anonymous users to download legally doubtful internet content which on - * tracing back appears to being downloaded by your server, or allows malicious php code - * in remote html pages to be executed by your server with your account privileges. - * - * @var bool - */ -def("DOMPDF_ENABLE_REMOTE", false); - -/** - * The debug output log - * @var string - */ -def("DOMPDF_LOG_OUTPUT_FILE", DOMPDF_FONT_DIR."log.htm"); - -/** - * A ratio applied to the fonts height to be more like browsers' line height - */ -def("DOMPDF_FONT_HEIGHT_RATIO", 1.1); - -/** - * Enable CSS float - * - * Allows people to disabled CSS float support - * @var bool - */ -def("DOMPDF_ENABLE_CSS_FLOAT", true); - -/** - * Enable the built in DOMPDF autoloader - * - * @var bool - */ -def("DOMPDF_ENABLE_AUTOLOAD", true); - -/** - * Prepend the DOMPDF autoload function to the spl_autoload stack - * - * @var bool - */ -def("DOMPDF_AUTOLOAD_PREPEND", false); - -/** - * Use the more-than-experimental HTML5 Lib parser - */ -def("DOMPDF_ENABLE_HTML5PARSER", false); -require_once(DOMPDF_LIB_DIR . "/html5lib/Parser.php"); - -// ### End of user-configurable options ### - -/** - * Load autoloader - */ -if (DOMPDF_ENABLE_AUTOLOAD) { - require_once(DOMPDF_INC_DIR . "/autoload.inc.php"); - require_once(DOMPDF_LIB_DIR . "/php-font-lib/classes/Font.php"); -} - -/** - * Ensure that PHP is working with text internally using UTF8 character encoding. - */ -mb_internal_encoding('UTF-8'); - -/** - * Global array of warnings generated by DomDocument parser and - * stylesheet class - * - * @var array - */ -global $_dompdf_warnings; -$_dompdf_warnings = array(); - -/** - * If true, $_dompdf_warnings is dumped on script termination when using - * dompdf/dompdf.php or after rendering when using the DOMPDF class. - * When using the class, setting this value to true will prevent you from - * streaming the PDF. - * - * @var bool - */ -global $_dompdf_show_warnings; -$_dompdf_show_warnings = false; - -/** - * If true, the entire tree is dumped to stdout in dompdf.cls.php. - * Setting this value to true will prevent you from streaming the PDF. - * - * @var bool - */ -global $_dompdf_debug; -$_dompdf_debug = false; - -/** - * Array of enabled debug message types - * - * @var array - */ -global $_DOMPDF_DEBUG_TYPES; -$_DOMPDF_DEBUG_TYPES = array(); //array("page-break" => 1); - -/* Optionally enable different classes of debug output before the pdf content. - * Visible if displaying pdf as text, - * E.g. on repeated display of same pdf in browser when pdf is not taken out of - * the browser cache and the premature output prevents setting of the mime type. - */ -def('DEBUGPNG', false); -def('DEBUGKEEPTEMP', false); -def('DEBUGCSS', false); - -/* Layout debugging. Will display rectangles around different block levels. - * Visible in the PDF itself. - */ -def('DEBUG_LAYOUT', false); -def('DEBUG_LAYOUT_LINES', false); -def('DEBUG_LAYOUT_BLOCKS', false); -def('DEBUG_LAYOUT_INLINE', false); -def('DEBUG_LAYOUT_PADDINGBOX', false); diff --git a/application/helpers/dompdf/include/absolute_positioner.cls.php b/application/helpers/dompdf/include/absolute_positioner.cls.php deleted file mode 100755 index 050db49f7..000000000 --- a/application/helpers/dompdf/include/absolute_positioner.cls.php +++ /dev/null @@ -1,125 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Positions absolutely positioned frames - */ -class Absolute_Positioner extends Positioner { - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - function position() { - - $frame = $this->_frame; - $style = $frame->get_style(); - - $p = $frame->find_positionned_parent(); - - list($x, $y, $w, $h) = $frame->get_containing_block(); - - $top = $style->length_in_pt($style->top, $h); - $right = $style->length_in_pt($style->right, $w); - $bottom = $style->length_in_pt($style->bottom, $h); - $left = $style->length_in_pt($style->left, $w); - - if ( $p && !($left === "auto" && $right === "auto") ) { - // Get the parent's padding box (see http://www.w3.org/TR/CSS21/visuren.html#propdef-top) - list($x, $y, $w, $h) = $p->get_padding_box(); - } - - list($width, $height) = array($frame->get_margin_width(), $frame->get_margin_height()); - - $orig_style = $this->_frame->get_original_style(); - $orig_width = $orig_style->width; - $orig_height = $orig_style->height; - - /**************************** - - Width auto: - ____________| left=auto | left=fixed | - right=auto | A | B | - right=fixed | C | D | - - Width fixed: - ____________| left=auto | left=fixed | - right=auto | E | F | - right=fixed | G | H | - - *****************************/ - - if ( $left === "auto" ) { - if ( $right === "auto" ) { - // A or E - Keep the frame at the same position - $x = $x + $frame->find_block_parent()->get_current_line_box()->w; - } - else { - if ( $orig_width === "auto" ) { - // C - $x += $w - $width - $right; - } - else { - // G - $x += $w - $width - $right; - } - } - } - else { - if ( $right === "auto" ) { - // B or F - $x += $left; - } - else { - if ( $orig_width === "auto" ) { - // D - TODO change width - $x += $left; - } - else { - // H - Everything is fixed: left + width win - $x += $left; - } - } - } - - // The same vertically - if ( $top === "auto" ) { - if ( $bottom === "auto" ) { - // A or E - Keep the frame at the same position - $y = $frame->find_block_parent()->get_current_line_box()->y; - } - else { - if ( $orig_height === "auto" ) { - // C - $y += $h - $height - $bottom; - } - else { - // G - $y += $h - $height - $bottom; - } - } - } - else { - if ( $bottom === "auto" ) { - // B or F - $y += $top; - } - else { - if ( $orig_height === "auto" ) { - // D - TODO change height - $y += $top; - } - else { - // H - Everything is fixed: top + height win - $y += $top; - } - } - } - - $frame->set_position($x, $y); - - } -} \ No newline at end of file diff --git a/application/helpers/dompdf/include/abstract_renderer.cls.php b/application/helpers/dompdf/include/abstract_renderer.cls.php deleted file mode 100755 index fc27aec10..000000000 --- a/application/helpers/dompdf/include/abstract_renderer.cls.php +++ /dev/null @@ -1,759 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Base renderer class - * - * @access private - * @package dompdf - */ -abstract class Abstract_Renderer { - - /** - * Rendering backend - * - * @var Canvas - */ - protected $_canvas; - - /** - * Current dompdf instance - * - * @var DOMPDF - */ - protected $_dompdf; - - /** - * Class constructor - * - * @param DOMPDF $dompdf The current dompdf instance - */ - function __construct(DOMPDF $dompdf) { - $this->_dompdf = $dompdf; - $this->_canvas = $dompdf->get_canvas(); - } - - /** - * Render a frame. - * - * Specialized in child classes - * - * @param Frame $frame The frame to render - */ - abstract function render(Frame $frame); - - //........................................................................ - - /** - * Render a background image over a rectangular area - * - * @param string $url The background image to load - * @param float $x The left edge of the rectangular area - * @param float $y The top edge of the rectangular area - * @param float $width The width of the rectangular area - * @param float $height The height of the rectangular area - * @param Style $style The associated Style object - * - * @throws Exception - */ - protected function _background_image($url, $x, $y, $width, $height, $style) { - if ( !function_exists("imagecreatetruecolor") ) { - throw new Exception("The PHP GD extension is required, but is not installed."); - } - - $sheet = $style->get_stylesheet(); - - // Skip degenerate cases - if ( $width == 0 || $height == 0 ) { - return; - } - - $box_width = $width; - $box_height = $height; - - //debugpng - if (DEBUGPNG) print '[_background_image '.$url.']'; - - list($img, $type, /*$msg*/) = Image_Cache::resolve_url( - $url, - $sheet->get_protocol(), - $sheet->get_host(), - $sheet->get_base_path(), - $this->_dompdf - ); - - // Bail if the image is no good - if ( Image_Cache::is_broken($img) ) { - return; - } - - //Try to optimize away reading and composing of same background multiple times - //Postponing read with imagecreatefrom ...() - //final composition parameters and name not known yet - //Therefore read dimension directly from file, instead of creating gd object first. - //$img_w = imagesx($src); $img_h = imagesy($src); - - list($img_w, $img_h) = dompdf_getimagesize($img); - if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) { - return; - } - - $repeat = $style->background_repeat; - $dpi = $this->_dompdf->get_option("dpi"); - - //Increase background resolution and dependent box size according to image resolution to be placed in - //Then image can be copied in without resize - $bg_width = round((float)($width * $dpi) / 72); - $bg_height = round((float)($height * $dpi) / 72); - - //Need %bg_x, $bg_y as background pos, where img starts, converted to pixel - - list($bg_x, $bg_y) = $style->background_position; - - if ( is_percent($bg_x) ) { - // The point $bg_x % from the left edge of the image is placed - // $bg_x % from the left edge of the background rectangle - $p = ((float)$bg_x)/100.0; - $x1 = $p * $img_w; - $x2 = $p * $bg_width; - - $bg_x = $x2 - $x1; - } - else { - $bg_x = (float)($style->length_in_pt($bg_x)*$dpi) / 72; - } - - $bg_x = round($bg_x + $style->length_in_pt($style->border_left_width)*$dpi / 72); - - if ( is_percent($bg_y) ) { - // The point $bg_y % from the left edge of the image is placed - // $bg_y % from the left edge of the background rectangle - $p = ((float)$bg_y)/100.0; - $y1 = $p * $img_h; - $y2 = $p * $bg_height; - - $bg_y = $y2 - $y1; - } - else { - $bg_y = (float)($style->length_in_pt($bg_y)*$dpi) / 72; - } - - $bg_y = round($bg_y + $style->length_in_pt($style->border_top_width)*$dpi / 72); - - //clip background to the image area on partial repeat. Nothing to do if img off area - //On repeat, normalize start position to the tile at immediate left/top or 0/0 of area - //On no repeat with positive offset: move size/start to have offset==0 - //Handle x/y Dimensions separately - - if ( $repeat !== "repeat" && $repeat !== "repeat-x" ) { - //No repeat x - if ($bg_x < 0) { - $bg_width = $img_w + $bg_x; - } - else { - $x += ($bg_x * 72)/$dpi; - $bg_width = $bg_width - $bg_x; - if ($bg_width > $img_w) { - $bg_width = $img_w; - } - $bg_x = 0; - } - - if ($bg_width <= 0) { - return; - } - - $width = (float)($bg_width * 72)/$dpi; - } - else { - //repeat x - if ($bg_x < 0) { - $bg_x = - ((-$bg_x) % $img_w); - } - else { - $bg_x = $bg_x % $img_w; - if ($bg_x > 0) { - $bg_x -= $img_w; - } - } - } - - if ( $repeat !== "repeat" && $repeat !== "repeat-y" ) { - //no repeat y - if ($bg_y < 0) { - $bg_height = $img_h + $bg_y; - } - else { - $y += ($bg_y * 72)/$dpi; - $bg_height = $bg_height - $bg_y; - if ($bg_height > $img_h) { - $bg_height = $img_h; - } - $bg_y = 0; - } - if ($bg_height <= 0) { - return; - } - $height = (float)($bg_height * 72)/$dpi; - } - else { - //repeat y - if ($bg_y < 0) { - $bg_y = - ((-$bg_y) % $img_h); - } - else { - $bg_y = $bg_y % $img_h; - if ($bg_y > 0) { - $bg_y -= $img_h; - } - } - } - - //Optimization, if repeat has no effect - if ( $repeat === "repeat" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height ) { - $repeat = "repeat-x"; - } - - if ( $repeat === "repeat" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width ) { - $repeat = "repeat-y"; - } - - if ( ($repeat === "repeat-x" && $bg_x <= 0 && $img_w+$bg_x >= $bg_width) || - ($repeat === "repeat-y" && $bg_y <= 0 && $img_h+$bg_y >= $bg_height) ) { - $repeat = "no-repeat"; - } - - //Use filename as indicator only - //different names for different variants to have different copies in the pdf - //This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color) - //Note: Here, bg_* are the start values, not end values after going through the tile loops! - - $filedummy = $img; - - $is_png = false; - $filedummy .= '_'.$bg_width.'_'.$bg_height.'_'.$bg_x.'_'.$bg_y.'_'.$repeat; - - //Optimization to avoid multiple times rendering the same image. - //If check functions are existing and identical image already cached, - //then skip creation of duplicate, because it is not needed by addImagePng - if ( $this->_canvas instanceof CPDF_Adapter && - $this->_canvas->get_cpdf()->image_iscached($filedummy) ) { - $bg = null; - } - - else { - - // Create a new image to fit over the background rectangle - $bg = imagecreatetruecolor($bg_width, $bg_height); - - switch (strtolower($type)) { - case IMAGETYPE_PNG: - $is_png = true; - imagesavealpha($bg, true); - imagealphablending($bg, false); - $src = imagecreatefrompng($img); - break; - - case IMAGETYPE_JPEG: - $src = imagecreatefromjpeg($img); - break; - - case IMAGETYPE_GIF: - $src = imagecreatefromgif($img); - break; - - case IMAGETYPE_BMP: - $src = imagecreatefrombmp($img); - break; - - default: - return; // Unsupported image type - } - - if ( $src == null ) { - return; - } - - //Background color if box is not relevant here - //Non transparent image: box clipped to real size. Background non relevant. - //Transparent image: The image controls the transparency and lets shine through whatever background. - //However on transparent image preset the composed image with the transparency color, - //to keep the transparency when copying over the non transparent parts of the tiles. - $ti = imagecolortransparent($src); - - if ( $ti >= 0 ) { - $tc = imagecolorsforindex($src, $ti); - $ti = imagecolorallocate($bg, $tc['red'], $tc['green'], $tc['blue']); - imagefill($bg, 0, 0, $ti); - imagecolortransparent($bg, $ti); - } - - //This has only an effect for the non repeatable dimension. - //compute start of src and dest coordinates of the single copy - if ( $bg_x < 0 ) { - $dst_x = 0; - $src_x = -$bg_x; - } - else { - $src_x = 0; - $dst_x = $bg_x; - } - - if ( $bg_y < 0 ) { - $dst_y = 0; - $src_y = -$bg_y; - } - else { - $src_y = 0; - $dst_y = $bg_y; - } - - //For historical reasons exchange meanings of variables: - //start_* will be the start values, while bg_* will be the temporary start values in the loops - $start_x = $bg_x; - $start_y = $bg_y; - - // Copy regions from the source image to the background - if ( $repeat === "no-repeat" ) { - - // Simply place the image on the background - imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h); - - } - else if ( $repeat === "repeat-x" ) { - - for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) { - if ( $bg_x < 0 ) { - $dst_x = 0; - $src_x = -$bg_x; - $w = $img_w + $bg_x; - } - else { - $dst_x = $bg_x; - $src_x = 0; - $w = $img_w; - } - imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h); - } - - } - else if ( $repeat === "repeat-y" ) { - - for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) { - if ( $bg_y < 0 ) { - $dst_y = 0; - $src_y = -$bg_y; - $h = $img_h + $bg_y; - } - else { - $dst_y = $bg_y; - $src_y = 0; - $h = $img_h; - } - imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h); - - } - - } - else if ( $repeat === "repeat" ) { - - for ( $bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h ) { - for ( $bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w ) { - - if ( $bg_x < 0 ) { - $dst_x = 0; - $src_x = -$bg_x; - $w = $img_w + $bg_x; - } - else { - $dst_x = $bg_x; - $src_x = 0; - $w = $img_w; - } - - if ( $bg_y < 0 ) { - $dst_y = 0; - $src_y = -$bg_y; - $h = $img_h + $bg_y; - } - else { - $dst_y = $bg_y; - $src_y = 0; - $h = $img_h; - } - imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h); - } - } - } - - else { - print 'Unknown repeat!'; - } - - imagedestroy($src); - - } /* End optimize away creation of duplicates */ - - $this->_canvas->clipping_rectangle($x, $y, $box_width, $box_height); - - //img: image url string - //img_w, img_h: original image size in px - //width, height: box size in pt - //bg_width, bg_height: box size in px - //x, y: left/top edge of box on page in pt - //start_x, start_y: placement of image relative to pattern - //$repeat: repeat mode - //$bg: GD object of result image - //$src: GD object of original image - //When using cpdf and optimization to direct png creation from gd object is available, - //don't create temp file, but place gd object directly into the pdf - if ( !$is_png && $this->_canvas instanceof CPDF_Adapter ) { - // Note: CPDF_Adapter image converts y position - $this->_canvas->get_cpdf()->addImagePng($filedummy, $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg); - } - - else { - $tmp_dir = $this->_dompdf->get_option("temp_dir"); - $tmp_name = tempnam($tmp_dir, "bg_dompdf_img_"); - @unlink($tmp_name); - $tmp_file = "$tmp_name.png"; - - //debugpng - if (DEBUGPNG) print '[_background_image '.$tmp_file.']'; - - imagepng($bg, $tmp_file); - $this->_canvas->image($tmp_file, $x, $y, $width, $height); - imagedestroy($bg); - - //debugpng - if (DEBUGPNG) print '[_background_image unlink '.$tmp_file.']'; - - if (!DEBUGKEEPTEMP) { - unlink($tmp_file); - } - } - - $this->_canvas->clipping_end(); - } - - protected function _get_dash_pattern($style, $width) { - $pattern = array(); - - switch ($style) { - default: - /*case "solid": - case "double": - case "groove": - case "inset": - case "outset": - case "ridge":*/ - case "none": break; - - case "dotted": - if ( $width <= 1 ) - $pattern = array($width, $width*2); - else - $pattern = array($width); - break; - - case "dashed": - $pattern = array(3 * $width); - break; - } - - return $pattern; - } - - protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - return; - } - - protected function _border_hidden($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - return; - } - - // Border rendering functions - - protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dotted", $r1, $r2); - } - - - protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dashed", $r1, $r2); - } - - - protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - // TODO: Solve rendering where one corner is beveled (radius == 0), one corner isn't. - if ( $corner_style !== "bevel" || $r1 > 0 || $r2 > 0 ) { - // do it the simple way - $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "solid", $r1, $r2); - return; - } - - list($top, $right, $bottom, $left) = $widths; - - // All this polygon business is for beveled corners... - switch ($side) { - case "top": - $points = array($x, $y, - $x + $length, $y, - $x + $length - $right, $y + $top, - $x + $left, $y + $top); - $this->_canvas->polygon($points, $color, null, null, true); - break; - - case "bottom": - $points = array($x, $y, - $x + $length, $y, - $x + $length - $right, $y - $bottom, - $x + $left, $y - $bottom); - $this->_canvas->polygon($points, $color, null, null, true); - break; - - case "left": - $points = array($x, $y, - $x, $y + $length, - $x + $left, $y + $length - $bottom, - $x + $left, $y + $top); - $this->_canvas->polygon($points, $color, null, null, true); - break; - - case "right": - $points = array($x, $y, - $x, $y + $length, - $x - $right, $y + $length - $bottom, - $x - $right, $y + $top); - $this->_canvas->polygon($points, $color, null, null, true); - break; - - default: - return; - } - } - - protected function _apply_ratio($side, $ratio, $top, $right, $bottom, $left, &$x, &$y, &$length, &$r1, &$r2) { - switch ($side) { - - case "top": - $r1 -= $left * $ratio; - $r2 -= $right * $ratio; - $x += $left * $ratio; - $y += $top * $ratio; - $length -= $left * $ratio + $right * $ratio; - break; - - case "bottom": - $r1 -= $right * $ratio; - $r2 -= $left * $ratio; - $x += $left * $ratio; - $y -= $bottom * $ratio; - $length -= $left * $ratio + $right * $ratio; - break; - - case "left": - $r1 -= $top * $ratio; - $r2 -= $bottom * $ratio; - $x += $left * $ratio; - $y += $top * $ratio; - $length -= $top * $ratio + $bottom * $ratio; - break; - - case "right": - $r1 -= $bottom * $ratio; - $r2 -= $top * $ratio; - $x -= $right * $ratio; - $y += $top * $ratio; - $length -= $top * $ratio + $bottom * $ratio; - break; - - default: - return; - - } - } - - protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - list($top, $right, $bottom, $left) = $widths; - - $third_widths = array($top / 3, $right / 3, $bottom / 3, $left / 3); - - // draw the outer border - $this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2); - - $this->_apply_ratio($side, 2/3, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); - - $this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2); - } - - protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - list($top, $right, $bottom, $left) = $widths; - - $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2); - - $this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); - - $this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); - - $this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); - - } - - protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - list($top, $right, $bottom, $left) = $widths; - - $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2); - - $this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); - - $this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); - - $this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); - - } - - protected function _tint($c) { - if ( !is_numeric($c) ) - return $c; - - return min(1, $c + 0.16); - } - - protected function _shade($c) { - if ( !is_numeric($c) ) - return $c; - - return max(0, $c - 0.33); - } - - protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - switch ($side) { - case "top": - case "left": - $shade = array_map(array($this, "_shade"), $color); - $this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2); - break; - - case "bottom": - case "right": - $tint = array_map(array($this, "_tint"), $color); - $this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2); - break; - - default: - return; - } - } - - protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) { - switch ($side) { - case "top": - case "left": - $tint = array_map(array($this, "_tint"), $color); - $this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2); - break; - - case "bottom": - case "right": - $shade = array_map(array($this, "_shade"), $color); - $this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2); - break; - - default: - return; - } - } - // Draws a solid, dotted, or dashed line, observing the border radius - protected function _border_line($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $pattern_name, $r1 = 0, $r2 = 0) { - list($top, $right, $bottom, $left) = $widths; - - $width = $$side; - $pattern = $this->_get_dash_pattern($pattern_name, $width); - - $half_width = $width/2; - $r1 -= $half_width; - $r2 -= $half_width; - $adjust = $r1/80; - $length -= $width; - - switch ($side) { - case "top": - $x += $half_width; - $y += $half_width; - - if ( $r1 > 0 ) { - $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 90-$adjust, 135+$adjust, $color, $width, $pattern); - } - - $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern); - - if ( $r2 > 0 ) { - $this->_canvas->arc($x + $length - $r2, $y + $r2, $r2, $r2, 45-$adjust, 90+$adjust, $color, $width, $pattern); - } - break; - - case "bottom": - $x += $half_width; - $y -= $half_width; - - if ( $r1 > 0 ) { - $this->_canvas->arc($x + $r1, $y - $r1, $r1, $r1, 225-$adjust, 270+$adjust, $color, $width, $pattern); - } - - $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern); - - if ( $r2 > 0 ) { - $this->_canvas->arc($x + $length - $r2, $y - $r2, $r2, $r2, 270-$adjust, 315+$adjust, $color, $width, $pattern); - } - break; - - case "left": - $y += $half_width; - $x += $half_width; - - if ( $r1 > 0 ) { - $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 135-$adjust, 180+$adjust, $color, $width, $pattern); - } - - $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern); - - if ( $r2 > 0 ) { - $this->_canvas->arc($x + $r2, $y + $length - $r2, $r2, $r2, 180-$adjust, 225+$adjust, $color, $width, $pattern); - } - break; - - case "right": - $y += $half_width; - $x -= $half_width; - - if ( $r1 > 0 ) { - $this->_canvas->arc($x - $r1, $y + $r1, $r1, $r1, 0-$adjust, 45+$adjust, $color, $width, $pattern); - } - - $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern); - - if ( $r2 > 0 ) { - $this->_canvas->arc($x - $r2, $y + $length - $r2, $r2, $r2, 315-$adjust, 360+$adjust, $color, $width, $pattern); - } - break; - } - } - - protected function _set_opacity($opacity) { - if ( is_numeric($opacity) && $opacity <= 1.0 && $opacity >= 0.0 ) { - $this->_canvas->set_opacity( $opacity ); - } - } - - protected function _debug_layout($box, $color = "red", $style = array()) { - $this->_canvas->rectangle($box[0], $box[1], $box[2], $box[3], CSS_Color::parse($color), 0.1, $style); - } -} diff --git a/application/helpers/dompdf/include/attribute_translator.cls.php b/application/helpers/dompdf/include/attribute_translator.cls.php deleted file mode 100755 index 68da668c1..000000000 --- a/application/helpers/dompdf/include/attribute_translator.cls.php +++ /dev/null @@ -1,592 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Translates HTML 4.0 attributes into CSS rules - * - * @package dompdf - */ -class Attribute_Translator { - static $_style_attr = "_html_style_attribute"; - - // Munged data originally from - // http://www.w3.org/TR/REC-html40/index/attributes.html - // http://www.cs.tut.fi/~jkorpela/html2css.html - static private $__ATTRIBUTE_LOOKUP = array( - //'caption' => array ( 'align' => '', ), - 'img' => array( - 'align' => array( - 'bottom' => 'vertical-align: baseline;', - 'middle' => 'vertical-align: middle;', - 'top' => 'vertical-align: top;', - 'left' => 'float: left;', - 'right' => 'float: right;' - ), - 'border' => 'border: %0.2F px solid;', - 'height' => 'height: %s px;', - 'hspace' => 'padding-left: %1$0.2F px; padding-right: %1$0.2F px;', - 'vspace' => 'padding-top: %1$0.2F px; padding-bottom: %1$0.2F px;', - 'width' => 'width: %s px;', - ), - 'table' => array( - 'align' => array( - 'left' => 'margin-left: 0; margin-right: auto;', - 'center' => 'margin-left: auto; margin-right: auto;', - 'right' => 'margin-left: auto; margin-right: 0;' - ), - 'bgcolor' => 'background-color: %s;', - 'border' => '!set_table_border', - 'cellpadding' => '!set_table_cellpadding',//'border-spacing: %0.2F; border-collapse: separate;', - 'cellspacing' => '!set_table_cellspacing', - 'frame' => array( - 'void' => 'border-style: none;', - 'above' => 'border-top-style: solid;', - 'below' => 'border-bottom-style: solid;', - 'hsides' => 'border-left-style: solid; border-right-style: solid;', - 'vsides' => 'border-top-style: solid; border-bottom-style: solid;', - 'lhs' => 'border-left-style: solid;', - 'rhs' => 'border-right-style: solid;', - 'box' => 'border-style: solid;', - 'border' => 'border-style: solid;' - ), - 'rules' => '!set_table_rules', - 'width' => 'width: %s;', - ), - 'hr' => array( - 'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly - 'noshade' => 'border-style: solid;', - 'size' => '!set_hr_size', //'border-width: %0.2F px;', - 'width' => 'width: %s;', - ), - 'div' => array( - 'align' => 'text-align: %s;', - ), - 'h1' => array( - 'align' => 'text-align: %s;', - ), - 'h2' => array( - 'align' => 'text-align: %s;', - ), - 'h3' => array( - 'align' => 'text-align: %s;', - ), - 'h4' => array( - 'align' => 'text-align: %s;', - ), - 'h5' => array( - 'align' => 'text-align: %s;', - ), - 'h6' => array( - 'align' => 'text-align: %s;', - ), - 'p' => array( - 'align' => 'text-align: %s;', - ), -// 'col' => array( -// 'align' => '', -// 'valign' => '', -// ), -// 'colgroup' => array( -// 'align' => '', -// 'valign' => '', -// ), - 'tbody' => array( - 'align' => '!set_table_row_align', - 'valign' => '!set_table_row_valign', - ), - 'td' => array( - 'align' => 'text-align: %s;', - 'bgcolor' => '!set_background_color', - 'height' => 'height: %s;', - 'nowrap' => 'white-space: nowrap;', - 'valign' => 'vertical-align: %s;', - 'width' => 'width: %s;', - ), - 'tfoot' => array( - 'align' => '!set_table_row_align', - 'valign' => '!set_table_row_valign', - ), - 'th' => array( - 'align' => 'text-align: %s;', - 'bgcolor' => '!set_background_color', - 'height' => 'height: %s;', - 'nowrap' => 'white-space: nowrap;', - 'valign' => 'vertical-align: %s;', - 'width' => 'width: %s;', - ), - 'thead' => array( - 'align' => '!set_table_row_align', - 'valign' => '!set_table_row_valign', - ), - 'tr' => array( - 'align' => '!set_table_row_align', - 'bgcolor' => '!set_table_row_bgcolor', - 'valign' => '!set_table_row_valign', - ), - 'body' => array( - 'background' => 'background-image: url(%s);', - 'bgcolor' => '!set_background_color', - 'link' => '!set_body_link', - 'text' => '!set_color', - ), - 'br' => array( - 'clear' => 'clear: %s;', - ), - 'basefont' => array( - 'color' => '!set_color', - 'face' => 'font-family: %s;', - 'size' => '!set_basefont_size', - ), - 'font' => array( - 'color' => '!set_color', - 'face' => 'font-family: %s;', - 'size' => '!set_font_size', - ), - 'dir' => array( - 'compact' => 'margin: 0.5em 0;', - ), - 'dl' => array( - 'compact' => 'margin: 0.5em 0;', - ), - 'menu' => array( - 'compact' => 'margin: 0.5em 0;', - ), - 'ol' => array( - 'compact' => 'margin: 0.5em 0;', - 'start' => 'counter-reset: -dompdf-default-counter %d;', - 'type' => 'list-style-type: %s;', - ), - 'ul' => array( - 'compact' => 'margin: 0.5em 0;', - 'type' => 'list-style-type: %s;', - ), - 'li' => array( - 'type' => 'list-style-type: %s;', - 'value' => 'counter-reset: -dompdf-default-counter %d;', - ), - 'pre' => array( - 'width' => 'width: %s;', - ), - ); - - static protected $_last_basefont_size = 3; - static protected $_font_size_lookup = array( - // For basefont support - -3 => "4pt", - -2 => "5pt", - -1 => "6pt", - 0 => "7pt", - - 1 => "8pt", - 2 => "10pt", - 3 => "12pt", - 4 => "14pt", - 5 => "18pt", - 6 => "24pt", - 7 => "34pt", - - // For basefont support - 8 => "48pt", - 9 => "44pt", - 10 => "52pt", - 11 => "60pt", - ); - - /** - * @param Frame $frame - */ - static function translate_attributes(Frame $frame) { - $node = $frame->get_node(); - $tag = $node->nodeName; - - if ( !isset(self::$__ATTRIBUTE_LOOKUP[$tag]) ) { - return; - } - - $valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag]; - $attrs = $node->attributes; - $style = rtrim($node->getAttribute(self::$_style_attr), "; "); - if ( $style != "" ) { - $style .= ";"; - } - - foreach ($attrs as $attr => $attr_node ) { - if ( !isset($valid_attrs[$attr]) ) { - continue; - } - - $value = $attr_node->value; - - $target = $valid_attrs[$attr]; - - // Look up $value in $target, if $target is an array: - if ( is_array($target) ) { - if ( isset($target[$value]) ) { - $style .= " " . self::_resolve_target($node, $target[$value], $value); - } - } - else { - // otherwise use target directly - $style .= " " . self::_resolve_target($node, $target, $value); - } - } - - if ( !is_null($style) ) { - $style = ltrim($style); - $node->setAttribute(self::$_style_attr, $style); - } - - } - - /** - * @param DOMNode $node - * @param string $target - * @param string $value - * - * @return string - */ - static protected function _resolve_target(DOMNode $node, $target, $value) { - if ( $target[0] === "!" ) { - // Function call - $func = "_" . mb_substr($target, 1); - return self::$func($node, $value); - } - - return $value ? sprintf($target, $value) : ""; - } - - /** - * @param DOMElement $node - * @param string $new_style - */ - static function append_style(DOMElement $node, $new_style) { - $style = rtrim($node->getAttribute(self::$_style_attr), ";"); - $style .= $new_style; - $style = ltrim($style, ";"); - $node->setAttribute(self::$_style_attr, $style); - } - - /** - * @param DOMNode $node - * - * @return DOMNodeList|DOMElement[] - */ - static protected function get_cell_list(DOMNode $node) { - $xpath = new DOMXpath($node->ownerDocument); - - switch($node->nodeName) { - default: - case "table": - $query = "tr/td | thead/tr/td | tbody/tr/td | tfoot/tr/td | tr/th | thead/tr/th | tbody/tr/th | tfoot/tr/th"; - break; - - case "tbody": - case "tfoot": - case "thead": - $query = "tr/td | tr/th"; - break; - - case "tr": - $query = "td | th"; - break; - } - - return $xpath->query($query, $node); - } - - /** - * @param string $value - * - * @return string - */ - static protected function _get_valid_color($value) { - if ( preg_match('/^#?([0-9A-F]{6})$/i', $value, $matches) ) { - $value = "#$matches[1]"; - } - - return $value; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_color(DOMElement $node, $value) { - $value = self::_get_valid_color($value); - return "color: $value;"; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_background_color(DOMElement $node, $value) { - $value = self::_get_valid_color($value); - return "background-color: $value;"; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_table_cellpadding(DOMElement $node, $value) { - $cell_list = self::get_cell_list($node); - - foreach ($cell_list as $cell) { - self::append_style($cell, "; padding: {$value}px;"); - } - - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_table_border(DOMElement $node, $value) { - $cell_list = self::get_cell_list($node); - - foreach ($cell_list as $cell) { - $style = rtrim($cell->getAttribute(self::$_style_attr)); - $style .= "; border-width: " . ($value > 0 ? 1 : 0) . "pt; border-style: inset;"; - $style = ltrim($style, ";"); - $cell->setAttribute(self::$_style_attr, $style); - } - - $style = rtrim($node->getAttribute(self::$_style_attr), ";"); - $style .= "; border-width: $value" . "px; "; - return ltrim($style, "; "); - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_table_cellspacing(DOMElement $node, $value) { - $style = rtrim($node->getAttribute(self::$_style_attr), ";"); - - if ( $value == 0 ) { - $style .= "; border-collapse: collapse;"; - } - else { - $style .= "; border-spacing: {$value}px; border-collapse: separate;"; - } - - return ltrim($style, ";"); - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null|string - */ - static protected function _set_table_rules(DOMElement $node, $value) { - $new_style = "; border-collapse: collapse;"; - - switch ($value) { - case "none": - $new_style .= "border-style: none;"; - break; - - case "groups": - // FIXME: unsupported - return null; - - case "rows": - $new_style .= "border-style: solid none solid none; border-width: 1px; "; - break; - - case "cols": - $new_style .= "border-style: none solid none solid; border-width: 1px; "; - break; - - case "all": - $new_style .= "border-style: solid; border-width: 1px; "; - break; - - default: - // Invalid value - return null; - } - - $cell_list = self::get_cell_list($node); - - foreach ($cell_list as $cell) { - $style = $cell->getAttribute(self::$_style_attr); - $style .= $new_style; - $cell->setAttribute(self::$_style_attr, $style); - } - - $style = rtrim($node->getAttribute(self::$_style_attr), ";"); - $style .= "; border-collapse: collapse; "; - - return ltrim($style, "; "); - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_hr_size(DOMElement $node, $value) { - $style = rtrim($node->getAttribute(self::$_style_attr), ";"); - $style .= "; border-width: ".max(0, $value-2)."; "; - return ltrim($style, "; "); - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null|string - */ - static protected function _set_hr_align(DOMElement $node, $value) { - $style = rtrim($node->getAttribute(self::$_style_attr),";"); - $width = $node->getAttribute("width"); - - if ( $width == "" ) { - $width = "100%"; - } - - $remainder = 100 - (double)rtrim($width, "% "); - - switch ($value) { - case "left": - $style .= "; margin-right: $remainder %;"; - break; - - case "right": - $style .= "; margin-left: $remainder %;"; - break; - - case "center": - $style .= "; margin-left: auto; margin-right: auto;"; - break; - - default: - return null; - } - - return ltrim($style, "; "); - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_table_row_align(DOMElement $node, $value) { - $cell_list = self::get_cell_list($node); - - foreach ($cell_list as $cell) { - self::append_style($cell, "; text-align: $value;"); - } - - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_table_row_valign(DOMElement $node, $value) { - $cell_list = self::get_cell_list($node); - - foreach ($cell_list as $cell) { - self::append_style($cell, "; vertical-align: $value;"); - } - - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_table_row_bgcolor(DOMElement $node, $value) { - $cell_list = self::get_cell_list($node); - $value = self::_get_valid_color($value); - - foreach ($cell_list as $cell) { - self::append_style($cell, "; background-color: $value;"); - } - - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_body_link(DOMElement $node, $value) { - $a_list = $node->getElementsByTagName("a"); - $value = self::_get_valid_color($value); - - foreach ($a_list as $a) { - self::append_style($a, "; color: $value;"); - } - - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return null - */ - static protected function _set_basefont_size(DOMElement $node, $value) { - // FIXME: ? we don't actually set the font size of anything here, just - // the base size for later modification by tags. - self::$_last_basefont_size = $value; - return null; - } - - /** - * @param DOMElement $node - * @param string $value - * - * @return string - */ - static protected function _set_font_size(DOMElement $node, $value) { - $style = $node->getAttribute(self::$_style_attr); - - if ( $value[0] === "-" || $value[0] === "+" ) { - $value = self::$_last_basefont_size + (int)$value; - } - - if ( isset(self::$_font_size_lookup[$value]) ) { - $style .= "; font-size: " . self::$_font_size_lookup[$value] . ";"; - } - else { - $style .= "; font-size: $value;"; - } - - return ltrim($style, "; "); - } -} diff --git a/application/helpers/dompdf/include/autoload.inc.php b/application/helpers/dompdf/include/autoload.inc.php deleted file mode 100755 index 509d3e3bc..000000000 --- a/application/helpers/dompdf/include/autoload.inc.php +++ /dev/null @@ -1,86 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * DOMPDF autoload function - * - * If you have an existing autoload function, add a call to this function - * from your existing __autoload() implementation. - * - * @param string $class - */ -function DOMPDF_autoload($class) { - $filename = DOMPDF_INC_DIR . "/" . mb_strtolower($class) . ".cls.php"; - - if ( is_file($filename) ) { - include_once $filename; - } -} - -// If SPL autoload functions are available (PHP >= 5.1.2) -if ( function_exists("spl_autoload_register") ) { - $autoload = "DOMPDF_autoload"; - $funcs = spl_autoload_functions(); - - // No functions currently in the stack. - if ( !DOMPDF_AUTOLOAD_PREPEND || $funcs === false ) { - spl_autoload_register($autoload); - } - - // If PHP >= 5.3 the $prepend argument is available - else if ( PHP_VERSION_ID >= 50300 ) { - spl_autoload_register($autoload, true, true); - } - - else { - // Unregister existing autoloaders... - $compat = (PHP_VERSION_ID <= 50102 && PHP_VERSION_ID >= 50100); - - foreach ($funcs as $func) { - if (is_array($func)) { - // :TRICKY: There are some compatibility issues and some - // places where we need to error out - $reflector = new ReflectionMethod($func[0], $func[1]); - if (!$reflector->isStatic()) { - throw new Exception('This function is not compatible with non-static object methods due to PHP Bug #44144.'); - } - - // Suprisingly, spl_autoload_register supports the - // Class::staticMethod callback format, although call_user_func doesn't - if ($compat) $func = implode('::', $func); - } - - spl_autoload_unregister($func); - } - - // Register the new one, thus putting it at the front of the stack... - spl_autoload_register($autoload); - - // Now, go back and re-register all of our old ones. - foreach ($funcs as $func) { - spl_autoload_register($func); - } - - // Be polite and ensure that userland autoload gets retained - if ( function_exists("__autoload") ) { - spl_autoload_register("__autoload"); - } - } -} - -else if ( !function_exists("__autoload") ) { - /** - * Default __autoload() function - * - * @param string $class - */ - function __autoload($class) { - DOMPDF_autoload($class); - } -} diff --git a/application/helpers/dompdf/include/block_frame_decorator.cls.php b/application/helpers/dompdf/include/block_frame_decorator.cls.php deleted file mode 100755 index 407635c0e..000000000 --- a/application/helpers/dompdf/include/block_frame_decorator.cls.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for block layout - * - * @access private - * @package dompdf - */ -class Block_Frame_Decorator extends Frame_Decorator { - /** - * Current line index - * - * @var int - */ - protected $_cl; - - /** - * The block's line boxes - * - * @var Line_Box[] - */ - protected $_line_boxes; - - function __construct(Frame $frame, DOMPDF $dompdf) { - parent::__construct($frame, $dompdf); - - $this->_line_boxes = array(new Line_Box($this)); - $this->_cl = 0; - } - - function reset() { - parent::reset(); - - $this->_line_boxes = array(new Line_Box($this)); - $this->_cl = 0; - } - - /** - * @return Line_Box - */ - function get_current_line_box() { - return $this->_line_boxes[$this->_cl]; - } - - /** - * @return integer - */ - function get_current_line_number() { - return $this->_cl; - } - - /** - * @return Line_Box[] - */ - function get_line_boxes() { - return $this->_line_boxes; - } - - /** - * @param integer $i - */ - function clear_line($i) { - if ( isset($this->_line_boxes[$i]) ) { - unset($this->_line_boxes[$i]); - } - } - - /** - * @param Frame $frame - */ - function add_frame_to_line(Frame $frame) { - if ( !$frame->is_in_flow() ) { - return; - } - - $style = $frame->get_style(); - - $frame->set_containing_line($this->_line_boxes[$this->_cl]); - - /* - // Adds a new line after a block, only if certain conditions are met - if ((($frame instanceof Inline_Frame_Decorator && $frame->get_node()->nodeName !== "br") || - $frame instanceof Text_Frame_Decorator && trim($frame->get_text())) && - ($frame->get_prev_sibling() && $frame->get_prev_sibling()->get_style()->display === "block" && - $this->_line_boxes[$this->_cl]->w > 0 )) { - - $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame ); - $this->add_line(); - - // Add each child of the inline frame to the line individually - foreach ($frame->get_children() as $child) - $this->add_frame_to_line( $child ); - } - else*/ - - // Handle inline frames (which are effectively wrappers) - if ( $frame instanceof Inline_Frame_Decorator ) { - - // Handle line breaks - if ( $frame->get_node()->nodeName === "br" ) { - $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame ); - $this->add_line(true); - } - - return; - } - - // Trim leading text if this is an empty line. Kinda a hack to put it here, - // but what can you do... - if ( $this->get_current_line_box()->w == 0 && - $frame->is_text_node() && - !$frame->is_pre() ) { - - $frame->set_text( ltrim($frame->get_text()) ); - $frame->recalculate_width(); - } - - $w = $frame->get_margin_width(); - - if ( $w == 0 ) { - return; - } - - // Debugging code: - /* - pre_r("\n

Adding frame to line:

"); - - // pre_r("Me: " . $this->get_node()->nodeName . " (" . spl_object_hash($this->get_node()) . ")"); - // pre_r("Node: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")"); - if ( $frame->is_text_node() ) - pre_r('"'.$frame->get_node()->nodeValue.'"'); - - pre_r("Line width: " . $this->_line_boxes[$this->_cl]->w); - pre_r("Frame: " . get_class($frame)); - pre_r("Frame width: " . $w); - pre_r("Frame height: " . $frame->get_margin_height()); - pre_r("Containing block width: " . $this->get_containing_block("w")); - */ - // End debugging - - $line = $this->_line_boxes[$this->_cl]; - if ( $line->left + $line->w + $line->right + $w > $this->get_containing_block("w")) { - $this->add_line(); - } - - $frame->position(); - - $current_line = $this->_line_boxes[$this->_cl]; - $current_line->add_frame($frame); - - if ( $frame->is_text_node() ) { - $current_line->wc += count(preg_split("/\s+/", trim($frame->get_text()))); - } - - $this->increase_line_width($w); - - $this->maximize_line_height($frame->get_margin_height(), $frame); - } - - function remove_frames_from_line(Frame $frame) { - // Search backwards through the lines for $frame - $i = $this->_cl; - $j = null; - - while ($i >= 0) { - if ( ($j = in_array($frame, $this->_line_boxes[$i]->get_frames(), true)) !== false ) { - break; - } - - $i--; - } - - if ( $j === false ) { - return; - } - - // Remove $frame and all frames that follow - while ($j < count($this->_line_boxes[$i]->get_frames())) { - $frames = $this->_line_boxes[$i]->get_frames(); - $f = $frames[$j]; - $frames[$j] = null; - unset($frames[$j]); - $j++; - $this->_line_boxes[$i]->w -= $f->get_margin_width(); - } - - // Recalculate the height of the line - $h = 0; - foreach ($this->_line_boxes[$i]->get_frames() as $f) { - $h = max( $h, $f->get_margin_height() ); - } - - $this->_line_boxes[$i]->h = $h; - - // Remove all lines that follow - while ($this->_cl > $i) { - $this->_line_boxes[ $this->_cl ] = null; - unset($this->_line_boxes[ $this->_cl ]); - $this->_cl--; - } - } - - function increase_line_width($w) { - $this->_line_boxes[ $this->_cl ]->w += $w; - } - - function maximize_line_height($val, Frame $frame) { - if ( $val > $this->_line_boxes[ $this->_cl ]->h ) { - $this->_line_boxes[ $this->_cl ]->tallest_frame = $frame; - $this->_line_boxes[ $this->_cl ]->h = $val; - } - } - - function add_line($br = false) { - -// if ( $this->_line_boxes[$this->_cl]["h"] == 0 ) //count($this->_line_boxes[$i]["frames"]) == 0 || -// return; - - $this->_line_boxes[$this->_cl]->br = $br; - $y = $this->_line_boxes[$this->_cl]->y + $this->_line_boxes[$this->_cl]->h; - - $new_line = new Line_Box($this, $y); - - $this->_line_boxes[ ++$this->_cl ] = $new_line; - } - - //........................................................................ -} diff --git a/application/helpers/dompdf/include/block_frame_reflower.cls.php b/application/helpers/dompdf/include/block_frame_reflower.cls.php deleted file mode 100755 index bbbdba96d..000000000 --- a/application/helpers/dompdf/include/block_frame_reflower.cls.php +++ /dev/null @@ -1,805 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Reflows block frames - * - * @access private - * @package dompdf - */ -class Block_Frame_Reflower extends Frame_Reflower { - // Minimum line width to justify, as fraction of available width - const MIN_JUSTIFY_WIDTH = 0.80; - - /** - * @var Block_Frame_Decorator - */ - protected $_frame; - - function __construct(Block_Frame_Decorator $frame) { parent::__construct($frame); } - - /** - * Calculate the ideal used value for the width property as per: - * http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins - * - * @param float $width - * @return array - */ - protected function _calculate_width($width) { - $frame = $this->_frame; - $style = $frame->get_style(); - $w = $frame->get_containing_block("w"); - - if ( $style->position === "fixed" ) { - $w = $frame->get_parent()->get_containing_block("w"); - } - - $rm = $style->length_in_pt($style->margin_right, $w); - $lm = $style->length_in_pt($style->margin_left, $w); - - $left = $style->length_in_pt($style->left, $w); - $right = $style->length_in_pt($style->right, $w); - - // Handle 'auto' values - $dims = array($style->border_left_width, - $style->border_right_width, - $style->padding_left, - $style->padding_right, - $width !== "auto" ? $width : 0, - $rm !== "auto" ? $rm : 0, - $lm !== "auto" ? $lm : 0); - - // absolutely positioned boxes take the 'left' and 'right' properties into account - if ( $frame->is_absolute() ) { - $absolute = true; - $dims[] = $left !== "auto" ? $left : 0; - $dims[] = $right !== "auto" ? $right : 0; - } - else { - $absolute = false; - } - - $sum = $style->length_in_pt($dims, $w); - - // Compare to the containing block - $diff = $w - $sum; - - if ( $diff > 0 ) { - - if ( $absolute ) { - - // resolve auto properties: see - // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width - - if ( $width === "auto" && $left === "auto" && $right === "auto" ) { - - if ( $lm === "auto" ) $lm = 0; - if ( $rm === "auto" ) $rm = 0; - - // Technically, the width should be "shrink-to-fit" i.e. based on the - // preferred width of the content... a little too costly here as a - // special case. Just get the width to take up the slack: - $left = 0; - $right = 0; - $width = $diff; - } - else if ( $width === "auto" ) { - - if ( $lm === "auto" ) $lm = 0; - if ( $rm === "auto" ) $rm = 0; - if ( $left === "auto" ) $left = 0; - if ( $right === "auto" ) $right = 0; - - $width = $diff; - } - else if ( $left === "auto" ) { - - if ( $lm === "auto" ) $lm = 0; - if ( $rm === "auto" ) $rm = 0; - if ( $right === "auto" ) $right = 0; - - $left = $diff; - } - else if ( $right === "auto" ) { - - if ( $lm === "auto" ) $lm = 0; - if ( $rm === "auto" ) $rm = 0; - - $right = $diff; - } - - } - else { - - // Find auto properties and get them to take up the slack - if ( $width === "auto" ) { - $width = $diff; - } - else if ( $lm === "auto" && $rm === "auto" ) { - $lm = $rm = round($diff / 2); - } - else if ( $lm === "auto" ) { - $lm = $diff; - } - else if ( $rm === "auto" ) { - $rm = $diff; - } - } - - } - else if ($diff < 0) { - - // We are over constrained--set margin-right to the difference - $rm = $diff; - - } - - return array( - "width" => $width, - "margin_left" => $lm, - "margin_right" => $rm, - "left" => $left, - "right" => $right, - ); - } - - /** - * Call the above function, but resolve max/min widths - * - * @throws DOMPDF_Exception - * @return array - */ - protected function _calculate_restricted_width() { - $frame = $this->_frame; - $style = $frame->get_style(); - $cb = $frame->get_containing_block(); - - if ( $style->position === "fixed" ) { - $cb = $frame->get_root()->get_containing_block(); - } - - //if ( $style->position === "absolute" ) - // $cb = $frame->find_positionned_parent()->get_containing_block(); - - if ( !isset($cb["w"]) ) { - throw new DOMPDF_Exception("Box property calculation requires containing block width"); - } - - // Treat width 100% as auto - if ( $style->width === "100%" ) { - $width = "auto"; - } - else { - $width = $style->length_in_pt($style->width, $cb["w"]); - } - - extract($this->_calculate_width($width)); - - // Handle min/max width - $min_width = $style->length_in_pt($style->min_width, $cb["w"]); - $max_width = $style->length_in_pt($style->max_width, $cb["w"]); - - if ( $max_width !== "none" && $min_width > $max_width ) { - list($max_width, $min_width) = array($min_width, $max_width); - } - - if ( $max_width !== "none" && $width > $max_width ) { - extract($this->_calculate_width($max_width)); - } - - if ( $width < $min_width ) { - extract($this->_calculate_width($min_width)); - } - - return array($width, $margin_left, $margin_right, $left, $right); - } - - /** - * Determine the unrestricted height of content within the block - * not by adding each line's height, but by getting the last line's position. - * This because lines could have been pushed lower by a clearing element. - * - * @return float - */ - protected function _calculate_content_height() { - $lines = $this->_frame->get_line_boxes(); - $height = 0; - - foreach ($lines as $line) { - $height += $line->h; - } - - /* - $first_line = reset($lines); - $last_line = end($lines); - $height2 = $last_line->y + $last_line->h - $first_line->y; - */ - - return $height; - } - - /** - * Determine the frame's restricted height - * - * @return array - */ - protected function _calculate_restricted_height() { - $frame = $this->_frame; - $style = $frame->get_style(); - $content_height = $this->_calculate_content_height(); - $cb = $frame->get_containing_block(); - - $height = $style->length_in_pt($style->height, $cb["h"]); - - $top = $style->length_in_pt($style->top, $cb["h"]); - $bottom = $style->length_in_pt($style->bottom, $cb["h"]); - - $margin_top = $style->length_in_pt($style->margin_top, $cb["h"]); - $margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); - - if ( $frame->is_absolute() ) { - - // see http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height - - $dims = array($top !== "auto" ? $top : 0, - $style->margin_top !== "auto" ? $style->margin_top : 0, - $style->padding_top, - $style->border_top_width, - $height !== "auto" ? $height : 0, - $style->border_bottom_width, - $style->padding_bottom, - $style->margin_bottom !== "auto" ? $style->margin_bottom : 0, - $bottom !== "auto" ? $bottom : 0); - - $sum = $style->length_in_pt($dims, $cb["h"]); - - $diff = $cb["h"] - $sum; - - if ( $diff > 0 ) { - - if ( $height === "auto" && $top === "auto" && $bottom === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $height = $diff; - } - else if ( $height === "auto" && $top === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $height = $content_height; - $top = $diff - $content_height; - } - else if ( $height === "auto" && $bottom === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $height = $content_height; - $bottom = $diff - $content_height; - } - else if ( $top === "auto" && $bottom === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $bottom = $diff; - } - else if ( $top === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $top = $diff; - } - else if ( $height === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $height = $diff; - } - else if ( $bottom === "auto" ) { - - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - - $bottom = $diff; - } - else { - - if ( $style->overflow === "visible" ) { - // set all autos to zero - if ( $margin_top === "auto" ) $margin_top = 0; - if ( $margin_bottom === "auto" ) $margin_bottom = 0; - if ( $top === "auto" ) $top = 0; - if ( $bottom === "auto" ) $bottom = 0; - if ( $height === "auto" ) $height = $content_height; - } - - // FIXME: overflow hidden - } - - } - - } - else { - - // Expand the height if overflow is visible - if ( $height === "auto" && $content_height > $height /* && $style->overflow === "visible" */) { - $height = $content_height; - } - - // FIXME: this should probably be moved to a seperate function as per - // _calculate_restricted_width - - // Only handle min/max height if the height is independent of the frame's content - if ( !($style->overflow === "visible" || - ($style->overflow === "hidden" && $height === "auto")) ) { - - $min_height = $style->min_height; - $max_height = $style->max_height; - - if ( isset($cb["h"]) ) { - $min_height = $style->length_in_pt($min_height, $cb["h"]); - $max_height = $style->length_in_pt($max_height, $cb["h"]); - - } - else if ( isset($cb["w"]) ) { - - if ( mb_strpos($min_height, "%") !== false ) { - $min_height = 0; - } - else { - $min_height = $style->length_in_pt($min_height, $cb["w"]); - } - - if ( mb_strpos($max_height, "%") !== false ) { - $max_height = "none"; - } - else { - $max_height = $style->length_in_pt($max_height, $cb["w"]); - } - } - - if ( $max_height !== "none" && $min_height > $max_height ) { - // Swap 'em - list($max_height, $min_height) = array($min_height, $max_height); - } - - if ( $max_height !== "none" && $height > $max_height ) { - $height = $max_height; - } - - if ( $height < $min_height ) { - $height = $min_height; - } - } - - } - - return array($height, $margin_top, $margin_bottom, $top, $bottom); - - } - - /** - * Adjust the justification of each of our lines. - * http://www.w3.org/TR/CSS21/text.html#propdef-text-align - */ - protected function _text_align() { - $style = $this->_frame->get_style(); - $w = $this->_frame->get_containing_block("w"); - $width = $style->length_in_pt($style->width, $w); - - switch ($style->text_align) { - default: - case "left": - foreach ($this->_frame->get_line_boxes() as $line) { - if ( !$line->left ) { - continue; - } - - foreach($line->get_frames() as $frame) { - if ( $frame instanceof Block_Frame_Decorator) { - continue; - } - $frame->set_position( $frame->get_position("x") + $line->left ); - } - } - return; - - case "right": - foreach ($this->_frame->get_line_boxes() as $line) { - // Move each child over by $dx - $dx = $width - $line->w - $line->right; - - foreach($line->get_frames() as $frame) { - // Block frames are not aligned by text-align - if ($frame instanceof Block_Frame_Decorator) { - continue; - } - - $frame->set_position( $frame->get_position("x") + $dx ); - } - } - break; - - - case "justify": - // We justify all lines except the last one - $lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards) - array_pop($lines); - - foreach($lines as $i => $line) { - if ( $line->br ) { - unset($lines[$i]); - } - } - - // One space character's width. Will be used to get a more accurate spacing - $space_width = Font_Metrics::get_text_width(" ", $style->font_family, $style->font_size); - - foreach ($lines as $line) { - if ( $line->left ) { - foreach ( $line->get_frames() as $frame ) { - if ( !$frame instanceof Text_Frame_Decorator ) { - continue; - } - - $frame->set_position( $frame->get_position("x") + $line->left ); - } - } - - // Only set the spacing if the line is long enough. This is really - // just an aesthetic choice ;) - //if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) { - - // Set the spacing for each child - if ( $line->wc > 1 ) { - $spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1); - } - else { - $spacing = 0; - } - - $dx = 0; - foreach($line->get_frames() as $frame) { - if ( !$frame instanceof Text_Frame_Decorator ) { - continue; - } - - $text = $frame->get_text(); - $spaces = mb_substr_count($text, " "); - - $char_spacing = $style->length_in_pt($style->letter_spacing); - $_spacing = $spacing + $char_spacing; - - $frame->set_position( $frame->get_position("x") + $dx ); - $frame->set_text_spacing($_spacing); - - $dx += $spaces * $_spacing; - } - - // The line (should) now occupy the entire width - $line->w = $width; - - //} - } - break; - - case "center": - case "centre": - foreach ($this->_frame->get_line_boxes() as $line) { - // Centre each line by moving each frame in the line by: - $dx = ($width + $line->left - $line->w - $line->right ) / 2; - - foreach ($line->get_frames() as $frame) { - // Block frames are not aligned by text-align - if ($frame instanceof Block_Frame_Decorator) { - continue; - } - - $frame->set_position( $frame->get_position("x") + $dx ); - } - } - break; - } - } - - /** - * Align inline children vertically. - * Aligns each child vertically after each line is reflowed - */ - function vertical_align() { - - $canvas = null; - - foreach ( $this->_frame->get_line_boxes() as $line ) { - - $height = $line->h; - - foreach ( $line->get_frames() as $frame ) { - $style = $frame->get_style(); - - if ( $style->display !== "inline" ) { - continue; - } - - $align = $frame->get_parent()->get_style()->vertical_align; - - if ( !isset($canvas) ) { - $canvas = $frame->get_root()->get_dompdf()->get_canvas(); - } - - $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size); - $y_offset = 0; - - switch ($align) { - case "baseline": - $y_offset = $height*0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning - break; - - case "middle": - $y_offset = ($height*0.8 - $baseline) / 2; - break; - - case "sub": - $y_offset = 0.3 * $height; - break; - - case "super": - $y_offset = -0.2 * $height; - break; - - case "text-top": - case "top": // Not strictly accurate, but good enough for now - break; - - case "text-bottom": - case "bottom": - $y_offset = $height*0.8 - $baseline; - break; - } - - if ( $y_offset ) { - $frame->move(0, $y_offset); - } - } - } - } - - /** - * @param Frame $child - */ - function process_clear(Frame $child){ - $enable_css_float = $this->get_dompdf()->get_option("enable_css_float"); - if ( !$enable_css_float ) { - return; - } - - $child_style = $child->get_style(); - $root = $this->_frame->get_root(); - - // Handle "clear" - if ( $child_style->clear !== "none" ) { - $lowest_y = $root->get_lowest_float_offset($child); - - // If a float is still applying, we handle it - if ( $lowest_y ) { - if ( $child->is_in_flow() ) { - $line_box = $this->_frame->get_current_line_box(); - $line_box->y = $lowest_y + $child->get_margin_height(); - $line_box->left = 0; - $line_box->right = 0; - } - - $child->move(0, $lowest_y - $child->get_position("y")); - } - } - } - - /** - * @param Frame $child - * @param float $cb_x - * @param float $cb_w - */ - function process_float(Frame $child, $cb_x, $cb_w){ - $enable_css_float = $this->_frame->get_dompdf()->get_option("enable_css_float"); - if ( !$enable_css_float ) { - return; - } - - $child_style = $child->get_style(); - $root = $this->_frame->get_root(); - - // Handle "float" - if ( $child_style->float !== "none" ) { - $root->add_floating_frame($child); - - // Remove next frame's beginning whitespace - $next = $child->get_next_sibling(); - if ( $next && $next instanceof Text_Frame_Decorator) { - $next->set_text(ltrim($next->get_text())); - } - - $line_box = $this->_frame->get_current_line_box(); - list($old_x, $old_y) = $child->get_position(); - - $float_x = $cb_x; - $float_y = $old_y; - $float_w = $child->get_margin_width(); - - if ( $child_style->clear === "none" ) { - switch( $child_style->float ) { - case "left": - $float_x += $line_box->left; - break; - case "right": - $float_x += ($cb_w - $line_box->right - $float_w); - break; - } - } - else { - if ( $child_style->float === "right" ) { - $float_x += ($cb_w - $float_w); - } - } - - if ( $cb_w < $float_x + $float_w - $old_x ) { - // TODO handle when floating elements don't fit - } - - $line_box->get_float_offsets(); - - if ( $child->_float_next_line ) { - $float_y += $line_box->h; - } - - $child->set_position($float_x, $float_y); - $child->move($float_x - $old_x, $float_y - $old_y, true); - } - } - - /** - * @param Frame_Decorator $block - */ - function reflow(Block_Frame_Decorator $block = null) { - - // Check if a page break is forced - $page = $this->_frame->get_root(); - $page->check_forced_page_break($this->_frame); - - // Bail if the page is full - if ( $page->is_full() ) { - return; - } - - // Generated content - $this->_set_content(); - - // Collapse margins if required - $this->_collapse_margins(); - - $style = $this->_frame->get_style(); - $cb = $this->_frame->get_containing_block(); - - if ( $style->position === "fixed" ) { - $cb = $this->_frame->get_root()->get_containing_block(); - } - - // Determine the constraints imposed by this frame: calculate the width - // of the content area: - list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width(); - - // Store the calculated properties - $style->width = $w . "pt"; - $style->margin_left = $left_margin."pt"; - $style->margin_right = $right_margin."pt"; - $style->left = $left ."pt"; - $style->right = $right . "pt"; - - // Update the position - $this->_frame->position(); - list($x, $y) = $this->_frame->get_position(); - - // Adjust the first line based on the text-indent property - $indent = $style->length_in_pt($style->text_indent, $cb["w"]); - $this->_frame->increase_line_width($indent); - - // Determine the content edge - $top = $style->length_in_pt(array($style->margin_top, - $style->padding_top, - $style->border_top_width), $cb["h"]); - - $bottom = $style->length_in_pt(array($style->border_bottom_width, - $style->margin_bottom, - $style->padding_bottom), $cb["h"]); - - $cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width, - $style->padding_left), $cb["w"]); - - $cb_y = $y + $top; - - $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y; - - // Set the y position of the first line in this block - $line_box = $this->_frame->get_current_line_box(); - $line_box->y = $cb_y; - $line_box->get_float_offsets(); - - // Set the containing blocks and reflow each child - foreach ( $this->_frame->get_children() as $child ) { - - // Bail out if the page is full - if ( $page->is_full() ) { - break; - } - - $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); - - $this->process_clear($child); - - $child->reflow($this->_frame); - - // Don't add the child to the line if a page break has occurred - if ( $page->check_page_break($child) ) { - break; - } - - $this->process_float($child, $cb_x, $w); - } - - // Determine our height - list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height(); - $style->height = $height; - $style->margin_top = $margin_top; - $style->margin_bottom = $margin_bottom; - $style->top = $top; - $style->bottom = $bottom; - - $needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto")); - - // Absolute positioning measurement - if ( $needs_reposition ) { - $orig_style = $this->_frame->get_original_style(); - if ( $orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto") ) { - $width = 0; - foreach ($this->_frame->get_line_boxes() as $line) { - $width = max($line->w, $width); - } - $style->width = $width; - } - - $style->left = $orig_style->left; - $style->right = $orig_style->right; - } - - $this->_text_align(); - $this->vertical_align(); - - // Absolute positioning - if ( $needs_reposition ) { - list($x, $y) = $this->_frame->get_position(); - $this->_frame->position(); - list($new_x, $new_y) = $this->_frame->get_position(); - $this->_frame->move($new_x-$x, $new_y-$y, true); - } - - if ( $block && $this->_frame->is_in_flow() ) { - $block->add_frame_to_line($this->_frame); - - // May be inline-block - if ( $style->display === "block" ) { - $block->add_line(); - } - } - } -} diff --git a/application/helpers/dompdf/include/block_positioner.cls.php b/application/helpers/dompdf/include/block_positioner.cls.php deleted file mode 100755 index d7e1c3fbc..000000000 --- a/application/helpers/dompdf/include/block_positioner.cls.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Positions block frames - * - * @access private - * @package dompdf - */ -class Block_Positioner extends Positioner { - - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - //........................................................................ - - function position() { - $frame = $this->_frame; - $style = $frame->get_style(); - $cb = $frame->get_containing_block(); - $p = $frame->find_block_parent(); - - if ( $p ) { - $float = $style->float; - - $enable_css_float = $frame->get_dompdf()->get_option("enable_css_float"); - if ( !$enable_css_float || !$float || $float === "none" ) { - $p->add_line(true); - } - $y = $p->get_current_line_box()->y; - - } - else { - $y = $cb["y"]; - } - - $x = $cb["x"]; - - // Relative positionning - if ( $style->position === "relative" ) { - $top = $style->length_in_pt($style->top, $cb["h"]); - //$right = $style->length_in_pt($style->right, $cb["w"]); - //$bottom = $style->length_in_pt($style->bottom, $cb["h"]); - $left = $style->length_in_pt($style->left, $cb["w"]); - - $x += $left; - $y += $top; - } - - $frame->set_position($x, $y); - } -} diff --git a/application/helpers/dompdf/include/block_renderer.cls.php b/application/helpers/dompdf/include/block_renderer.cls.php deleted file mode 100755 index ef42c93d5..000000000 --- a/application/helpers/dompdf/include/block_renderer.cls.php +++ /dev/null @@ -1,230 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Renders block frames - * - * @access private - * @package dompdf - */ -class Block_Renderer extends Abstract_Renderer { - - //........................................................................ - - 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") ) { - $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 (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) { - $this->_debug_layout($frame->get_border_box(), "red"); - if (DEBUG_LAYOUT_PADDINGBOX) { - $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5)); - } - } - - if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES && $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"); - } - } - } - - protected function _render_border(Frame_Decorator $frame, $border_box = null, $corner_style = "bevel") { - $style = $frame->get_style(); - $bp = $style->get_border_properties(); - - if ( empty($border_box) ) { - $border_box = $frame->get_border_box(); - } - - // find the radius - $radius = $style->get_computed_border_radius($border_box[2], $border_box[3]); // w, h - - // Short-cut: If all the borders are "solid" with the same color and style, and no radius, we'd better draw a rectangle - if ( - in_array($bp["top"]["style"], array("solid", "dashed", "dotted")) && - $bp["top"] == $bp["right"] && - $bp["right"] == $bp["bottom"] && - $bp["bottom"] == $bp["left"] && - array_sum($radius) == 0 - ) { - $props = $bp["top"]; - if ( $props["color"] === "transparent" || $props["width"] <= 0 ) return; - - list($x, $y, $w, $h) = $border_box; - $width = $style->length_in_pt($props["width"]); - $pattern = $this->_get_dash_pattern($props["style"], $width); - $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern); - return; - } - - // Do it the long way - $widths = array($style->length_in_pt($bp["top"]["width"]), - $style->length_in_pt($bp["right"]["width"]), - $style->length_in_pt($bp["bottom"]["width"]), - $style->length_in_pt($bp["left"]["width"])); - - foreach ($bp as $side => $props) { - list($x, $y, $w, $h) = $border_box; - $length = 0; - $r1 = 0; - $r2 = 0; - - if ( !$props["style"] || - $props["style"] === "none" || - $props["width"] <= 0 || - $props["color"] == "transparent" ) - continue; - - switch($side) { - case "top": - $length = $w; - $r1 = $radius["top-left"]; - $r2 = $radius["top-right"]; - break; - - case "bottom": - $length = $w; - $y += $h; - $r1 = $radius["bottom-left"]; - $r2 = $radius["bottom-right"]; - break; - - case "left": - $length = $h; - $r1 = $radius["top-left"]; - $r2 = $radius["bottom-left"]; - break; - - case "right": - $length = $h; - $x += $w; - $r1 = $radius["top-right"]; - $r2 = $radius["bottom-right"]; - break; - default: - break; - } - $method = "_border_" . $props["style"]; - - // draw rounded corners - $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2); - } - } - - protected function _render_outline(Frame_Decorator $frame, $border_box = null, $corner_style = "bevel") { - $style = $frame->get_style(); - - $props = array( - "width" => $style->outline_width, - "style" => $style->outline_style, - "color" => $style->outline_color, - ); - - if ( !$props["style"] || $props["style"] === "none" || $props["width"] <= 0 ) - return; - - if ( empty($border_box) ) { - $border_box = $frame->get_border_box(); - } - - $offset = $style->length_in_pt($props["width"]); - $pattern = $this->_get_dash_pattern($props["style"], $offset); - - // If the outline style is "solid" we'd better draw a rectangle - if ( in_array($props["style"], array("solid", "dashed", "dotted")) ) { - $border_box[0] -= $offset / 2; - $border_box[1] -= $offset / 2; - $border_box[2] += $offset; - $border_box[3] += $offset; - - list($x, $y, $w, $h) = $border_box; - $this->_canvas->rectangle($x, $y, $w, $h, $props["color"], $offset, $pattern); - return; - } - - $border_box[0] -= $offset; - $border_box[1] -= $offset; - $border_box[2] += $offset * 2; - $border_box[3] += $offset * 2; - - $method = "_border_" . $props["style"]; - $widths = array_fill(0, 4, $props["width"]); - $sides = array("top", "right", "left", "bottom"); - $length = 0; - - foreach ($sides as $side) { - list($x, $y, $w, $h) = $border_box; - - switch($side) { - case "top": - $length = $w; - break; - - case "bottom": - $length = $w; - $y += $h; - break; - - case "left": - $length = $h; - break; - - case "right": - $length = $h; - $x += $w; - break; - default: - break; - } - - $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style); - } - } -} diff --git a/application/helpers/dompdf/include/cached_pdf_decorator.cls.php b/application/helpers/dompdf/include/cached_pdf_decorator.cls.php deleted file mode 100755 index 519e572e8..000000000 --- a/application/helpers/dompdf/include/cached_pdf_decorator.cls.php +++ /dev/null @@ -1,164 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Caching canvas implementation - * - * Each rendered page is serialized and stored in the {@link Page_Cache}. - * This is useful for static forms/pages that do not need to be re-rendered - * all the time. - * - * This class decorates normal CPDF_Adapters. It is currently completely - * experimental. - * - * @access private - * @package dompdf - */ -class Cached_PDF_Decorator extends CPDF_Adapter implements Canvas { - /** - * @var CPDF_Adapter - */ - protected $_pdf; - protected $_cache_id; - protected $_current_page_id; - protected $_fonts; // fonts used in this document - - function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf) { - $this->_fonts = array(); - } - - /** - * Must be called after constructor - * - * @param int $cache_id - * @param CPDF_Adapter $pdf - */ - function init($cache_id, CPDF_Adapter $pdf) { - $this->_cache_id = $cache_id; - $this->_pdf = $pdf; - $this->_current_page_id = $this->_pdf->open_object(); - } - - //........................................................................ - - function get_cpdf() { return $this->_pdf->get_cpdf(); } - - function open_object() { $this->_pdf->open_object(); } - function reopen_object($object) { $this->_pdf->reopen_object($object); } - - function close_object() { $this->_pdf->close_object(); } - - function add_object($object, $where = 'all') { $this->_pdf->add_object($object, $where); } - - function serialize_object($id) { $this->_pdf->serialize_object($id); } - - function reopen_serialized_object($obj) { $this->_pdf->reopen_serialized_object($obj); } - - //........................................................................ - - function get_width() { return $this->_pdf->get_width(); } - function get_height() { return $this->_pdf->get_height(); } - function get_page_number() { return $this->_pdf->get_page_number(); } - function get_page_count() { return $this->_pdf->get_page_count(); } - - function set_page_number($num) { $this->_pdf->set_page_number($num); } - function set_page_count($count) { $this->_pdf->set_page_count($count); } - - function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) { - $this->_pdf->line($x1, $y1, $x2, $y2, $color, $width, $style); - } - - function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) { - $this->_pdf->rectangle($x1, $y1, $w, $h, $color, $width, $style); - } - - function filled_rectangle($x1, $y1, $w, $h, $color) { - $this->_pdf->filled_rectangle($x1, $y1, $w, $h, $color); - } - - function polygon($points, $color, $width = null, $style = array(), $fill = false) { - $this->_pdf->polygon($points, $color, $width, $style, $fill); - } - - function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) { - $this->_pdf->circle($x, $y, $r1, $color, $width, $style, $fill); - } - - function image($img_url, $x, $y, $w, $h, $resolution = "normal") { - $this->_pdf->image($img_url, $x, $y, $w, $h, $resolution); - } - - function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) { - $this->_fonts[$font] = true; - $this->_pdf->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle); - } - - function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) { - - // We want to remove this from cached pages since it may not be correct - $this->_pdf->close_object(); - $this->_pdf->page_text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle); - $this->_pdf->reopen_object($this->_current_page_id); - } - - function page_script($script, $type = 'text/php') { - - // We want to remove this from cached pages since it may not be correct - $this->_pdf->close_object(); - $this->_pdf->page_script($script, $type); - $this->_pdf->reopen_object($this->_current_page_id); - } - - function new_page() { - $this->_pdf->close_object(); - - // Add the object to the current page - $this->_pdf->add_object($this->_current_page_id, "add"); - $this->_pdf->new_page(); - - Page_Cache::store_page($this->_cache_id, - $this->_pdf->get_page_number() - 1, - $this->_pdf->serialize_object($this->_current_page_id)); - - $this->_current_page_id = $this->_pdf->open_object(); - return $this->_current_page_id; - } - - function stream($filename, $options = null) { - // Store the last page in the page cache - if ( !is_null($this->_current_page_id) ) { - $this->_pdf->close_object(); - $this->_pdf->add_object($this->_current_page_id, "add"); - Page_Cache::store_page($this->_cache_id, - $this->_pdf->get_page_number(), - $this->_pdf->serialize_object($this->_current_page_id)); - Page_Cache::store_fonts($this->_cache_id, $this->_fonts); - $this->_current_page_id = null; - } - - $this->_pdf->stream($filename); - - } - - function output($options = null) { - // Store the last page in the page cache - if ( !is_null($this->_current_page_id) ) { - $this->_pdf->close_object(); - $this->_pdf->add_object($this->_current_page_id, "add"); - Page_Cache::store_page($this->_cache_id, - $this->_pdf->get_page_number(), - $this->_pdf->serialize_object($this->_current_page_id)); - $this->_current_page_id = null; - } - - return $this->_pdf->output(); - } - - function get_messages() { return $this->_pdf->get_messages(); } - -} diff --git a/application/helpers/dompdf/include/canvas.cls.php b/application/helpers/dompdf/include/canvas.cls.php deleted file mode 100755 index 0158df6b1..000000000 --- a/application/helpers/dompdf/include/canvas.cls.php +++ /dev/null @@ -1,385 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Main rendering interface - * - * Currently {@link CPDF_Adapter}, {@link PDFLib_Adapter}, {@link TCPDF_Adapter}, and {@link GD_Adapter} - * implement this interface. - * - * Implementations should measure x and y increasing to the left and down, - * respectively, with the origin in the top left corner. Implementations - * are free to use a unit other than points for length, but I can't - * guarantee that the results will look any good. - * - * @package dompdf - */ -interface Canvas { - function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf); - - /** - * @return DOMPDF - */ - function get_dompdf(); - - /** - * Returns the current page number - * - * @return int - */ - function get_page_number(); - - /** - * Returns the total number of pages - * - * @return int - */ - function get_page_count(); - - /** - * Sets the total number of pages - * - * @param int $count - */ - function set_page_count($count); - - /** - * Draws a line from x1,y1 to x2,y2 - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the format of the - * $style parameter (aka dash). - * - * @param float $x1 - * @param float $y1 - * @param float $x2 - * @param float $y2 - * @param array $color - * @param float $width - * @param array $style - */ - function line($x1, $y1, $x2, $y2, $color, $width, $style = null); - - /** - * Draws a rectangle at x1,y1 with width w and height h - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - * @param array $color - * @param float $width - * @param array $style - */ - function rectangle($x1, $y1, $w, $h, $color, $width, $style = null); - - /** - * Draws a filled rectangle at x1,y1 with width w and height h - * - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - * @param array $color - */ - function filled_rectangle($x1, $y1, $w, $h, $color); - - /** - * Starts a clipping rectangle at x1,y1 with width w and height h - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - */ - function clipping_rectangle($x1, $y1, $w, $h); - - /** - * Starts a rounded clipping rectangle at x1,y1 with width w and height h - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - * @param float $tl - * @param float $tr - * @param float $br - * @param float $bl - * - * @return - */ - function clipping_roundrectangle($x1, $y1, $w, $h, $tl, $tr, $br, $bl); - - /** - * Ends the last clipping shape - */ - function clipping_end(); - - /** - * Save current state - */ - function save(); - - /** - * Restore last state - */ - function restore(); - - /** - * Rotate - */ - function rotate($angle, $x, $y); - - /** - * Skew - */ - function skew($angle_x, $angle_y, $x, $y); - - /** - * Scale - */ - function scale($s_x, $s_y, $x, $y); - - /** - * Translate - */ - function translate($t_x, $t_y); - - /** - * Transform - */ - function transform($a, $b, $c, $d, $e, $f); - - /** - * Draws a polygon - * - * The polygon is formed by joining all the points stored in the $points - * array. $points has the following structure: - * - * array(0 => x1, - * 1 => y1, - * 2 => x2, - * 3 => y2, - * ... - * ); - * - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param array $points - * @param array $color - * @param float $width - * @param array $style - * @param bool $fill Fills the polygon if true - */ - function polygon($points, $color, $width = null, $style = null, $fill = false); - - /** - * Draws a circle at $x,$y with radius $r - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param float $x - * @param float $y - * @param float $r - * @param array $color - * @param float $width - * @param array $style - * @param bool $fill Fills the circle if true - */ - function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false); - - /** - * Add an image to the pdf. - * - * The image is placed at the specified x and y coordinates with the - * given width and height. - * - * @param string $img_url the path to the image - * @param float $x x position - * @param float $y y position - * @param int $w width (in pixels) - * @param int $h height (in pixels) - * @param string $resolution The resolution of the image - */ - function image($img_url, $x, $y, $w, $h, $resolution = "normal"); - - /** - * Add an arc to the PDF - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x X coordinate of the arc - * @param float $y Y coordinate of the arc - * @param float $r1 Radius 1 - * @param float $r2 Radius 2 - * @param float $astart Start angle in degrees - * @param float $aend End angle in degrees - * @param array $color Color - * @param float $width - * @param array $style - * - * @return void - */ - function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array()); - - /** - * Writes text at the specified x and y coordinates - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x - * @param float $y - * @param string $text the text to write - * @param string $font the font file to use - * @param float $size the font size, in points - * @param array $color - * @param float $word_space word spacing adjustment - * @param float $char_space char spacing adjustment - * @param float $angle angle - * - * @return void - */ - function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0); - - /** - * Add a named destination (similar to ... in html) - * - * @param string $anchorname The name of the named destination - */ - function add_named_dest($anchorname); - - /** - * Add a link to the pdf - * - * @param string $url The url to link to - * @param float $x The x position of the link - * @param float $y The y position of the link - * @param float $width The width of the link - * @param float $height The height of the link - * - * @return void - */ - function add_link($url, $x, $y, $width, $height); - - /** - * Add meta information to the pdf - * - * @param string $name Label of the value (Creator, Producer, etc.) - * @param string $value The text to set - */ - function add_info($name, $value); - - /** - * Calculates text size, in points - * - * @param string $text the text to be sized - * @param string $font the desired font - * @param float $size the desired font size - * @param float $word_spacing word spacing, if any - * @param float $char_spacing - * - * @return float - */ - function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0); - - /** - * Calculates font height, in points - * - * @param string $font - * @param float $size - * - * @return float - */ - function get_font_height($font, $size); - - /** - * Calculates font baseline, in points - * - * @param string $font - * @param float $size - * - * @return float - */ - function get_font_baseline($font, $size); - - /** - * Returns the font x-height, in points - * - * @param string $font - * @param float $size - * - * @return float - */ - //function get_font_x_height($font, $size); - - /** - * Sets the opacity - * - * @param float $opacity - * @param string $mode - */ - function set_opacity($opacity, $mode = "Normal"); - - /** - * Sets the default view - * - * @param string $view - * 'XYZ' left, top, zoom - * 'Fit' - * 'FitH' top - * 'FitV' left - * 'FitR' left,bottom,right - * 'FitB' - * 'FitBH' top - * 'FitBV' left - * @param array $options - * - * @return void - */ - function set_default_view($view, $options = array()); - - /** - * @param string $script - * - * @return void - */ - function javascript($script); - - /** - * Starts a new page - * - * Subsequent drawing operations will appear on the new page. - */ - function new_page(); - - /** - * Streams the PDF directly to the browser - * - * @param string $filename the name of the PDF file - * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0 - */ - function stream($filename, $options = null); - - /** - * Returns the PDF as a string - * - * @param array $options associative array: 'compress' => 1 or 0 - * @return string - */ - function output($options = null); -} diff --git a/application/helpers/dompdf/include/canvas_factory.cls.php b/application/helpers/dompdf/include/canvas_factory.cls.php deleted file mode 100755 index ef634e6b0..000000000 --- a/application/helpers/dompdf/include/canvas_factory.cls.php +++ /dev/null @@ -1,63 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Create canvas instances - * - * The canvas factory creates canvas instances based on the - * availability of rendering backends and config options. - * - * @package dompdf - */ -class Canvas_Factory { - - /** - * Constructor is private: this is a static class - */ - private function __construct() { } - - /** - * @param DOMPDF $dompdf - * @param string|array $paper - * @param string $orientation - * @param string $class - * - * @return Canvas - */ - static function get_instance(DOMPDF $dompdf, $paper = null, $orientation = null, $class = null) { - - $backend = strtolower(DOMPDF_PDF_BACKEND); - - if ( isset($class) && class_exists($class, false) ) { - $class .= "_Adapter"; - } - - else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "pdflib" ) && - class_exists("PDFLib", false) ) { - $class = "PDFLib_Adapter"; - } - - // FIXME The TCPDF adapter is not ready yet - //else if ( (DOMPDF_PDF_BACKEND === "auto" || $backend === "cpdf") ) - // $class = "CPDF_Adapter"; - - else if ( $backend === "tcpdf" ) { - $class = "TCPDF_Adapter"; - } - - else if ( $backend === "gd" ) { - $class = "GD_Adapter"; - } - - else { - $class = "CPDF_Adapter"; - } - - return new $class($paper, $orientation, $dompdf); - } -} diff --git a/application/helpers/dompdf/include/cellmap.cls.php b/application/helpers/dompdf/include/cellmap.cls.php deleted file mode 100755 index 0982849b3..000000000 --- a/application/helpers/dompdf/include/cellmap.cls.php +++ /dev/null @@ -1,790 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Maps table cells to the table grid. - * - * This class resolves borders in tables with collapsed borders and helps - * place row & column spanned table cells. - * - * @access private - * @package dompdf - */ -class Cellmap { - - /** - * Border style weight lookup for collapsed border resolution. - * - * @var array - */ - static protected $_BORDER_STYLE_SCORE = array( - "inset" => 1, - "groove" => 2, - "outset" => 3, - "ridge" => 4, - "dotted" => 5, - "dashed" => 6, - "solid" => 7, - "double" => 8, - "hidden" => 9, - "none" => 0, - ); - - /** - * The table object this cellmap is attached to. - * - * @var Table_Frame_Decorator - */ - protected $_table; - - /** - * The total number of rows in the table - * - * @var int - */ - protected $_num_rows; - - /** - * The total number of columns in the table - * - * @var int - */ - protected $_num_cols; - - /** - * 2D array mapping to frames - * - * @var Frame[][] - */ - protected $_cells; - - /** - * 1D array of column dimensions - * - * @var array - */ - protected $_columns; - - /** - * 1D array of row dimensions - * - * @var array - */ - protected $_rows; - - /** - * 2D array of border specs - * - * @var array - */ - protected $_borders; - - /** - * 1D Array mapping frames to (multiple) pairs, keyed on frame_id. - * - * @var Frame[] - */ - protected $_frames; - - /** - * Current column when adding cells, 0-based - * - * @var int - */ - private $__col; - - /** - * Current row when adding cells, 0-based - * - * @var int - */ - private $__row; - - /** - * Tells wether the columns' width can be modified - * - * @var bool - */ - private $_columns_locked = false; - - /** - * Tells wether the table has table-layout:fixed - * - * @var bool - */ - private $_fixed_layout = false; - - //........................................................................ - - function __construct(Table_Frame_Decorator $table) { - $this->_table = $table; - $this->reset(); - } - - function __destruct() { - clear_object($this); - } - //........................................................................ - - function reset() { - $this->_num_rows = 0; - $this->_num_cols = 0; - - $this->_cells = array(); - $this->_frames = array(); - - if ( !$this->_columns_locked ) { - $this->_columns = array(); - } - - $this->_rows = array(); - - $this->_borders = array(); - - $this->__col = $this->__row = 0; - } - - //........................................................................ - - function lock_columns() { - $this->_columns_locked = true; - } - - function is_columns_locked() { - return $this->_columns_locked; - } - - function set_layout_fixed($fixed) { - $this->_fixed_layout = $fixed; - } - - function is_layout_fixed() { - return $this->_fixed_layout; - } - - function get_num_rows() { return $this->_num_rows; } - function get_num_cols() { return $this->_num_cols; } - - function &get_columns() { - return $this->_columns; - } - - function set_columns($columns) { - $this->_columns = $columns; - } - - function &get_column($i) { - if ( !isset($this->_columns[$i]) ) { - $this->_columns[$i] = array( - "x" => 0, - "min-width" => 0, - "max-width" => 0, - "used-width" => null, - "absolute" => 0, - "percent" => 0, - "auto" => true, - ); - } - - return $this->_columns[$i]; - } - - function &get_rows() { - return $this->_rows; - } - - function &get_row($j) { - if ( !isset($this->_rows[$j]) ) { - $this->_rows[$j] = array( - "y" => 0, - "first-column" => 0, - "height" => null, - ); - } - - return $this->_rows[$j]; - } - - function get_border($i, $j, $h_v, $prop = null) { - if ( !isset($this->_borders[$i][$j][$h_v]) ) { - $this->_borders[$i][$j][$h_v] = array( - "width" => 0, - "style" => "solid", - "color" => "black", - ); - } - - if ( isset($prop) ) { - return $this->_borders[$i][$j][$h_v][$prop]; - } - - return $this->_borders[$i][$j][$h_v]; - } - - function get_border_properties($i, $j) { - return array( - "top" => $this->get_border($i, $j, "horizontal"), - "right" => $this->get_border($i, $j+1, "vertical"), - "bottom" => $this->get_border($i+1, $j, "horizontal"), - "left" => $this->get_border($i, $j, "vertical"), - ); - } - - //........................................................................ - - function get_spanned_cells(Frame $frame) { - $key = $frame->get_id(); - - if ( !isset($this->_frames[$key]) ) { - throw new DOMPDF_Exception("Frame not found in cellmap"); - } - - return $this->_frames[$key]; - - } - - function frame_exists_in_cellmap(Frame $frame) { - $key = $frame->get_id(); - return isset($this->_frames[$key]); - } - - function get_frame_position(Frame $frame) { - global $_dompdf_warnings; - - $key = $frame->get_id(); - - if ( !isset($this->_frames[$key]) ) { - throw new DOMPDF_Exception("Frame not found in cellmap"); - } - - $col = $this->_frames[$key]["columns"][0]; - $row = $this->_frames[$key]["rows"][0]; - - if ( !isset($this->_columns[$col])) { - $_dompdf_warnings[] = "Frame not found in columns array. Check your table layout for missing or extra TDs."; - $x = 0; - } - else { - $x = $this->_columns[$col]["x"]; - } - - if ( !isset($this->_rows[$row])) { - $_dompdf_warnings[] = "Frame not found in row array. Check your table layout for missing or extra TDs."; - $y = 0; - } - else { - $y = $this->_rows[$row]["y"]; - } - - return array($x, $y, "x" => $x, "y" => $y); - } - - function get_frame_width(Frame $frame) { - $key = $frame->get_id(); - - if ( !isset($this->_frames[$key]) ) { - throw new DOMPDF_Exception("Frame not found in cellmap"); - } - - $cols = $this->_frames[$key]["columns"]; - $w = 0; - foreach ($cols as $i) { - $w += $this->_columns[$i]["used-width"]; - } - - return $w; - } - - function get_frame_height(Frame $frame) { - $key = $frame->get_id(); - - if ( !isset($this->_frames[$key]) ) { - throw new DOMPDF_Exception("Frame not found in cellmap"); - } - - $rows = $this->_frames[$key]["rows"]; - $h = 0; - foreach ($rows as $i) { - if ( !isset($this->_rows[$i]) ) { - throw new Exception("The row #$i could not be found, please file an issue in the tracker with the HTML code"); - } - - $h += $this->_rows[$i]["height"]; - } - - return $h; - } - - - //........................................................................ - - function set_column_width($j, $width) { - if ( $this->_columns_locked ) { - return; - } - - $col =& $this->get_column($j); - $col["used-width"] = $width; - $next_col =& $this->get_column($j+1); - $next_col["x"] = $next_col["x"] + $width; - } - - function set_row_height($i, $height) { - $row =& $this->get_row($i); - - if ( $row["height"] !== null && $height <= $row["height"] ) { - return; - } - - $row["height"] = $height; - $next_row =& $this->get_row($i+1); - $next_row["y"] = $row["y"] + $height; - - } - - //........................................................................ - - - protected function _resolve_border($i, $j, $h_v, $border_spec) { - $n_width = $border_spec["width"]; - $n_style = $border_spec["style"]; - - if ( !isset($this->_borders[$i][$j][$h_v]) ) { - $this->_borders[$i][$j][$h_v] = $border_spec; - return $this->_borders[$i][$j][$h_v]["width"]; - } - - $border = &$this->_borders[$i][$j][$h_v]; - - $o_width = $border["width"]; - $o_style = $border["style"]; - - if ( ($n_style === "hidden" || - $n_width > $o_width || - $o_style === "none") - - or - - ($o_width == $n_width && - in_array($n_style, self::$_BORDER_STYLE_SCORE) && - self::$_BORDER_STYLE_SCORE[ $n_style ] > self::$_BORDER_STYLE_SCORE[ $o_style ]) ) { - $border = $border_spec; - } - - return $border["width"]; - } - - //........................................................................ - - function add_frame(Frame $frame) { - - $style = $frame->get_style(); - $display = $style->display; - - $collapse = $this->_table->get_style()->border_collapse == "collapse"; - - // Recursively add the frames within tables, table-row-groups and table-rows - if ( $display === "table-row" || - $display === "table" || - $display === "inline-table" || - in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) { - - $start_row = $this->__row; - foreach ( $frame->get_children() as $child ) { - $this->add_frame( $child ); - } - - if ( $display === "table-row" ) { - $this->add_row(); - } - - $num_rows = $this->__row - $start_row - 1; - $key = $frame->get_id(); - - // Row groups always span across the entire table - $this->_frames[$key]["columns"] = range(0,max(0,$this->_num_cols-1)); - $this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1)); - $this->_frames[$key]["frame"] = $frame; - - if ( $display !== "table-row" && $collapse ) { - - $bp = $style->get_border_properties(); - - // Resolve the borders - for ( $i = 0; $i < $num_rows+1; $i++) { - $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]); - $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]); - } - - for ( $j = 0; $j < $this->_num_cols; $j++) { - $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]); - $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]); - } - } - - - return; - } - - $node = $frame->get_node(); - - // Determine where this cell is going - $colspan = $node->getAttribute("colspan"); - $rowspan = $node->getAttribute("rowspan"); - - if ( !$colspan ) { - $colspan = 1; - $node->setAttribute("colspan",1); - } - - if ( !$rowspan ) { - $rowspan = 1; - $node->setAttribute("rowspan",1); - } - $key = $frame->get_id(); - - $bp = $style->get_border_properties(); - - - // Add the frame to the cellmap - $max_left = $max_right = 0; - - // Find the next available column (fix by Ciro Mondueri) - $ac = $this->__col; - while ( isset($this->_cells[$this->__row][$ac]) ) { - $ac++; - } - - $this->__col = $ac; - - // Rows: - for ( $i = 0; $i < $rowspan; $i++ ) { - $row = $this->__row + $i; - - $this->_frames[$key]["rows"][] = $row; - - for ( $j = 0; $j < $colspan; $j++) { - $this->_cells[$row][$this->__col + $j] = $frame; - } - - if ( $collapse ) { - // Resolve vertical borders - $max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"])); - $max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"])); - } - } - - $max_top = $max_bottom = 0; - - // Columns: - for ( $j = 0; $j < $colspan; $j++ ) { - $col = $this->__col + $j; - $this->_frames[$key]["columns"][] = $col; - - if ( $collapse ) { - // Resolve horizontal borders - $max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"])); - $max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"])); - } - } - - $this->_frames[$key]["frame"] = $frame; - - // Handle seperated border model - if ( !$collapse ) { - list($h, $v) = $this->_table->get_style()->border_spacing; - - // Border spacing is effectively a margin between cells - $v = $style->length_in_pt($v) / 2; - $h = $style->length_in_pt($h) / 2; - $style->margin = "$v $h"; - - // The additional 1/2 width gets added to the table proper - } - else { - // Drop the frame's actual border - $style->border_left_width = $max_left / 2; - $style->border_right_width = $max_right / 2; - $style->border_top_width = $max_top / 2; - $style->border_bottom_width = $max_bottom / 2; - $style->margin = "none"; - } - - if ( !$this->_columns_locked ) { - // Resolve the frame's width - if ( $this->_fixed_layout ) { - list($frame_min, $frame_max) = array(0, 10e-10); - } - else { - list($frame_min, $frame_max) = $frame->get_min_max_width(); - } - - $width = $style->width; - - $val = null; - if ( is_percent($width) ) { - $var = "percent"; - $val = (float)rtrim($width, "% ") / $colspan; - } - else if ( $width !== "auto" ) { - $var = "absolute"; - $val = $style->length_in_pt($frame_min) / $colspan; - } - - $min = 0; - $max = 0; - for ( $cs = 0; $cs < $colspan; $cs++ ) { - - // Resolve the frame's width(s) with other cells - $col =& $this->get_column( $this->__col + $cs ); - - // Note: $var is either 'percent' or 'absolute'. We compare the - // requested percentage or absolute values with the existing widths - // and adjust accordingly. - if ( isset($var) && $val > $col[$var] ) { - $col[$var] = $val; - $col["auto"] = false; - } - - $min += $col["min-width"]; - $max += $col["max-width"]; - } - - if ( $frame_min > $min ) { - // The frame needs more space. Expand each sub-column - // FIXME try to avoid putting this dummy value when table-layout:fixed - $inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_min - $min) / $colspan); - for ($c = 0; $c < $colspan; $c++) { - $col =& $this->get_column($this->__col + $c); - $col["min-width"] += $inc; - } - } - - if ( $frame_max > $max ) { - // FIXME try to avoid putting this dummy value when table-layout:fixed - $inc = ($this->is_layout_fixed() ? 10e-10 : ($frame_max - $max) / $colspan); - for ($c = 0; $c < $colspan; $c++) { - $col =& $this->get_column($this->__col + $c); - $col["max-width"] += $inc; - } - } - } - - $this->__col += $colspan; - if ( $this->__col > $this->_num_cols ) - $this->_num_cols = $this->__col; - - } - - //........................................................................ - - function add_row() { - - $this->__row++; - $this->_num_rows++; - - // Find the next available column - $i = 0; - while ( isset($this->_cells[$this->__row][$i]) ) { - $i++; - } - - $this->__col = $i; - - } - - //........................................................................ - - /** - * Remove a row from the cellmap. - * - * @param Frame - */ - function remove_row(Frame $row) { - - $key = $row->get_id(); - if ( !isset($this->_frames[$key]) ) { - return; // Presumably this row has alredy been removed - } - - $this->_row = $this->_num_rows--; - - $rows = $this->_frames[$key]["rows"]; - $columns = $this->_frames[$key]["columns"]; - - // Remove all frames from this row - foreach ( $rows as $r ) { - foreach ( $columns as $c ) { - if ( isset($this->_cells[$r][$c]) ) { - $id = $this->_cells[$r][$c]->get_id(); - - $this->_frames[$id] = null; - unset($this->_frames[$id]); - - $this->_cells[$r][$c] = null; - unset($this->_cells[$r][$c]); - } - } - - $this->_rows[$r] = null; - unset($this->_rows[$r]); - } - - $this->_frames[$key] = null; - unset($this->_frames[$key]); - - } - - /** - * Remove a row group from the cellmap. - * - * @param Frame $group The group to remove - */ - function remove_row_group(Frame $group) { - - $key = $group->get_id(); - if ( !isset($this->_frames[$key]) ) { - return; // Presumably this row has alredy been removed - } - - $iter = $group->get_first_child(); - while ($iter) { - $this->remove_row($iter); - $iter = $iter->get_next_sibling(); - } - - $this->_frames[$key] = null; - unset($this->_frames[$key]); - } - - /** - * Update a row group after rows have been removed - * - * @param Frame $group The group to update - * @param Frame $last_row The last row in the row group - */ - function update_row_group(Frame $group, Frame $last_row) { - - $g_key = $group->get_id(); - $r_key = $last_row->get_id(); - - $r_rows = $this->_frames[$r_key]["rows"]; - $this->_frames[$g_key]["rows"] = range( $this->_frames[$g_key]["rows"][0], end($r_rows) ); - - } - - //........................................................................ - - function assign_x_positions() { - // Pre-condition: widths must be resolved and assigned to columns and - // column[0]["x"] must be set. - - if ( $this->_columns_locked ) { - return; - } - - $x = $this->_columns[0]["x"]; - foreach ( array_keys($this->_columns) as $j ) { - $this->_columns[$j]["x"] = $x; - $x += $this->_columns[$j]["used-width"]; - } - - } - - function assign_frame_heights() { - // Pre-condition: widths and heights of each column & row must be - // calcluated - - foreach ( $this->_frames as $arr ) { - $frame = $arr["frame"]; - - $h = 0; - foreach( $arr["rows"] as $row ) { - if ( !isset($this->_rows[$row]) ) { - // The row has been removed because of a page split, so skip it. - continue; - } - - $h += $this->_rows[$row]["height"]; - } - - if ( $frame instanceof Table_Cell_Frame_Decorator ) { - $frame->set_cell_height($h); - } - else { - $frame->get_style()->height = $h; - } - } - - } - - //........................................................................ - - /** - * Re-adjust frame height if the table height is larger than its content - */ - function set_frame_heights($table_height, $content_height) { - - - // Distribute the increased height proportionally amongst each row - foreach ( $this->_frames as $arr ) { - $frame = $arr["frame"]; - - $h = 0; - foreach ($arr["rows"] as $row ) { - if ( !isset($this->_rows[$row]) ) { - continue; - } - - $h += $this->_rows[$row]["height"]; - } - - if ( $content_height > 0 ) { - $new_height = ($h / $content_height) * $table_height; - } - else { - $new_height = 0; - } - - if ( $frame instanceof Table_Cell_Frame_Decorator ) { - $frame->set_cell_height($new_height); - } - else { - $frame->get_style()->height = $new_height; - } - } - - } - - //........................................................................ - - // Used for debugging: - function __toString() { - $str = ""; - $str .= "Columns:
"; - $str .= pre_r($this->_columns, true); - $str .= "Rows:
"; - $str .= pre_r($this->_rows, true); - - $str .= "Frames:
"; - $arr = array(); - foreach ( $this->_frames as $key => $val ) { - $arr[$key] = array("columns" => $val["columns"], "rows" => $val["rows"]); - } - - $str .= pre_r($arr, true); - - if ( php_sapi_name() == "cli" ) { - $str = strip_tags(str_replace(array("
","",""), - array("\n",chr(27)."[01;33m", chr(27)."[0m"), - $str)); - } - - return $str; - } -} diff --git a/application/helpers/dompdf/include/cpdf_adapter.cls.php b/application/helpers/dompdf/include/cpdf_adapter.cls.php deleted file mode 100755 index 06947b505..000000000 --- a/application/helpers/dompdf/include/cpdf_adapter.cls.php +++ /dev/null @@ -1,877 +0,0 @@ - - * @author Orion Richardson - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -// FIXME: Need to sanity check inputs to this class -require_once(DOMPDF_LIB_DIR . "/class.pdf.php"); - -/** - * PDF rendering interface - * - * CPDF_Adapter provides a simple stateless interface to the stateful one - * provided by the Cpdf class. - * - * Unless otherwise mentioned, all dimensions are in points (1/72 in). The - * coordinate origin is in the top left corner, and y values increase - * downwards. - * - * See {@link http://www.ros.co.nz/pdf/} for more complete documentation - * on the underlying {@link Cpdf} class. - * - * @package dompdf - */ -class CPDF_Adapter implements Canvas { - - /** - * Dimensions of paper sizes in points - * - * @var array; - */ - static $PAPER_SIZES = array( - "4a0" => array(0,0,4767.87,6740.79), - "2a0" => array(0,0,3370.39,4767.87), - "a0" => array(0,0,2383.94,3370.39), - "a1" => array(0,0,1683.78,2383.94), - "a2" => array(0,0,1190.55,1683.78), - "a3" => array(0,0,841.89,1190.55), - "a4" => array(0,0,595.28,841.89), - "a5" => array(0,0,419.53,595.28), - "a6" => array(0,0,297.64,419.53), - "a7" => array(0,0,209.76,297.64), - "a8" => array(0,0,147.40,209.76), - "a9" => array(0,0,104.88,147.40), - "a10" => array(0,0,73.70,104.88), - "b0" => array(0,0,2834.65,4008.19), - "b1" => array(0,0,2004.09,2834.65), - "b2" => array(0,0,1417.32,2004.09), - "b3" => array(0,0,1000.63,1417.32), - "b4" => array(0,0,708.66,1000.63), - "b5" => array(0,0,498.90,708.66), - "b6" => array(0,0,354.33,498.90), - "b7" => array(0,0,249.45,354.33), - "b8" => array(0,0,175.75,249.45), - "b9" => array(0,0,124.72,175.75), - "b10" => array(0,0,87.87,124.72), - "c0" => array(0,0,2599.37,3676.54), - "c1" => array(0,0,1836.85,2599.37), - "c2" => array(0,0,1298.27,1836.85), - "c3" => array(0,0,918.43,1298.27), - "c4" => array(0,0,649.13,918.43), - "c5" => array(0,0,459.21,649.13), - "c6" => array(0,0,323.15,459.21), - "c7" => array(0,0,229.61,323.15), - "c8" => array(0,0,161.57,229.61), - "c9" => array(0,0,113.39,161.57), - "c10" => array(0,0,79.37,113.39), - "ra0" => array(0,0,2437.80,3458.27), - "ra1" => array(0,0,1729.13,2437.80), - "ra2" => array(0,0,1218.90,1729.13), - "ra3" => array(0,0,864.57,1218.90), - "ra4" => array(0,0,609.45,864.57), - "sra0" => array(0,0,2551.18,3628.35), - "sra1" => array(0,0,1814.17,2551.18), - "sra2" => array(0,0,1275.59,1814.17), - "sra3" => array(0,0,907.09,1275.59), - "sra4" => array(0,0,637.80,907.09), - "letter" => array(0,0,612.00,792.00), - "legal" => array(0,0,612.00,1008.00), - "ledger" => array(0,0,1224.00, 792.00), - "tabloid" => array(0,0,792.00, 1224.00), - "executive" => array(0,0,521.86,756.00), - "folio" => array(0,0,612.00,936.00), - "commercial #10 envelope" => array(0,0,684,297), - "catalog #10 1/2 envelope" => array(0,0,648,864), - "8.5x11" => array(0,0,612.00,792.00), - "8.5x14" => array(0,0,612.00,1008.0), - "11x17" => array(0,0,792.00, 1224.00), - ); - - /** - * The DOMPDF object - * - * @var DOMPDF - */ - private $_dompdf; - - /** - * Instance of Cpdf class - * - * @var Cpdf - */ - private $_pdf; - - /** - * PDF width, in points - * - * @var float - */ - private $_width; - - /** - * PDF height, in points - * - * @var float; - */ - private $_height; - - /** - * Current page number - * - * @var int - */ - private $_page_number; - - /** - * Total number of pages - * - * @var int - */ - private $_page_count; - - /** - * Text to display on every page - * - * @var array - */ - private $_page_text; - - /** - * Array of pages for accesing after rendering is initially complete - * - * @var array - */ - private $_pages; - - /** - * Array of temporary cached images to be deleted when processing is complete - * - * @var array - */ - private $_image_cache; - - /** - * Class constructor - * - * @param mixed $paper The size of paper to use in this PDF ({@link CPDF_Adapter::$PAPER_SIZES}) - * @param string $orientation The orientation of the document (either 'landscape' or 'portrait') - * @param DOMPDF $dompdf The DOMPDF instance - */ - function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf) { - if ( is_array($paper) ) { - $size = $paper; - } - else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) ) { - $size = self::$PAPER_SIZES[mb_strtolower($paper)]; - } - else { - $size = self::$PAPER_SIZES["letter"]; - } - - if ( mb_strtolower($orientation) === "landscape" ) { - list($size[2], $size[3]) = array($size[3], $size[2]); - } - - $this->_dompdf = $dompdf; - - $this->_pdf = new Cpdf( - $size, - $dompdf->get_option("enable_unicode"), - $dompdf->get_option("font_cache"), - $dompdf->get_option("temp_dir") - ); - - $this->_pdf->addInfo("Creator", "DOMPDF"); - $time = substr_replace(date('YmdHisO'), '\'', -2, 0).'\''; - $this->_pdf->addInfo("CreationDate", "D:$time"); - $this->_pdf->addInfo("ModDate", "D:$time"); - - $this->_width = $size[2] - $size[0]; - $this->_height= $size[3] - $size[1]; - - $this->_page_number = $this->_page_count = 1; - $this->_page_text = array(); - - $this->_pages = array($this->_pdf->getFirstPageId()); - - $this->_image_cache = array(); - } - - function get_dompdf(){ - return $this->_dompdf; - } - - /** - * Class destructor - * - * Deletes all temporary image files - */ - function __destruct() { - foreach ($this->_image_cache as $img) { - // The file might be already deleted by 3rd party tmp cleaner, - // the file might not have been created at all - // (if image outputting commands failed) - // or because the destructor was called twice accidentally. - if (!file_exists($img)) { - continue; - } - - if (DEBUGPNG) print '[__destruct unlink '.$img.']'; - if (!DEBUGKEEPTEMP) unlink($img); - } - } - - /** - * Returns the Cpdf instance - * - * @return Cpdf - */ - function get_cpdf() { - return $this->_pdf; - } - - /** - * Add meta information to the PDF - * - * @param string $label label of the value (Creator, Producer, etc.) - * @param string $value the text to set - */ - function add_info($label, $value) { - $this->_pdf->addInfo($label, $value); - } - - /** - * Opens a new 'object' - * - * While an object is open, all drawing actions are recored in the object, - * as opposed to being drawn on the current page. Objects can be added - * later to a specific page or to several pages. - * - * The return value is an integer ID for the new object. - * - * @see CPDF_Adapter::close_object() - * @see CPDF_Adapter::add_object() - * - * @return int - */ - function open_object() { - $ret = $this->_pdf->openObject(); - $this->_pdf->saveState(); - return $ret; - } - - /** - * Reopens an existing 'object' - * - * @see CPDF_Adapter::open_object() - * @param int $object the ID of a previously opened object - */ - function reopen_object($object) { - $this->_pdf->reopenObject($object); - $this->_pdf->saveState(); - } - - /** - * Closes the current 'object' - * - * @see CPDF_Adapter::open_object() - */ - function close_object() { - $this->_pdf->restoreState(); - $this->_pdf->closeObject(); - } - - /** - * Adds a specified 'object' to the document - * - * $object int specifying an object created with {@link - * CPDF_Adapter::open_object()}. $where can be one of: - * - 'add' add to current page only - * - 'all' add to every page from the current one onwards - * - 'odd' add to all odd numbered pages from now on - * - 'even' add to all even numbered pages from now on - * - 'next' add the object to the next page only - * - 'nextodd' add to all odd numbered pages from the next one - * - 'nexteven' add to all even numbered pages from the next one - * - * @see Cpdf::addObject() - * - * @param int $object - * @param string $where - */ - function add_object($object, $where = 'all') { - $this->_pdf->addObject($object, $where); - } - - /** - * Stops the specified 'object' from appearing in the document. - * - * The object will stop being displayed on the page following the current - * one. - * - * @param int $object - */ - function stop_object($object) { - $this->_pdf->stopObject($object); - } - - /** - * @access private - */ - function serialize_object($id) { - // Serialize the pdf object's current state for retrieval later - return $this->_pdf->serializeObject($id); - } - - /** - * @access private - */ - function reopen_serialized_object($obj) { - return $this->_pdf->restoreSerializedObject($obj); - } - - //........................................................................ - - /** - * Returns the PDF's width in points - * @return float - */ - function get_width() { return $this->_width; } - - /** - * Returns the PDF's height in points - * @return float - */ - function get_height() { return $this->_height; } - - /** - * Returns the current page number - * @return int - */ - function get_page_number() { return $this->_page_number; } - - /** - * Returns the total number of pages in the document - * @return int - */ - function get_page_count() { return $this->_page_count; } - - /** - * Sets the current page number - * - * @param int $num - */ - function set_page_number($num) { $this->_page_number = $num; } - - /** - * Sets the page count - * - * @param int $count - */ - function set_page_count($count) { $this->_page_count = $count; } - - /** - * Sets the stroke color - * - * See {@link Style::set_color()} for the format of the color array. - * @param array $color - */ - protected function _set_stroke_color($color) { - $this->_pdf->setStrokeColor($color); - } - - /** - * Sets the fill colour - * - * See {@link Style::set_color()} for the format of the colour array. - * @param array $color - */ - protected function _set_fill_color($color) { - $this->_pdf->setColor($color); - } - - /** - * Sets line transparency - * @see Cpdf::setLineTransparency() - * - * Valid blend modes are (case-sensitive): - * - * Normal, Multiply, Screen, Overlay, Darken, Lighten, - * ColorDodge, ColorBurn, HardLight, SoftLight, Difference, - * Exclusion - * - * @param string $mode the blending mode to use - * @param float $opacity 0.0 fully transparent, 1.0 fully opaque - */ - protected function _set_line_transparency($mode, $opacity) { - $this->_pdf->setLineTransparency($mode, $opacity); - } - - /** - * Sets fill transparency - * @see Cpdf::setFillTransparency() - * - * Valid blend modes are (case-sensitive): - * - * Normal, Multiply, Screen, Overlay, Darken, Lighten, - * ColorDogde, ColorBurn, HardLight, SoftLight, Difference, - * Exclusion - * - * @param string $mode the blending mode to use - * @param float $opacity 0.0 fully transparent, 1.0 fully opaque - */ - protected function _set_fill_transparency($mode, $opacity) { - $this->_pdf->setFillTransparency($mode, $opacity); - } - - /** - * Sets the line style - * - * @see Cpdf::setLineStyle() - * - * @param float $width - * @param string $cap - * @param string $join - * @param array $dash - */ - protected function _set_line_style($width, $cap, $join, $dash) { - $this->_pdf->setLineStyle($width, $cap, $join, $dash); - } - - /** - * Sets the opacity - * - * @param $opacity - * @param $mode - */ - function set_opacity($opacity, $mode = "Normal") { - $this->_set_line_transparency($mode, $opacity); - $this->_set_fill_transparency($mode, $opacity); - } - - function set_default_view($view, $options = array()) { - array_unshift($options, $view); - call_user_func_array(array($this->_pdf, "openHere"), $options); - } - - /** - * Remaps y coords from 4th to 1st quadrant - * - * @param float $y - * @return float - */ - protected function y($y) { - return $this->_height - $y; - } - - // Canvas implementation - function line($x1, $y1, $x2, $y2, $color, $width, $style = array()) { - $this->_set_stroke_color($color); - $this->_set_line_style($width, "butt", "", $style); - - $this->_pdf->line($x1, $this->y($y1), - $x2, $this->y($y2)); - } - - function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array()) { - $this->_set_stroke_color($color); - $this->_set_line_style($width, "butt", "", $style); - - $this->_pdf->ellipse($x, $this->y($y), $r1, $r2, 0, 8, $astart, $aend, false, false, true, false); - } - - //........................................................................ - - /** - * Convert a GIF or BMP image to a PNG image - * - * @param string $image_url - * @param integer $type - * - * @throws DOMPDF_Exception - * @return string The url of the newly converted image - */ - protected function _convert_gif_bmp_to_png($image_url, $type) { - $image_type = Image_Cache::type_to_ext($type); - $func_name = "imagecreatefrom$image_type"; - - if ( !function_exists($func_name) ) { - throw new DOMPDF_Exception("Function $func_name() not found. Cannot convert $image_type image: $image_url. Please install the image PHP extension."); - } - - set_error_handler("record_warnings"); - $im = $func_name($image_url); - - if ( $im ) { - imageinterlace($im, false); - - $tmp_dir = $this->_dompdf->get_option("temp_dir"); - $tmp_name = tempnam($tmp_dir, "{$image_type}dompdf_img_"); - @unlink($tmp_name); - $filename = "$tmp_name.png"; - $this->_image_cache[] = $filename; - - imagepng($im, $filename); - imagedestroy($im); - } - else { - $filename = Image_Cache::$broken_image; - } - - restore_error_handler(); - - return $filename; - } - - function rectangle($x1, $y1, $w, $h, $color, $width, $style = array()) { - $this->_set_stroke_color($color); - $this->_set_line_style($width, "butt", "", $style); - $this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h); - } - - function filled_rectangle($x1, $y1, $w, $h, $color) { - $this->_set_fill_color($color); - $this->_pdf->filledRectangle($x1, $this->y($y1) - $h, $w, $h); - } - - function clipping_rectangle($x1, $y1, $w, $h) { - $this->_pdf->clippingRectangle($x1, $this->y($y1) - $h, $w, $h); - } - - function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) { - $this->_pdf->clippingRectangleRounded($x1, $this->y($y1) - $h, $w, $h, $rTL, $rTR, $rBR, $rBL); - } - - function clipping_end() { - $this->_pdf->clippingEnd(); - } - - function save() { - $this->_pdf->saveState(); - } - - function restore() { - $this->_pdf->restoreState(); - } - - function rotate($angle, $x, $y) { - $this->_pdf->rotate($angle, $x, $y); - } - - function skew($angle_x, $angle_y, $x, $y) { - $this->_pdf->skew($angle_x, $angle_y, $x, $y); - } - - function scale($s_x, $s_y, $x, $y) { - $this->_pdf->scale($s_x, $s_y, $x, $y); - } - - function translate($t_x, $t_y) { - $this->_pdf->translate($t_x, $t_y); - } - - function transform($a, $b, $c, $d, $e, $f) { - $this->_pdf->transform(array($a, $b, $c, $d, $e, $f)); - } - - function polygon($points, $color, $width = null, $style = array(), $fill = false) { - $this->_set_fill_color($color); - $this->_set_stroke_color($color); - - // Adjust y values - for ( $i = 1; $i < count($points); $i += 2) { - $points[$i] = $this->y($points[$i]); - } - - $this->_pdf->polygon($points, count($points) / 2, $fill); - } - - function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false) { - $this->_set_fill_color($color); - $this->_set_stroke_color($color); - - if ( !$fill && isset($width) ) { - $this->_set_line_style($width, "round", "round", $style); - } - - $this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill); - } - - function image($img, $x, $y, $w, $h, $resolution = "normal") { - list($width, $height, $type) = dompdf_getimagesize($img); - - $debug_png = $this->_dompdf->get_option("debug_png"); - - if ($debug_png) print "[image:$img|$width|$height|$type]"; - - switch ($type) { - case IMAGETYPE_JPEG: - if ($debug_png) print '!!!jpg!!!'; - $this->_pdf->addJpegFromFile($img, $x, $this->y($y) - $h, $w, $h); - break; - - case IMAGETYPE_GIF: - case IMAGETYPE_BMP: - if ($debug_png) print '!!!bmp or gif!!!'; - // @todo use cache for BMP and GIF - $img = $this->_convert_gif_bmp_to_png($img, $type); - - case IMAGETYPE_PNG: - if ($debug_png) print '!!!png!!!'; - - $this->_pdf->addPngFromFile($img, $x, $this->y($y) - $h, $w, $h); - break; - - default: - if ($debug_png) print '!!!unknown!!!'; - } - } - - function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) { - $pdf = $this->_pdf; - - $pdf->setColor($color); - - $font .= ".afm"; - $pdf->selectFont($font); - - //Font_Metrics::get_font_height($font, $size) == - //$this->get_font_height($font, $size) == - //$this->_pdf->selectFont($font),$this->_pdf->getFontHeight($size) - //- FontBBoxheight+FontHeightOffset, scaled to $size, in pt - //$this->_pdf->getFontDescender($size) - //- Descender scaled to size - // - //$this->_pdf->fonts[$this->_pdf->currentFont] sizes: - //['FontBBox'][0] left, ['FontBBox'][1] bottom, ['FontBBox'][2] right, ['FontBBox'][3] top - //Maximum extent of all glyphs of the font from the baseline point - //['Ascender'] maximum height above baseline except accents - //['Descender'] maximum depth below baseline, negative number means below baseline - //['FontHeightOffset'] manual enhancement of .afm files to trim windows fonts. currently not used. - //Values are in 1/1000 pt for a font size of 1 pt - // - //['FontBBox'][1] should be close to ['Descender'] - //['FontBBox'][3] should be close to ['Ascender']+Accents - //in practice, FontBBox values are a little bigger - // - //The text position is referenced to the baseline, not to the lower corner of the FontBBox, - //for what the left,top corner is given. - //FontBBox spans also the background box for the text. - //If the lower corner would be used as reference point, the Descents of the glyphs would - //hang over the background box border. - //Therefore compensate only the extent above the Baseline. - // - //print '
['.$font.','.$size.','.$pdf->getFontHeight($size).','.$pdf->getFontDescender($size).','.$pdf->fonts[$pdf->currentFont]['FontBBox'][3].','.$pdf->fonts[$pdf->currentFont]['FontBBox'][1].','.$pdf->fonts[$pdf->currentFont]['FontHeightOffset'].','.$pdf->fonts[$pdf->currentFont]['Ascender'].','.$pdf->fonts[$pdf->currentFont]['Descender'].']
'; - // - //$pdf->addText($x, $this->y($y) - ($pdf->fonts[$pdf->currentFont]['FontBBox'][3]*$size)/1000, $size, $text, $angle, $word_space, $char_space); - $pdf->addText($x, $this->y($y) - $pdf->getFontHeight($size), $size, $text, $angle, $word_space, $char_space); - } - - //........................................................................ - - function javascript($code) { - $this->_pdf->addJavascript($code); - } - - //........................................................................ - - /** - * Add a named destination (similar to ... in html) - * - * @param string $anchorname The name of the named destination - */ - function add_named_dest($anchorname) { - $this->_pdf->addDestination($anchorname, "Fit"); - } - - //........................................................................ - - /** - * Add a link to the pdf - * - * @param string $url The url to link to - * @param float $x The x position of the link - * @param float $y The y position of the link - * @param float $width The width of the link - * @param float $height The height of the link - */ - function add_link($url, $x, $y, $width, $height) { - - $y = $this->y($y) - $height; - - if ( strpos($url, '#') === 0 ) { - // Local link - $name = substr($url,1); - if ( $name ) { - $this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height); - } - - } - else { - $this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height); - } - } - - function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0) { - $this->_pdf->selectFont($font); - - $unicode = $this->_dompdf->get_option("enable_unicode"); - if (!$unicode) { - $text = mb_convert_encoding($text, 'Windows-1252', 'UTF-8'); - } - - return $this->_pdf->getTextWidth($size, $text, $word_spacing, $char_spacing); - } - - function register_string_subset($font, $string) { - $this->_pdf->registerText($font, $string); - } - - function get_font_height($font, $size) { - $this->_pdf->selectFont($font); - - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $this->_pdf->getFontHeight($size) * $ratio; - } - - /*function get_font_x_height($font, $size) { - $this->_pdf->selectFont($font); - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $this->_pdf->getFontXHeight($size) * $ratio; - }*/ - - function get_font_baseline($font, $size) { - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $this->get_font_height($font, $size) / $ratio; - } - - /** - * Writes text at the specified x and y coordinates on every page - * - * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced - * with their current values. - * - * See {@link Style::munge_color()} for the format of the colour array. - * - * @param float $x - * @param float $y - * @param string $text the text to write - * @param string $font the font file to use - * @param float $size the font size, in points - * @param array $color - * @param float $word_space word spacing adjustment - * @param float $char_space char spacing adjustment - * @param float $angle angle to write the text at, measured CW starting from the x-axis - */ - function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) { - $_t = "text"; - $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle"); - } - - /** - * Processes a script on every page - * - * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available. - * - * This function can be used to add page numbers to all pages - * after the first one, for example. - * - * @param string $code the script code - * @param string $type the language type for script - */ - function page_script($code, $type = "text/php") { - $_t = "script"; - $this->_page_text[] = compact("_t", "code", "type"); - } - - function new_page() { - $this->_page_number++; - $this->_page_count++; - - $ret = $this->_pdf->newPage(); - $this->_pages[] = $ret; - return $ret; - } - - /** - * Add text to each page after rendering is complete - */ - protected function _add_page_text() { - - if ( !count($this->_page_text) ) { - return; - } - - $page_number = 1; - $eval = null; - - foreach ($this->_pages as $pid) { - $this->reopen_object($pid); - - foreach ($this->_page_text as $pt) { - extract($pt); - - switch ($_t) { - case "text": - $text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"), - array($page_number, $this->_page_count), $text); - $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle); - break; - - case "script": - if ( !$eval ) { - $eval = new PHP_Evaluator($this); - } - $eval->evaluate($code, array('PAGE_NUM' => $page_number, 'PAGE_COUNT' => $this->_page_count)); - break; - } - } - - $this->close_object(); - $page_number++; - } - } - - /** - * Streams the PDF directly to the browser - * - * @param string $filename the name of the PDF file - * @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0 - */ - function stream($filename, $options = null) { - // Add page text - $this->_add_page_text(); - - $options["Content-Disposition"] = $filename; - $this->_pdf->stream($options); - } - - /** - * Returns the PDF as a string - * - * @param array $options Output options - * @return string - */ - function output($options = null) { - $this->_add_page_text(); - - $debug = isset($options["compress"]) && $options["compress"] != 1; - - return $this->_pdf->output($debug); - } - - /** - * Returns logging messages generated by the Cpdf class - * - * @return string - */ - function get_messages() { - return $this->_pdf->messages; - } -} diff --git a/application/helpers/dompdf/include/css_color.cls.php b/application/helpers/dompdf/include/css_color.cls.php deleted file mode 100755 index 481751db5..000000000 --- a/application/helpers/dompdf/include/css_color.cls.php +++ /dev/null @@ -1,287 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -class CSS_Color { - static $cssColorNames = array( - "aliceblue" => "F0F8FF", - "antiquewhite" => "FAEBD7", - "aqua" => "00FFFF", - "aquamarine" => "7FFFD4", - "azure" => "F0FFFF", - "beige" => "F5F5DC", - "bisque" => "FFE4C4", - "black" => "000000", - "blanchedalmond" => "FFEBCD", - "blue" => "0000FF", - "blueviolet" => "8A2BE2", - "brown" => "A52A2A", - "burlywood" => "DEB887", - "cadetblue" => "5F9EA0", - "chartreuse" => "7FFF00", - "chocolate" => "D2691E", - "coral" => "FF7F50", - "cornflowerblue" => "6495ED", - "cornsilk" => "FFF8DC", - "crimson" => "DC143C", - "cyan" => "00FFFF", - "darkblue" => "00008B", - "darkcyan" => "008B8B", - "darkgoldenrod" => "B8860B", - "darkgray" => "A9A9A9", - "darkgreen" => "006400", - "darkgrey" => "A9A9A9", - "darkkhaki" => "BDB76B", - "darkmagenta" => "8B008B", - "darkolivegreen" => "556B2F", - "darkorange" => "FF8C00", - "darkorchid" => "9932CC", - "darkred" => "8B0000", - "darksalmon" => "E9967A", - "darkseagreen" => "8FBC8F", - "darkslateblue" => "483D8B", - "darkslategray" => "2F4F4F", - "darkslategrey" => "2F4F4F", - "darkturquoise" => "00CED1", - "darkviolet" => "9400D3", - "deeppink" => "FF1493", - "deepskyblue" => "00BFFF", - "dimgray" => "696969", - "dimgrey" => "696969", - "dodgerblue" => "1E90FF", - "firebrick" => "B22222", - "floralwhite" => "FFFAF0", - "forestgreen" => "228B22", - "fuchsia" => "FF00FF", - "gainsboro" => "DCDCDC", - "ghostwhite" => "F8F8FF", - "gold" => "FFD700", - "goldenrod" => "DAA520", - "gray" => "808080", - "green" => "008000", - "greenyellow" => "ADFF2F", - "grey" => "808080", - "honeydew" => "F0FFF0", - "hotpink" => "FF69B4", - "indianred" => "CD5C5C", - "indigo" => "4B0082", - "ivory" => "FFFFF0", - "khaki" => "F0E68C", - "lavender" => "E6E6FA", - "lavenderblush" => "FFF0F5", - "lawngreen" => "7CFC00", - "lemonchiffon" => "FFFACD", - "lightblue" => "ADD8E6", - "lightcoral" => "F08080", - "lightcyan" => "E0FFFF", - "lightgoldenrodyellow" => "FAFAD2", - "lightgray" => "D3D3D3", - "lightgreen" => "90EE90", - "lightgrey" => "D3D3D3", - "lightpink" => "FFB6C1", - "lightsalmon" => "FFA07A", - "lightseagreen" => "20B2AA", - "lightskyblue" => "87CEFA", - "lightslategray" => "778899", - "lightslategrey" => "778899", - "lightsteelblue" => "B0C4DE", - "lightyellow" => "FFFFE0", - "lime" => "00FF00", - "limegreen" => "32CD32", - "linen" => "FAF0E6", - "magenta" => "FF00FF", - "maroon" => "800000", - "mediumaquamarine" => "66CDAA", - "mediumblue" => "0000CD", - "mediumorchid" => "BA55D3", - "mediumpurple" => "9370DB", - "mediumseagreen" => "3CB371", - "mediumslateblue" => "7B68EE", - "mediumspringgreen" => "00FA9A", - "mediumturquoise" => "48D1CC", - "mediumvioletred" => "C71585", - "midnightblue" => "191970", - "mintcream" => "F5FFFA", - "mistyrose" => "FFE4E1", - "moccasin" => "FFE4B5", - "navajowhite" => "FFDEAD", - "navy" => "000080", - "oldlace" => "FDF5E6", - "olive" => "808000", - "olivedrab" => "6B8E23", - "orange" => "FFA500", - "orangered" => "FF4500", - "orchid" => "DA70D6", - "palegoldenrod" => "EEE8AA", - "palegreen" => "98FB98", - "paleturquoise" => "AFEEEE", - "palevioletred" => "DB7093", - "papayawhip" => "FFEFD5", - "peachpuff" => "FFDAB9", - "peru" => "CD853F", - "pink" => "FFC0CB", - "plum" => "DDA0DD", - "powderblue" => "B0E0E6", - "purple" => "800080", - "red" => "FF0000", - "rosybrown" => "BC8F8F", - "royalblue" => "4169E1", - "saddlebrown" => "8B4513", - "salmon" => "FA8072", - "sandybrown" => "F4A460", - "seagreen" => "2E8B57", - "seashell" => "FFF5EE", - "sienna" => "A0522D", - "silver" => "C0C0C0", - "skyblue" => "87CEEB", - "slateblue" => "6A5ACD", - "slategray" => "708090", - "slategrey" => "708090", - "snow" => "FFFAFA", - "springgreen" => "00FF7F", - "steelblue" => "4682B4", - "tan" => "D2B48C", - "teal" => "008080", - "thistle" => "D8BFD8", - "tomato" => "FF6347", - "turquoise" => "40E0D0", - "violet" => "EE82EE", - "wheat" => "F5DEB3", - "white" => "FFFFFF", - "whitesmoke" => "F5F5F5", - "yellow" => "FFFF00", - "yellowgreen" => "9ACD32", - ); - - static function parse($color) { - if ( is_array($color) ) { - // Assume the array has the right format... - // FIXME: should/could verify this. - return $color; - } - - static $cache = array(); - - $color = strtolower($color); - - if ( isset($cache[$color]) ) { - return $cache[$color]; - } - - if ( in_array($color, array("transparent", "inherit")) ) { - return $cache[$color] = $color; - } - - if ( isset(self::$cssColorNames[$color]) ) { - return $cache[$color] = self::getArray(self::$cssColorNames[$color]); - } - - $length = mb_strlen($color); - - // #rgb format - if ( $length == 4 && $color[0] === "#" ) { - return $cache[$color] = self::getArray($color[1].$color[1].$color[2].$color[2].$color[3].$color[3]); - } - - // #rrggbb format - else if ( $length == 7 && $color[0] === "#" ) { - return $cache[$color] = self::getArray(mb_substr($color, 1, 6)); - } - - // rgb( r,g,b ) / rgbaa( r,g,b,α ) format - else if ( mb_strpos($color, "rgb") !== false ) { - $i = mb_strpos($color, "("); - $j = mb_strpos($color, ")"); - - // Bad color value - if ( $i === false || $j === false ) { - return null; - } - - $triplet = explode(",", mb_substr($color, $i+1, $j-$i-1)); - - // alpha transparency - // FIXME: not currently using transparency - $alpha = 1; - if ( count( $triplet ) == 4 ) { - $alpha = (float) ( trim( array_pop( $triplet ) ) ); - // bad value, set to fully opaque - if ( $alpha > 1 || $alpha < 0 ) { - $alpha = 1; - } - } - - if ( count($triplet) != 3 ) { - return null; - } - - foreach (array_keys($triplet) as $c) { - $triplet[$c] = trim($triplet[$c]); - - if ( $triplet[$c][mb_strlen($triplet[$c]) - 1] === "%" ) { - $triplet[$c] = round($triplet[$c] * 2.55); - } - } - - return $cache[$color] = self::getArray(vsprintf("%02X%02X%02X", $triplet)); - - } - - // cmyk( c,m,y,k ) format - // http://www.w3.org/TR/css3-gcpm/#cmyk-colors - else if ( mb_strpos($color, "cmyk") !== false ) { - $i = mb_strpos($color, "("); - $j = mb_strpos($color, ")"); - - // Bad color value - if ( $i === false || $j === false ) { - return null; - } - - $values = explode(",", mb_substr($color, $i+1, $j-$i-1)); - - if ( count($values) != 4 ) { - return null; - } - - foreach ($values as &$c) { - $c = floatval(trim($c)); - if ($c > 1.0) $c = 1.0; - if ($c < 0.0) $c = 0.0; - } - - return $cache[$color] = self::getArray($values); - } - - return null; - } - - static function getArray($color) { - $c = array(null, null, null, null, "hex" => null); - - if (is_array($color)) { - $c = $color; - $c["c"] = $c[0]; - $c["m"] = $c[1]; - $c["y"] = $c[2]; - $c["k"] = $c[3]; - $c["hex"] = "cmyk($c[0],$c[1],$c[2],$c[3])"; - } - else { - $c[0] = hexdec(mb_substr($color, 0, 2)) / 0xff; - $c[1] = hexdec(mb_substr($color, 2, 2)) / 0xff; - $c[2] = hexdec(mb_substr($color, 4, 2)) / 0xff; - $c["r"] = $c[0]; - $c["g"] = $c[1]; - $c["b"] = $c[2]; - $c["hex"] = "#$color"; - } - - return $c; - } -} diff --git a/application/helpers/dompdf/include/dompdf.cls.php b/application/helpers/dompdf/include/dompdf.cls.php deleted file mode 100755 index 1be1f8284..000000000 --- a/application/helpers/dompdf/include/dompdf.cls.php +++ /dev/null @@ -1,1077 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * DOMPDF - PHP5 HTML to PDF renderer - * - * DOMPDF loads HTML and does its best to render it as a PDF. It gets its - * name from the new DomDocument PHP5 extension. Source HTML is first - * parsed by a DomDocument object. DOMPDF takes the resulting DOM tree and - * attaches a {@link Frame} object to each node. {@link Frame} objects store - * positioning and layout information and each has a reference to a {@link - * Style} object. - * - * Style information is loaded and parsed (see {@link Stylesheet}) and is - * applied to the frames in the tree by using XPath. CSS selectors are - * converted into XPath queries, and the computed {@link Style} objects are - * applied to the {@link Frame}s. - * - * {@link Frame}s are then decorated (in the design pattern sense of the - * word) based on their CSS display property ({@link - * http://www.w3.org/TR/CSS21/visuren.html#propdef-display}). - * Frame_Decorators augment the basic {@link Frame} class by adding - * additional properties and methods specific to the particular type of - * {@link Frame}. For example, in the CSS layout model, block frames - * (display: block;) contain line boxes that are usually filled with text or - * other inline frames. The Block_Frame_Decorator therefore adds a $lines - * property as well as methods to add {@link Frame}s to lines and to add - * additional lines. {@link Frame}s also are attached to specific - * Positioner and {@link Frame_Reflower} objects that contain the - * positioining and layout algorithm for a specific type of frame, - * respectively. This is an application of the Strategy pattern. - * - * Layout, or reflow, proceeds recursively (post-order) starting at the root - * of the document. Space constraints (containing block width & height) are - * pushed down, and resolved positions and sizes bubble up. Thus, every - * {@link Frame} in the document tree is traversed once (except for tables - * which use a two-pass layout algorithm). If you are interested in the - * details, see the reflow() method of the Reflower classes. - * - * Rendering is relatively straightforward once layout is complete. {@link - * Frame}s are rendered using an adapted {@link Cpdf} class, originally - * written by Wayne Munro, http://www.ros.co.nz/pdf/. (Some performance - * related changes have been made to the original {@link Cpdf} class, and - * the {@link CPDF_Adapter} class provides a simple, stateless interface to - * PDF generation.) PDFLib support has now also been added, via the {@link - * PDFLib_Adapter}. - * - * - * @package dompdf - */ -class DOMPDF { - - /** - * DomDocument representing the HTML document - * - * @var DOMDocument - */ - protected $_xml; - - /** - * Frame_Tree derived from the DOM tree - * - * @var Frame_Tree - */ - protected $_tree; - - /** - * Stylesheet for the document - * - * @var Stylesheet - */ - protected $_css; - - /** - * Actual PDF renderer - * - * @var Canvas - */ - protected $_pdf; - - /** - * Desired paper size ('letter', 'legal', 'A4', etc.) - * - * @var string - */ - protected $_paper_size; - - /** - * Paper orientation ('portrait' or 'landscape') - * - * @var string - */ - protected $_paper_orientation; - - /** - * Callbacks on new page and new element - * - * @var array - */ - protected $_callbacks; - - /** - * Experimental caching capability - * - * @var string - */ - private $_cache_id; - - /** - * Base hostname - * - * Used for relative paths/urls - * @var string - */ - protected $_base_host; - - /** - * Absolute base path - * - * Used for relative paths/urls - * @var string - */ - protected $_base_path; - - /** - * Protcol used to request file (file://, http://, etc) - * - * @var string - */ - protected $_protocol; - - /** - * HTTP context created with stream_context_create() - * Will be used for file_get_contents - * - * @var resource - */ - protected $_http_context; - - /** - * Timestamp of the script start time - * - * @var int - */ - private $_start_time = null; - - /** - * The system's locale - * - * @var string - */ - private $_system_locale = null; - - /** - * Tells if the system's locale is the C standard one - * - * @var bool - */ - private $_locale_standard = false; - - /** - * The default view of the PDF in the viewer - * - * @var string - */ - private $_default_view = "Fit"; - - /** - * The default view options of the PDF in the viewer - * - * @var array - */ - private $_default_view_options = array(); - - /** - * Tells wether the DOM document is in quirksmode (experimental) - * - * @var bool - */ - private $_quirksmode = false; - - /** - * The list of built-in fonts - * - * @var array - */ - public static $native_fonts = array( - "courier", "courier-bold", "courier-oblique", "courier-boldoblique", - "helvetica", "helvetica-bold", "helvetica-oblique", "helvetica-boldoblique", - "times-roman", "times-bold", "times-italic", "times-bolditalic", - "symbol", "zapfdinbats" - ); - - private $_options = array( - // Directories - "temp_dir" => DOMPDF_TEMP_DIR, - "font_dir" => DOMPDF_FONT_DIR, - "font_cache" => DOMPDF_FONT_CACHE, - "chroot" => DOMPDF_CHROOT, - "log_output_file" => DOMPDF_LOG_OUTPUT_FILE, - - // Rendering - "default_media_type" => DOMPDF_DEFAULT_MEDIA_TYPE, - "default_paper_size" => DOMPDF_DEFAULT_PAPER_SIZE, - "default_font" => DOMPDF_DEFAULT_FONT, - "dpi" => DOMPDF_DPI, - "font_height_ratio" => DOMPDF_FONT_HEIGHT_RATIO, - - // Features - "enable_unicode" => DOMPDF_UNICODE_ENABLED, - "enable_php" => DOMPDF_ENABLE_PHP, - "enable_remote" => DOMPDF_ENABLE_REMOTE, - "enable_css_float" => DOMPDF_ENABLE_CSS_FLOAT, - "enable_javascript" => DOMPDF_ENABLE_JAVASCRIPT, - "enable_html5_parser" => DOMPDF_ENABLE_HTML5PARSER, - "enable_font_subsetting" => DOMPDF_ENABLE_FONTSUBSETTING, - - // Debug - "debug_png" => DEBUGPNG, - "debug_keep_temp" => DEBUGKEEPTEMP, - "debug_css" => DEBUGCSS, - "debug_layout" => DEBUG_LAYOUT, - "debug_layout_lines" => DEBUG_LAYOUT_LINES, - "debug_layout_blocks" => DEBUG_LAYOUT_BLOCKS, - "debug_layout_inline" => DEBUG_LAYOUT_INLINE, - "debug_layout_padding_box" => DEBUG_LAYOUT_PADDINGBOX, - - // Admin - "admin_username" => DOMPDF_ADMIN_USERNAME, - "admin_password" => DOMPDF_ADMIN_PASSWORD, - ); - - /** - * Class constructor - */ - function __construct() { - $this->_locale_standard = sprintf('%.1f', 1.0) == '1.0'; - - $this->save_locale(); - - $this->_messages = array(); - $this->_css = new Stylesheet($this); - $this->_pdf = null; - $this->_paper_size = DOMPDF_DEFAULT_PAPER_SIZE; - $this->_paper_orientation = "portrait"; - $this->_base_protocol = ""; - $this->_base_host = ""; - $this->_base_path = ""; - $this->_http_context = null; - $this->_callbacks = array(); - $this->_cache_id = null; - - $this->restore_locale(); - } - - /** - * Class destructor - */ - function __destruct() { - clear_object($this); - } - - /** - * Get the dompdf option value - * - * @param string $key - * - * @return mixed - * @throws DOMPDF_Exception - */ - function get_option($key) { - if ( !array_key_exists($key, $this->_options) ) { - throw new DOMPDF_Exception("Option '$key' doesn't exist"); - } - - return $this->_options[$key]; - } - - /** - * @param string $key - * @param mixed $value - * - * @throws DOMPDF_Exception - */ - function set_option($key, $value) { - if ( !array_key_exists($key, $this->_options) ) { - throw new DOMPDF_Exception("Option '$key' doesn't exist"); - } - - $this->_options[$key] = $value; - } - - /** - * @param array $options - */ - function set_options(array $options) { - foreach ($options as $key => $value) { - $this->set_option($key, $value); - } - } - - /** - * Save the system's locale configuration and - * set the right value for numeric formatting - */ - private function save_locale() { - if ( $this->_locale_standard ) { - return; - } - - $this->_system_locale = setlocale(LC_NUMERIC, "0"); - setlocale(LC_NUMERIC, "C"); - } - - /** - * Restore the system's locale configuration - */ - private function restore_locale() { - if ( $this->_locale_standard ) { - return; - } - - setlocale(LC_NUMERIC, $this->_system_locale); - } - - /** - * Returns the underlying {@link Frame_Tree} object - * - * @return Frame_Tree - */ - function get_tree() { - return $this->_tree; - } - - /** - * Sets the protocol to use - * FIXME validate these - * - * @param string $proto - */ - function set_protocol($proto) { - $this->_protocol = $proto; - } - - /** - * Sets the base hostname - * - * @param string $host - */ - function set_host($host) { - $this->_base_host = $host; - } - - /** - * Sets the base path - * - * @param string $path - */ - function set_base_path($path) { - $this->_base_path = $path; - } - - /** - * Sets the HTTP context - * - * @param resource $http_context - */ - function set_http_context($http_context) { - $this->_http_context = $http_context; - } - - /** - * Sets the default view - * - * @param string $default_view The default document view - * @param array $options The view's options - */ - function set_default_view($default_view, $options) { - $this->_default_view = $default_view; - $this->_default_view_options = $options; - } - - /** - * Returns the protocol in use - * - * @return string - */ - function get_protocol() { - return $this->_protocol; - } - - /** - * Returns the base hostname - * - * @return string - */ - function get_host() { - return $this->_base_host; - } - - /** - * Returns the base path - * - * @return string - */ - function get_base_path() { - return $this->_base_path; - } - - /** - * Returns the HTTP context - * - * @return resource - */ - function get_http_context() { - return $this->_http_context; - } - - /** - * Return the underlying Canvas instance (e.g. CPDF_Adapter, GD_Adapter) - * - * @return Canvas - */ - function get_canvas() { - return $this->_pdf; - } - - /** - * Returns the callbacks array - * - * @return array - */ - function get_callbacks() { - return $this->_callbacks; - } - - /** - * Returns the stylesheet - * - * @return Stylesheet - */ - function get_css() { - return $this->_css; - } - - /** - * @return DOMDocument - */ - function get_dom() { - return $this->_xml; - } - - /** - * Loads an HTML file - * Parse errors are stored in the global array _dompdf_warnings. - * - * @param string $file a filename or url to load - * - * @throws DOMPDF_Exception - */ - function load_html_file($file) { - $this->save_locale(); - - // Store parsing warnings as messages (this is to prevent output to the - // browser if the html is ugly and the dom extension complains, - // preventing the pdf from being streamed.) - if ( !$this->_protocol && !$this->_base_host && !$this->_base_path ) { - list($this->_protocol, $this->_base_host, $this->_base_path) = explode_url($file); - } - - if ( !$this->get_option("enable_remote") && ($this->_protocol != "" && $this->_protocol !== "file://" ) ) { - throw new DOMPDF_Exception("Remote file requested, but DOMPDF_ENABLE_REMOTE is false."); - } - - if ($this->_protocol == "" || $this->_protocol === "file://") { - - // Get the full path to $file, returns false if the file doesn't exist - $realfile = realpath($file); - if ( !$realfile ) { - throw new DOMPDF_Exception("File '$file' not found."); - } - - $chroot = $this->get_option("chroot"); - if ( strpos($realfile, $chroot) !== 0 ) { - throw new DOMPDF_Exception("Permission denied on $file. The file could not be found under the directory specified by DOMPDF_CHROOT."); - } - - // Exclude dot files (e.g. .htaccess) - if ( substr(basename($realfile), 0, 1) === "." ) { - throw new DOMPDF_Exception("Permission denied on $file."); - } - - $file = $realfile; - } - - $contents = file_get_contents($file, null, $this->_http_context); - $encoding = null; - - // See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/ - if ( isset($http_response_header) ) { - foreach($http_response_header as $_header) { - if ( preg_match("@Content-Type:\s*[\w/]+;\s*?charset=([^\s]+)@i", $_header, $matches) ) { - $encoding = strtoupper($matches[1]); - break; - } - } - } - - $this->restore_locale(); - - $this->load_html($contents, $encoding); - } - - /** - * Loads an HTML string - * Parse errors are stored in the global array _dompdf_warnings. - * @todo use the $encoding variable - * - * @param string $str HTML text to load - * @param string $encoding Not used yet - */ - function load_html($str, $encoding = null) { - $this->save_locale(); - - // FIXME: Determine character encoding, switch to UTF8, update meta tag. Need better http/file stream encoding detection, currently relies on text or meta tag. - mb_detect_order('auto'); - - if (mb_detect_encoding($str) !== 'UTF-8') { - $metatags = array( - '@]*charset\s*=\s*["\']?\s*([^"\' ]+)@i', - ); - - foreach($metatags as $metatag) { - if (preg_match($metatag, $str, $matches)) break; - } - - if (mb_detect_encoding($str) == '') { - if (isset($matches[1])) { - $encoding = strtoupper($matches[1]); - } - else { - $encoding = 'UTF-8'; - } - } - else { - if ( isset($matches[1]) ) { - $encoding = strtoupper($matches[1]); - } - else { - $encoding = 'auto'; - } - } - - if ( $encoding !== 'UTF-8' ) { - $str = mb_convert_encoding($str, 'UTF-8', $encoding); - } - - if ( isset($matches[1]) ) { - $str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str); - } - else { - $str = str_replace('', '', $str); - } - } - else { - $encoding = 'UTF-8'; - } - - // remove BOM mark from UTF-8, it's treated as document text by DOMDocument - // FIXME: roll this into the encoding detection using UTF-8/16/32 BOM (http://us2.php.net/manual/en/function.mb-detect-encoding.php#91051)? - if ( substr($str, 0, 3) == chr(0xEF).chr(0xBB).chr(0xBF) ) { - $str = substr($str, 3); - } - - // if the document contains non utf-8 with a utf-8 meta tag chars and was - // detected as utf-8 by mbstring, problems could happen. - // http://devzone.zend.com/article/8855 - if ( $encoding !== 'UTF-8' ) { - $re = '/]*)((?:charset=[^"\' ]+)([^>]*)|(?:charset=["\'][^"\' ]+["\']))([^>]*)>/i'; - $str = preg_replace($re, '', $str); - } - - // Store parsing warnings as messages - set_error_handler("record_warnings"); - - // @todo Take the quirksmode into account - // http://hsivonen.iki.fi/doctype/ - // https://developer.mozilla.org/en/mozilla's_quirks_mode - $quirksmode = false; - - if ( $this->get_option("enable_html5_parser") ) { - $tokenizer = new HTML5_Tokenizer($str); - $tokenizer->parse(); - $doc = $tokenizer->save(); - - // Remove #text children nodes in nodes that shouldn't have - $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr"); - foreach($tag_names as $tag_name) { - $nodes = $doc->getElementsByTagName($tag_name); - - foreach($nodes as $node) { - self::remove_text_nodes($node); - } - } - - $quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS); - } - else { - // loadHTML assumes ISO-8859-1 unless otherwise specified, but there are - // bugs in how DOMDocument determines the actual encoding. Converting to - // HTML-ENTITIES prior to import appears to resolve the issue. - // http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/ (see #4) - // http://stackoverflow.com/a/11310258/264628 - $doc = new DOMDocument(); - $doc->preserveWhiteSpace = true; - $doc->loadHTML( mb_convert_encoding( $str , 'HTML-ENTITIES' , 'UTF-8' ) ); - - // If some text is before the doctype, we are in quirksmode - if ( preg_match("/^(.+) - if ( !$doc->doctype->publicId && !$doc->doctype->systemId ) { - $quirksmode = false; - } - - // not XHTML - if ( !preg_match("/xhtml/i", $doc->doctype->publicId) ) { - $quirksmode = true; - } - } - } - - $this->_xml = $doc; - $this->_quirksmode = $quirksmode; - - $this->_tree = new Frame_Tree($this->_xml); - - restore_error_handler(); - - $this->restore_locale(); - } - - static function remove_text_nodes(DOMNode $node) { - $children = array(); - for ($i = 0; $i < $node->childNodes->length; $i++) { - $child = $node->childNodes->item($i); - if ( $child->nodeName === "#text" ) { - $children[] = $child; - } - } - - foreach($children as $child) { - $node->removeChild($child); - } - } - - /** - * Builds the {@link Frame_Tree}, loads any CSS and applies the styles to - * the {@link Frame_Tree} - */ - protected function _process_html() { - $this->_tree->build_tree(); - - $this->_css->load_css_file(Stylesheet::DEFAULT_STYLESHEET, Stylesheet::ORIG_UA); - - $acceptedmedia = Stylesheet::$ACCEPTED_GENERIC_MEDIA_TYPES; - $acceptedmedia[] = $this->get_option("default_media_type"); - - // - $base_nodes = $this->_xml->getElementsByTagName("base"); - if ( $base_nodes->length && ($href = $base_nodes->item(0)->getAttribute("href")) ) { - list($this->_protocol, $this->_base_host, $this->_base_path) = explode_url($href); - } - - // Set the base path of the Stylesheet to that of the file being processed - $this->_css->set_protocol($this->_protocol); - $this->_css->set_host($this->_base_host); - $this->_css->set_base_path($this->_base_path); - - // Get all the stylesheets so that they are processed in document order - $xpath = new DOMXPath($this->_xml); - $stylesheets = $xpath->query("//*[name() = 'link' or name() = 'style']"); - - foreach($stylesheets as $tag) { - switch (strtolower($tag->nodeName)) { - // load tags - case "link": - if ( mb_strtolower(stripos($tag->getAttribute("rel"), "stylesheet") !== false) || // may be "appendix stylesheet" - mb_strtolower($tag->getAttribute("type")) === "text/css" ) { - //Check if the css file is for an accepted media type - //media not given then always valid - $formedialist = preg_split("/[\s\n,]/", $tag->getAttribute("media"),-1, PREG_SPLIT_NO_EMPTY); - if ( count($formedialist) > 0 ) { - $accept = false; - foreach ( $formedialist as $type ) { - if ( in_array(mb_strtolower(trim($type)), $acceptedmedia) ) { - $accept = true; - break; - } - } - - if (!$accept) { - //found at least one mediatype, but none of the accepted ones - //Skip this css file. - continue; - } - } - - $url = $tag->getAttribute("href"); - $url = build_url($this->_protocol, $this->_base_host, $this->_base_path, $url); - - $this->_css->load_css_file($url, Stylesheet::ORIG_AUTHOR); - } - break; - - // load - $child = $child->nextSibling; - } - } - else { - $css = $tag->nodeValue; - } - - $this->_css->load_css($css); - break; - } - } - } - - /** - * Sets the paper size & orientation - * - * @param string $size 'letter', 'legal', 'A4', etc. {@link CPDF_Adapter::$PAPER_SIZES} - * @param string $orientation 'portrait' or 'landscape' - */ - function set_paper($size, $orientation = "portrait") { - $this->_paper_size = $size; - $this->_paper_orientation = $orientation; - } - - /** - * Enable experimental caching capability - * @access private - */ - function enable_caching($cache_id) { - $this->_cache_id = $cache_id; - } - - /** - * Sets callbacks for events like rendering of pages and elements. - * The callbacks array contains arrays with 'event' set to 'begin_page', - * 'end_page', 'begin_frame', or 'end_frame' and 'f' set to a function or - * object plus method to be called. - * - * The function 'f' must take an array as argument, which contains info - * about the event. - * - * @param array $callbacks the set of callbacks to set - */ - function set_callbacks($callbacks) { - if (is_array($callbacks)) { - $this->_callbacks = array(); - foreach ($callbacks as $c) { - if (is_array($c) && isset($c['event']) && isset($c['f'])) { - $event = $c['event']; - $f = $c['f']; - if (is_callable($f) && is_string($event)) { - $this->_callbacks[$event][] = $f; - } - } - } - } - } - - /** - * Get the quirks mode - * - * @return boolean true if quirks mode is active - */ - function get_quirksmode(){ - return $this->_quirksmode; - } - - function parse_default_view($value) { - $valid = array("XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV"); - - $options = preg_split("/\s*,\s*/", trim($value)); - $default_view = array_shift($options); - - if ( !in_array($default_view, $valid) ) { - return false; - } - - $this->set_default_view($default_view, $options); - return true; - } - - /** - * Renders the HTML to PDF - */ - function render() { - $this->save_locale(); - - $log_output_file = $this->get_option("log_output_file"); - if ( $log_output_file ) { - if ( !file_exists($log_output_file) && is_writable(dirname($log_output_file)) ) { - touch($log_output_file); - } - - $this->_start_time = microtime(true); - ob_start(); - } - - //enable_mem_profile(); - - $this->_process_html(); - - $this->_css->apply_styles($this->_tree); - - // @page style rules : size, margins - $page_styles = $this->_css->get_page_styles(); - - $base_page_style = $page_styles["base"]; - unset($page_styles["base"]); - - foreach($page_styles as $_page_style) { - $_page_style->inherit($base_page_style); - } - - if ( is_array($base_page_style->size) ) { - $this->set_paper(array(0, 0, $base_page_style->size[0], $base_page_style->size[1])); - } - - $this->_pdf = Canvas_Factory::get_instance($this, $this->_paper_size, $this->_paper_orientation); - Font_Metrics::init($this->_pdf); - - if ( $this->get_option("enable_font_subsetting") && $this->_pdf instanceof CPDF_Adapter ) { - foreach ($this->_tree->get_frames() as $frame) { - $style = $frame->get_style(); - $node = $frame->get_node(); - - // Handle text nodes - if ( $node->nodeName === "#text" ) { - $this->_pdf->register_string_subset($style->font_family, $node->nodeValue); - continue; - } - - // Handle generated content (list items) - if ( $style->display === "list-item" ) { - $chars = List_Bullet_Renderer::get_counter_chars($style->list_style_type); - $this->_pdf->register_string_subset($style->font_family, $chars); - continue; - } - - // Handle other generated content (pseudo elements) - // FIXME: This only captures the text of the stylesheet declaration, - // not the actual generated content, and forces all possible counter - // values. See notes in issue #750. - if ( $frame->get_node()->nodeName == "dompdf_generated" ) { - // all possible counter values - $chars = List_Bullet_Renderer::get_counter_chars('decimal'); - $this->_pdf->register_string_subset($style->font_family, $chars); - $chars = List_Bullet_Renderer::get_counter_chars('upper-alpha'); - $this->_pdf->register_string_subset($style->font_family, $chars); - $chars = List_Bullet_Renderer::get_counter_chars('lower-alpha'); - $this->_pdf->register_string_subset($style->font_family, $chars); - $chars = List_Bullet_Renderer::get_counter_chars('lower-greek'); - $this->_pdf->register_string_subset($style->font_family, $chars); - // the text of the stylesheet declaration - $this->_pdf->register_string_subset($style->font_family, $style->content); - continue; - } - } - } - - $root = null; - - foreach ($this->_tree->get_frames() as $frame) { - // Set up the root frame - if ( is_null($root) ) { - $root = Frame_Factory::decorate_root( $this->_tree->get_root(), $this ); - continue; - } - - // Create the appropriate decorators, reflowers & positioners. - Frame_Factory::decorate_frame($frame, $this, $root); - } - - // Add meta information - $title = $this->_xml->getElementsByTagName("title"); - if ( $title->length ) { - $this->_pdf->add_info("Title", trim($title->item(0)->nodeValue)); - } - - $metas = $this->_xml->getElementsByTagName("meta"); - $labels = array( - "author" => "Author", - "keywords" => "Keywords", - "description" => "Subject", - ); - foreach($metas as $meta) { - $name = mb_strtolower($meta->getAttribute("name")); - $value = trim($meta->getAttribute("content")); - - if ( isset($labels[$name]) ) { - $this->_pdf->add_info($labels[$name], $value); - continue; - } - - if ( $name === "dompdf.view" && $this->parse_default_view($value) ) { - $this->_pdf->set_default_view($this->_default_view, $this->_default_view_options); - } - } - - $root->set_containing_block(0, 0, $this->_pdf->get_width(), $this->_pdf->get_height()); - $root->set_renderer(new Renderer($this)); - - // This is where the magic happens: - $root->reflow(); - - // Clean up cached images - Image_Cache::clear(); - - global $_dompdf_warnings, $_dompdf_show_warnings; - if ( $_dompdf_show_warnings ) { - echo 'DOMPDF Warnings
';
-      foreach ($_dompdf_warnings as $msg) {
-        echo $msg . "\n";
-      }
-      echo $this->get_canvas()->get_cpdf()->messages;
-      echo '
'; - flush(); - } - - $this->restore_locale(); - } - - /** - * Add meta information to the PDF after rendering - */ - function add_info($label, $value) { - if ( !is_null($this->_pdf) ) { - $this->_pdf->add_info($label, $value); - } - } - - /** - * Writes the output buffer in the log file - * - * @return void - */ - private function write_log() { - $log_output_file = $this->get_option("log_output_file"); - if ( !$log_output_file || !is_writable($log_output_file) ) { - return; - } - - $frames = Frame::$ID_COUNTER; - $memory = DOMPDF_memory_usage() / 1024; - $time = (microtime(true) - $this->_start_time) * 1000; - - $out = sprintf( - "%6d". - "%10.2f KB". - "%10.2f ms". - " ". - ($this->_quirksmode ? " ON" : "OFF"). - "
", $frames, $memory, $time); - - $out .= ob_get_clean(); - - $log_output_file = $this->get_option("log_output_file"); - file_put_contents($log_output_file, $out); - } - - /** - * Streams the PDF to the client - * - * The file will open a download dialog by default. The options - * parameter controls the output. Accepted options are: - * - * 'Accept-Ranges' => 1 or 0 - if this is not set to 1, then this - * header is not included, off by default this header seems to - * have caused some problems despite the fact that it is supposed - * to solve them, so I am leaving it off by default. - * - * 'compress' = > 1 or 0 - apply content stream compression, this is - * on (1) by default - * - * 'Attachment' => 1 or 0 - if 1, force the browser to open a - * download dialog, on (1) by default - * - * @param string $filename the name of the streamed file - * @param array $options header options (see above) - */ - function stream($filename, $options = null) { - $this->save_locale(); - - $this->write_log(); - - if ( !is_null($this->_pdf) ) { - $this->_pdf->stream($filename, $options); - } - - $this->restore_locale(); - } - - /** - * Returns the PDF as a string - * - * The file will open a download dialog by default. The options - * parameter controls the output. Accepted options are: - * - * - * 'compress' = > 1 or 0 - apply content stream compression, this is - * on (1) by default - * - * - * @param array $options options (see above) - * - * @return string - */ - function output($options = null) { - $this->save_locale(); - - $this->write_log(); - - if ( is_null($this->_pdf) ) { - return null; - } - - $output = $this->_pdf->output( $options ); - - $this->restore_locale(); - - return $output; - } - - /** - * Returns the underlying HTML document as a string - * - * @return string - */ - function output_html() { - return $this->_xml->saveHTML(); - } -} diff --git a/application/helpers/dompdf/include/dompdf_exception.cls.php b/application/helpers/dompdf/include/dompdf_exception.cls.php deleted file mode 100755 index ca47fa036..000000000 --- a/application/helpers/dompdf/include/dompdf_exception.cls.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Standard exception thrown by DOMPDF classes - * - * @package dompdf - */ -class DOMPDF_Exception extends Exception { - - /** - * Class constructor - * - * @param string $message Error message - * @param int $code Error code - */ - function __construct($message = null, $code = 0) { - parent::__construct($message, $code); - } - -} diff --git a/application/helpers/dompdf/include/dompdf_image_exception.cls.php b/application/helpers/dompdf/include/dompdf_image_exception.cls.php deleted file mode 100755 index 8fdecec52..000000000 --- a/application/helpers/dompdf/include/dompdf_image_exception.cls.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Image exception thrown by DOMPDF - * - * @package dompdf - */ -class DOMPDF_Image_Exception extends DOMPDF_Exception { - - /** - * Class constructor - * - * @param string $message Error message - * @param int $code Error code - */ - function __construct($message = null, $code = 0) { - parent::__construct($message, $code); - } - -} diff --git a/application/helpers/dompdf/include/file.skel b/application/helpers/dompdf/include/file.skel deleted file mode 100755 index 1f5fba936..000000000 --- a/application/helpers/dompdf/include/file.skel +++ /dev/null @@ -1,8 +0,0 @@ - - * @author ... - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ diff --git a/application/helpers/dompdf/include/fixed_positioner.cls.php b/application/helpers/dompdf/include/fixed_positioner.cls.php deleted file mode 100755 index 31a2a079c..000000000 --- a/application/helpers/dompdf/include/fixed_positioner.cls.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Positions fixely positioned frames - */ -class Fixed_Positioner extends Positioner { - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - function position() { - - $frame = $this->_frame; - $style = $frame->get_original_style(); - $root = $frame->get_root(); - $initialcb = $root->get_containing_block(); - $initialcb_style = $root->get_style(); - - $p = $frame->find_block_parent(); - if ( $p ) { - $p->add_line(); - } - - // Compute the margins of the @page style - $margin_top = $initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]); - $margin_right = $initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]); - $margin_bottom = $initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]); - $margin_left = $initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]); - - // The needed computed style of the element - $height = $style->length_in_pt($style->height, $initialcb["h"]); - $width = $style->length_in_pt($style->width, $initialcb["w"]); - - $top = $style->length_in_pt($style->top, $initialcb["h"]); - $right = $style->length_in_pt($style->right, $initialcb["w"]); - $bottom = $style->length_in_pt($style->bottom, $initialcb["h"]); - $left = $style->length_in_pt($style->left, $initialcb["w"]); - - $y = $margin_top; - if ( isset($top) ) { - $y = $top + $margin_top; - if ( $top === "auto" ) { - $y = $margin_top; - if ( isset($bottom) && $bottom !== "auto" ) { - $y = $initialcb["h"] - $bottom - $margin_bottom; - $margin_height = $this->_frame->get_margin_height(); - if ( $margin_height !== "auto" ) { - $y -= $margin_height; - } - else { - $y -= $height; - } - } - } - } - - $x = $margin_left; - if ( isset($left) ) { - $x = $left + $margin_left; - if ( $left === "auto" ) { - $x = $margin_left; - if ( isset($right) && $right !== "auto" ) { - $x = $initialcb["w"] - $right - $margin_right; - $margin_width = $this->_frame->get_margin_width(); - if ( $margin_width !== "auto" ) { - $x -= $margin_width; - } - else { - $x -= $width; - } - } - } - } - - $frame->set_position($x, $y); - - $children = $frame->get_children(); - foreach($children as $child) { - $child->set_position($x, $y); - } - } -} \ No newline at end of file diff --git a/application/helpers/dompdf/include/font_metrics.cls.php b/application/helpers/dompdf/include/font_metrics.cls.php deleted file mode 100755 index ad20d9119..000000000 --- a/application/helpers/dompdf/include/font_metrics.cls.php +++ /dev/null @@ -1,363 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -require_once DOMPDF_LIB_DIR . "/class.pdf.php"; - -/** - * Name of the font cache file - * - * This file must be writable by the webserver process only to update it - * with save_font_families() after adding the .afm file references of a new font family - * with Font_Metrics::save_font_families(). - * This is typically done only from command line with load_font.php on converting - * ttf fonts to ufm with php-font-lib. - * - * Declared here because PHP5 prevents constants from being declared with expressions - */ -define('__DOMPDF_FONT_CACHE_FILE', DOMPDF_FONT_DIR . "dompdf_font_family_cache.php"); - -/** - * The font metrics class - * - * This class provides information about fonts and text. It can resolve - * font names into actual installed font files, as well as determine the - * size of text in a particular font and size. - * - * @static - * @package dompdf - */ -class Font_Metrics { - - /** - * @see __DOMPDF_FONT_CACHE_FILE - */ - const CACHE_FILE = __DOMPDF_FONT_CACHE_FILE; - - /** - * Underlying {@link Canvas} object to perform text size calculations - * - * @var Canvas - */ - static protected $_pdf = null; - - /** - * Array of font family names to font files - * - * Usually cached by the {@link load_font.php} script - * - * @var array - */ - static protected $_font_lookup = array(); - - - /** - * Class initialization - * - */ - static function init(Canvas $canvas = null) { - if (!self::$_pdf) { - if (!$canvas) { - $canvas = Canvas_Factory::get_instance(new DOMPDF()); - } - - self::$_pdf = $canvas; - } - } - - /** - * Calculates text size, in points - * - * @param string $text the text to be sized - * @param string $font the desired font - * @param float $size the desired font size - * @param float $word_spacing - * @param float $char_spacing - * - * @internal param float $spacing word spacing, if any - * @return float - */ - static function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) { - //return self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing); - - // @todo Make sure this cache is efficient before enabling it - static $cache = array(); - - if ( $text === "" ) { - return 0; - } - - // Don't cache long strings - $use_cache = !isset($text[50]); // Faster than strlen - - $key = "$font/$size/$word_spacing/$char_spacing"; - - if ( $use_cache && isset($cache[$key][$text]) ) { - return $cache[$key]["$text"]; - } - - $width = self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing); - - if ( $use_cache ) { - $cache[$key][$text] = $width; - } - - return $width; - } - - /** - * Calculates font height - * - * @param string $font - * @param float $size - * @return float - */ - static function get_font_height($font, $size) { - return self::$_pdf->get_font_height($font, $size); - } - - /** - * Resolves a font family & subtype into an actual font file - * Subtype can be one of 'normal', 'bold', 'italic' or 'bold_italic'. If - * the particular font family has no suitable font file, the default font - * ({@link DOMPDF_DEFAULT_FONT}) is used. The font file returned - * is the absolute pathname to the font file on the system. - * - * @param string $family_raw - * @param string $subtype_raw - * - * @return string - */ - static function get_font($family_raw, $subtype_raw = "normal") { - static $cache = array(); - - if ( isset($cache[$family_raw][$subtype_raw]) ) { - return $cache[$family_raw][$subtype_raw]; - } - - /* Allow calling for various fonts in search path. Therefore not immediately - * return replacement on non match. - * Only when called with NULL try replacement. - * When this is also missing there is really trouble. - * If only the subtype fails, nevertheless return failure. - * Only on checking the fallback font, check various subtypes on same font. - */ - - $subtype = strtolower($subtype_raw); - - if ( $family_raw ) { - $family = str_replace( array("'", '"'), "", strtolower($family_raw)); - - if ( isset(self::$_font_lookup[$family][$subtype]) ) { - return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype]; - } - - return null; - } - - $family = "serif"; - - if ( isset(self::$_font_lookup[$family][$subtype]) ) { - return $cache[$family_raw][$subtype_raw] = self::$_font_lookup[$family][$subtype]; - } - - if ( !isset(self::$_font_lookup[$family]) ) { - return null; - } - - $family = self::$_font_lookup[$family]; - - foreach ( $family as $sub => $font ) { - if (strpos($subtype, $sub) !== false) { - return $cache[$family_raw][$subtype_raw] = $font; - } - } - - if ($subtype !== "normal") { - foreach ( $family as $sub => $font ) { - if ($sub !== "normal") { - return $cache[$family_raw][$subtype_raw] = $font; - } - } - } - - $subtype = "normal"; - - if ( isset($family[$subtype]) ) { - return $cache[$family_raw][$subtype_raw] = $family[$subtype]; - } - - return null; - } - - static function get_family($family) { - $family = str_replace( array("'", '"'), "", mb_strtolower($family)); - - if ( isset(self::$_font_lookup[$family]) ) { - return self::$_font_lookup[$family]; - } - - return null; - } - - /** - * Saves the stored font family cache - * - * The name and location of the cache file are determined by {@link - * Font_Metrics::CACHE_FILE}. This file should be writable by the - * webserver process. - * - * @see Font_Metrics::load_font_families() - */ - static function save_font_families() { - // replace the path to the DOMPDF font directories with the corresponding constants (allows for more portability) - $cache_data = var_export(self::$_font_lookup, true); - $cache_data = str_replace('\''.DOMPDF_FONT_DIR , 'DOMPDF_FONT_DIR . \'' , $cache_data); - $cache_data = str_replace('\''.DOMPDF_DIR , 'DOMPDF_DIR . \'' , $cache_data); - $cache_data = "<"."?php return $cache_data ?".">"; - file_put_contents(self::CACHE_FILE, $cache_data); - } - - /** - * Loads the stored font family cache - * - * @see save_font_families() - */ - static function load_font_families() { - $dist_fonts = require_once DOMPDF_DIR . "/lib/fonts/dompdf_font_family_cache.dist.php"; - - // FIXME: temporary step for font cache created before the font cache fix - if ( is_readable( DOMPDF_FONT_DIR . "dompdf_font_family_cache" ) ) { - $old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache"; - // If the font family cache is still in the old format - if ( $old_fonts === 1 ) { - $cache_data = file_get_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache"); - file_put_contents(DOMPDF_FONT_DIR . "dompdf_font_family_cache", "<"."?php return $cache_data ?".">"); - $old_fonts = require_once DOMPDF_FONT_DIR . "dompdf_font_family_cache"; - } - $dist_fonts += $old_fonts; - } - - if ( !is_readable(self::CACHE_FILE) ) { - self::$_font_lookup = $dist_fonts; - return; - } - - self::$_font_lookup = require_once self::CACHE_FILE; - - // If the font family cache is still in the old format - if ( self::$_font_lookup === 1 ) { - $cache_data = file_get_contents(self::CACHE_FILE); - file_put_contents(self::CACHE_FILE, "<"."?php return $cache_data ?".">"); - self::$_font_lookup = require_once self::CACHE_FILE; - } - - // Merge provided fonts - self::$_font_lookup += $dist_fonts; - } - - static function get_type($type) { - if (preg_match("/bold/i", $type)) { - if (preg_match("/italic|oblique/i", $type)) { - $type = "bold_italic"; - } - else { - $type = "bold"; - } - } - elseif (preg_match("/italic|oblique/i", $type)) { - $type = "italic"; - } - else { - $type = "normal"; - } - - return $type; - } - - static function install_fonts($files) { - $names = array(); - - foreach($files as $file) { - $font = Font::load($file); - $records = $font->getData("name", "records"); - $type = self::get_type($records[2]); - $names[mb_strtolower($records[1])][$type] = $file; - } - - return $names; - } - - static function get_system_fonts() { - $files = glob("/usr/share/fonts/truetype/*.ttf") + - glob("/usr/share/fonts/truetype/*/*.ttf") + - glob("/usr/share/fonts/truetype/*/*/*.ttf") + - glob("C:\\Windows\\fonts\\*.ttf") + - glob("C:\\WinNT\\fonts\\*.ttf") + - glob("/mnt/c_drive/WINDOWS/Fonts/"); - - return self::install_fonts($files); - } - - /** - * Returns the current font lookup table - * - * @return array - */ - static function get_font_families() { - return self::$_font_lookup; - } - - static function set_font_family($fontname, $entry) { - self::$_font_lookup[mb_strtolower($fontname)] = $entry; - } - - static function register_font($style, $remote_file) { - $fontname = mb_strtolower($style["family"]); - $families = Font_Metrics::get_font_families(); - - $entry = array(); - if ( isset($families[$fontname]) ) { - $entry = $families[$fontname]; - } - - $local_file = DOMPDF_FONT_DIR . md5($remote_file); - $cache_entry = $local_file; - $local_file .= ".ttf"; - - $style_string = Font_Metrics::get_type("{$style['weight']} {$style['style']}"); - - if ( !isset($entry[$style_string]) ) { - $entry[$style_string] = $cache_entry; - - Font_Metrics::set_font_family($fontname, $entry); - - // Download the remote file - if ( !is_file($local_file) ) { - file_put_contents($local_file, file_get_contents($remote_file)); - } - - $font = Font::load($local_file); - - if (!$font) { - return false; - } - - $font->parse(); - $font->saveAdobeFontMetrics("$cache_entry.ufm"); - - // Save the changes - Font_Metrics::save_font_families(); - } - - return true; - } -} - -Font_Metrics::load_font_families(); diff --git a/application/helpers/dompdf/include/frame.cls.php b/application/helpers/dompdf/include/frame.cls.php deleted file mode 100755 index bc2f26d40..000000000 --- a/application/helpers/dompdf/include/frame.cls.php +++ /dev/null @@ -1,1191 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * The main Frame class - * - * This class represents a single HTML element. This class stores - * positioning information as well as containing block location and - * dimensions. Style information for the element is stored in a {@link - * Style} object. Tree structure is maintained via the parent & children - * links. - * - * @access protected - * @package dompdf - */ -class Frame { - - /** - * The DOMElement or DOMText object this frame represents - * - * @var DOMElement|DOMText - */ - protected $_node; - - /** - * Unique identifier for this frame. Used to reference this frame - * via the node. - * - * @var string - */ - protected $_id; - - /** - * Unique id counter - */ - static /*protected*/ $ID_COUNTER = 0; - - /** - * This frame's calculated style - * - * @var Style - */ - protected $_style; - - /** - * This frame's original style. Needed for cases where frames are - * split across pages. - * - * @var Style - */ - protected $_original_style; - - /** - * This frame's parent in the document tree. - * - * @var Frame - */ - protected $_parent; - - /** - * This frame's children - * - * @var Frame[] - */ - protected $_frame_list; - - /** - * This frame's first child. All children are handled as a - * doubly-linked list. - * - * @var Frame - */ - protected $_first_child; - - /** - * This frame's last child. - * - * @var Frame - */ - protected $_last_child; - - /** - * This frame's previous sibling in the document tree. - * - * @var Frame - */ - protected $_prev_sibling; - - /** - * This frame's next sibling in the document tree. - * - * @var Frame - */ - protected $_next_sibling; - - /** - * This frame's containing block (used in layout): array(x, y, w, h) - * - * @var float[] - */ - protected $_containing_block; - - /** - * Position on the page of the top-left corner of the margin box of - * this frame: array(x,y) - * - * @var float[] - */ - protected $_position; - - /** - * Absolute opacity of this frame - * - * @var float - */ - protected $_opacity; - - /** - * This frame's decorator - * - * @var Frame_Decorator - */ - protected $_decorator; - - /** - * This frame's containing line box - * - * @var Line_Box - */ - protected $_containing_line; - - protected $_is_cache = array(); - - /** - * Tells wether the frame was already pushed to the next page - * - * @var bool - */ - public $_already_pushed = false; - - public $_float_next_line = false; - - /** - * Tells wether the frame was split - * - * @var bool - */ - public $_splitted; - - static $_ws_state = self::WS_SPACE; - - const WS_TEXT = 1; - const WS_SPACE = 2; - - /** - * Class destructor - */ - function __destruct() { - clear_object($this); - } - - /** - * Class constructor - * - * @param DOMNode $node the DOMNode this frame represents - */ - function __construct(DOMNode $node) { - $this->_node = $node; - - $this->_parent = null; - $this->_first_child = null; - $this->_last_child = null; - $this->_prev_sibling = $this->_next_sibling = null; - - $this->_style = null; - $this->_original_style = null; - - $this->_containing_block = array( - "x" => null, - "y" => null, - "w" => null, - "h" => null, - ); - - $this->_containing_block[0] =& $this->_containing_block["x"]; - $this->_containing_block[1] =& $this->_containing_block["y"]; - $this->_containing_block[2] =& $this->_containing_block["w"]; - $this->_containing_block[3] =& $this->_containing_block["h"]; - - $this->_position = array( - "x" => null, - "y" => null, - ); - - $this->_position[0] =& $this->_position["x"]; - $this->_position[1] =& $this->_position["y"]; - - $this->_opacity = 1.0; - $this->_decorator = null; - - $this->set_id( self::$ID_COUNTER++ ); - } - - // WIP : preprocessing to remove all the unused whitespace - protected function ws_trim(){ - if ( $this->ws_keep() ) { - return; - } - - switch(self::$_ws_state) { - case self::WS_SPACE: - $node = $this->_node; - - if ( $node->nodeName === "#text" ) { - $node->nodeValue = preg_replace("/[ \t\r\n\f]+/u", " ", $node->nodeValue); - - // starts with a whitespace - if ( isset($node->nodeValue[0]) && $node->nodeValue[0] === " " ) { - $node->nodeValue = ltrim($node->nodeValue); - } - - // if not empty - if ( $node->nodeValue !== "" ) { - // change the current state (text) - self::$_ws_state = self::WS_TEXT; - - // ends with a whitespace - if ( preg_match("/[ \t\r\n\f]+$/u", $node->nodeValue) ) { - $node->nodeValue = ltrim($node->nodeValue); - } - } - } - break; - - case self::WS_TEXT: - } - } - - protected function ws_keep(){ - $whitespace = $this->get_style()->white_space; - return in_array($whitespace, array("pre", "pre-wrap", "pre-line")); - } - - protected function ws_is_text(){ - $node = $this->get_node(); - - if ($node->nodeName === "img") { - return true; - } - - if ( !$this->is_in_flow() ) { - return false; - } - - if ($this->is_text_node()) { - return trim($node->nodeValue) !== ""; - } - - return true; - } - - /** - * "Destructor": forcibly free all references held by this frame - * - * @param bool $recursive if true, call dispose on all children - */ - function dispose($recursive = false) { - - if ( $recursive ) { - while ( $child = $this->_first_child ) { - $child->dispose(true); - } - } - - // Remove this frame from the tree - if ( $this->_prev_sibling ) { - $this->_prev_sibling->_next_sibling = $this->_next_sibling; - } - - if ( $this->_next_sibling ) { - $this->_next_sibling->_prev_sibling = $this->_prev_sibling; - } - - if ( $this->_parent && $this->_parent->_first_child === $this ) { - $this->_parent->_first_child = $this->_next_sibling; - } - - if ( $this->_parent && $this->_parent->_last_child === $this ) { - $this->_parent->_last_child = $this->_prev_sibling; - } - - if ( $this->_parent ) { - $this->_parent->get_node()->removeChild($this->_node); - } - - $this->_style->dispose(); - $this->_style = null; - unset($this->_style); - - $this->_original_style->dispose(); - $this->_original_style = null; - unset($this->_original_style); - - } - - // Re-initialize the frame - function reset() { - $this->_position["x"] = null; - $this->_position["y"] = null; - - $this->_containing_block["x"] = null; - $this->_containing_block["y"] = null; - $this->_containing_block["w"] = null; - $this->_containing_block["h"] = null; - - $this->_style = null; - unset($this->_style); - $this->_style = clone $this->_original_style; - } - - //........................................................................ - - /** - * @return DOMElement|DOMText - */ - function get_node() { - return $this->_node; - } - - /** - * @return string - */ - function get_id() { - return $this->_id; - } - - /** - * @return Style - */ - function get_style() { - return $this->_style; - } - - /** - * @return Style - */ - function get_original_style() { - return $this->_original_style; - } - - /** - * @return Frame - */ - function get_parent() { - return $this->_parent; - } - - /** - * @return Frame_Decorator - */ - function get_decorator() { - return $this->_decorator; - } - - /** - * @return Frame - */ - function get_first_child() { - return $this->_first_child; - } - - /** - * @return Frame - */ - function get_last_child() { - return $this->_last_child; - } - - /** - * @return Frame - */ - function get_prev_sibling() { - return $this->_prev_sibling; - } - - /** - * @return Frame - */ - function get_next_sibling() { - return $this->_next_sibling; - } - - /** - * @return FrameList|Frame[] - */ - function get_children() { - if ( isset($this->_frame_list) ) { - return $this->_frame_list; - } - - $this->_frame_list = new FrameList($this); - return $this->_frame_list; - } - - // Layout property accessors - - /** - * Containing block dimensions - * - * @param $i string The key of the wanted containing block's dimension (x, y, x, h) - * - * @return float[]|float - */ - function get_containing_block($i = null) { - if ( isset($i) ) { - return $this->_containing_block[$i]; - } - return $this->_containing_block; - } - - /** - * Block position - * - * @param $i string The key of the wanted position value (x, y) - * - * @return array|float - */ - function get_position($i = null) { - if ( isset($i) ) { - return $this->_position[$i]; - } - return $this->_position; - } - - //........................................................................ - - /** - * Return the height of the margin box of the frame, in pt. Meaningless - * unless the height has been calculated properly. - * - * @return float - */ - function get_margin_height() { - $style = $this->_style; - - return $style->length_in_pt(array( - $style->height, - $style->margin_top, - $style->margin_bottom, - $style->border_top_width, - $style->border_bottom_width, - $style->padding_top, - $style->padding_bottom - ), $this->_containing_block["h"]); - } - - /** - * Return the width of the margin box of the frame, in pt. Meaningless - * unless the width has been calculated properly. - * - * @return float - */ - function get_margin_width() { - $style = $this->_style; - - return $style->length_in_pt(array( - $style->width, - $style->margin_left, - $style->margin_right, - $style->border_left_width, - $style->border_right_width, - $style->padding_left, - $style->padding_right - ), $this->_containing_block["w"]); - } - - function get_break_margins(){ - $style = $this->_style; - - return $style->length_in_pt(array( - //$style->height, - $style->margin_top, - $style->margin_bottom, - $style->border_top_width, - $style->border_bottom_width, - $style->padding_top, - $style->padding_bottom - ), $this->_containing_block["h"]); - } - - /** - * Return the padding box (x,y,w,h) of the frame - * - * @return array - */ - function get_padding_box() { - $style = $this->_style; - $cb = $this->_containing_block; - - $x = $this->_position["x"] + - $style->length_in_pt(array($style->margin_left, - $style->border_left_width), - $cb["w"]); - - $y = $this->_position["y"] + - $style->length_in_pt(array($style->margin_top, - $style->border_top_width), - $cb["h"]); - - $w = $style->length_in_pt(array($style->padding_left, - $style->width, - $style->padding_right), - $cb["w"]); - - $h = $style->length_in_pt(array($style->padding_top, - $style->height, - $style->padding_bottom), - $cb["h"]); - - return array(0 => $x, "x" => $x, - 1 => $y, "y" => $y, - 2 => $w, "w" => $w, - 3 => $h, "h" => $h); - } - - /** - * Return the border box of the frame - * - * @return array - */ - function get_border_box() { - $style = $this->_style; - $cb = $this->_containing_block; - - $x = $this->_position["x"] + $style->length_in_pt($style->margin_left, $cb["w"]); - - $y = $this->_position["y"] + $style->length_in_pt($style->margin_top, $cb["h"]); - - $w = $style->length_in_pt(array($style->border_left_width, - $style->padding_left, - $style->width, - $style->padding_right, - $style->border_right_width), - $cb["w"]); - - $h = $style->length_in_pt(array($style->border_top_width, - $style->padding_top, - $style->height, - $style->padding_bottom, - $style->border_bottom_width), - $cb["h"]); - - return array(0 => $x, "x" => $x, - 1 => $y, "y" => $y, - 2 => $w, "w" => $w, - 3 => $h, "h" => $h); - } - - function get_opacity($opacity = null) { - if ( $opacity !== null ) { - $this->set_opacity($opacity); - } - return $this->_opacity; - } - - /** - * @return Line_Box - */ - function &get_containing_line() { - return $this->_containing_line; - } - - //........................................................................ - - // Set methods - function set_id($id) { - $this->_id = $id; - - // We can only set attributes of DOMElement objects (nodeType == 1). - // Since these are the only objects that we can assign CSS rules to, - // this shortcoming is okay. - if ( $this->_node->nodeType == XML_ELEMENT_NODE ) { - $this->_node->setAttribute("frame_id", $id); - } - } - - function set_style(Style $style) { - if ( is_null($this->_style) ) { - $this->_original_style = clone $style; - } - - //$style->set_frame($this); - $this->_style = $style; - } - - function set_decorator(Frame_Decorator $decorator) { - $this->_decorator = $decorator; - } - - function set_containing_block($x = null, $y = null, $w = null, $h = null) { - if ( is_array($x) ){ - foreach($x as $key => $val){ - $$key = $val; - } - } - - if (is_numeric($x)) { - $this->_containing_block["x"] = $x; - } - - if (is_numeric($y)) { - $this->_containing_block["y"] = $y; - } - - if (is_numeric($w)) { - $this->_containing_block["w"] = $w; - } - - if (is_numeric($h)) { - $this->_containing_block["h"] = $h; - } - } - - function set_position($x = null, $y = null) { - if ( is_array($x) ) { - list($x, $y) = array($x["x"], $x["y"]); - } - - if ( is_numeric($x) ) { - $this->_position["x"] = $x; - } - - if ( is_numeric($y) ) { - $this->_position["y"] = $y; - } - } - - function set_opacity($opacity) { - $parent = $this->get_parent(); - $base_opacity = (($parent && $parent->_opacity !== null) ? $parent->_opacity : 1.0); - $this->_opacity = $base_opacity * $opacity; - } - - function set_containing_line(Line_Box $line) { - $this->_containing_line = $line; - } - - //........................................................................ - - /** - * Tells if the frame is a text node - * @return bool - */ - function is_text_node() { - if ( isset($this->_is_cache["text_node"]) ) { - return $this->_is_cache["text_node"]; - } - - return $this->_is_cache["text_node"] = ($this->get_node()->nodeName === "#text"); - } - - function is_positionned() { - if ( isset($this->_is_cache["positionned"]) ) { - return $this->_is_cache["positionned"]; - } - - $position = $this->get_style()->position; - - return $this->_is_cache["positionned"] = in_array($position, Style::$POSITIONNED_TYPES); - } - - function is_absolute() { - if ( isset($this->_is_cache["absolute"]) ) { - return $this->_is_cache["absolute"]; - } - - $position = $this->get_style()->position; - - return $this->_is_cache["absolute"] = ($position === "absolute" || $position === "fixed"); - } - - function is_block() { - if ( isset($this->_is_cache["block"]) ) { - return $this->_is_cache["block"]; - } - - return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::$BLOCK_TYPES); - } - - function is_in_flow() { - if ( isset($this->_is_cache["in_flow"]) ) { - return $this->_is_cache["in_flow"]; - } - - $enable_css_float = $this->get_style()->get_stylesheet()->get_dompdf()->get_option("enable_css_float"); - return $this->_is_cache["in_flow"] = !($enable_css_float && $this->get_style()->float !== "none" || $this->is_absolute()); - } - - function is_pre(){ - if ( isset($this->_is_cache["pre"]) ) { - return $this->_is_cache["pre"]; - } - - $white_space = $this->get_style()->white_space; - - return $this->_is_cache["pre"] = in_array($white_space, array("pre", "pre-wrap")); - } - - function is_table(){ - if ( isset($this->_is_cache["table"]) ) { - return $this->_is_cache["table"]; - } - - $display = $this->get_style()->display; - - return $this->_is_cache["table"] = in_array($display, Style::$TABLE_TYPES); - } - - - /** - * Inserts a new child at the beginning of the Frame - * - * @param $child Frame The new Frame to insert - * @param $update_node boolean Whether or not to update the DOM - */ - function prepend_child(Frame $child, $update_node = true) { - if ( $update_node ) { - $this->_node->insertBefore($child->_node, $this->_first_child ? $this->_first_child->_node : null); - } - - // Remove the child from its parent - if ( $child->_parent ) { - $child->_parent->remove_child($child, false); - } - - $child->_parent = $this; - $child->_prev_sibling = null; - - // Handle the first child - if ( !$this->_first_child ) { - $this->_first_child = $child; - $this->_last_child = $child; - $child->_next_sibling = null; - } - else { - $this->_first_child->_prev_sibling = $child; - $child->_next_sibling = $this->_first_child; - $this->_first_child = $child; - } - } - - /** - * Inserts a new child at the end of the Frame - * - * @param $child Frame The new Frame to insert - * @param $update_node boolean Whether or not to update the DOM - */ - function append_child(Frame $child, $update_node = true) { - if ( $update_node ) { - $this->_node->appendChild($child->_node); - } - - // Remove the child from its parent - if ( $child->_parent ) { - $child->_parent->remove_child($child, false); - } - - $child->_parent = $this; - $child->_next_sibling = null; - - // Handle the first child - if ( !$this->_last_child ) { - $this->_first_child = $child; - $this->_last_child = $child; - $child->_prev_sibling = null; - } - else { - $this->_last_child->_next_sibling = $child; - $child->_prev_sibling = $this->_last_child; - $this->_last_child = $child; - } - } - - /** - * Inserts a new child immediately before the specified frame - * - * @param $new_child Frame The new Frame to insert - * @param $ref Frame The Frame after the new Frame - * @param $update_node boolean Whether or not to update the DOM - * - * @throws DOMPDF_Exception - */ - function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) { - if ( $ref === $this->_first_child ) { - $this->prepend_child($new_child, $update_node); - return; - } - - if ( is_null($ref) ) { - $this->append_child($new_child, $update_node); - return; - } - - if ( $ref->_parent !== $this ) { - throw new DOMPDF_Exception("Reference child is not a child of this node."); - } - - // Update the node - if ( $update_node ) { - $this->_node->insertBefore($new_child->_node, $ref->_node); - } - - // Remove the child from its parent - if ( $new_child->_parent ) { - $new_child->_parent->remove_child($new_child, false); - } - - $new_child->_parent = $this; - $new_child->_next_sibling = $ref; - $new_child->_prev_sibling = $ref->_prev_sibling; - - if ( $ref->_prev_sibling ) { - $ref->_prev_sibling->_next_sibling = $new_child; - } - - $ref->_prev_sibling = $new_child; - } - - /** - * Inserts a new child immediately after the specified frame - * - * @param $new_child Frame The new Frame to insert - * @param $ref Frame The Frame before the new Frame - * @param $update_node boolean Whether or not to update the DOM - * - * @throws DOMPDF_Exception - */ - function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) { - if ( $ref === $this->_last_child ) { - $this->append_child($new_child, $update_node); - return; - } - - if ( is_null($ref) ) { - $this->prepend_child($new_child, $update_node); - return; - } - - if ( $ref->_parent !== $this ) { - throw new DOMPDF_Exception("Reference child is not a child of this node."); - } - - // Update the node - if ( $update_node ) { - if ( $ref->_next_sibling ) { - $next_node = $ref->_next_sibling->_node; - $this->_node->insertBefore($new_child->_node, $next_node); - } - else { - $new_child->_node = $this->_node->appendChild($new_child->_node); - } - } - - // Remove the child from its parent - if ( $new_child->_parent ) { - $new_child->_parent->remove_child($new_child, false); - } - - $new_child->_parent = $this; - $new_child->_prev_sibling = $ref; - $new_child->_next_sibling = $ref->_next_sibling; - - if ( $ref->_next_sibling ) { - $ref->_next_sibling->_prev_sibling = $new_child; - } - - $ref->_next_sibling = $new_child; - } - - - /** - * Remove a child frame - * - * @param Frame $child - * @param boolean $update_node Whether or not to remove the DOM node - * - * @throws DOMPDF_Exception - * @return Frame The removed child frame - */ - function remove_child(Frame $child, $update_node = true) { - if ( $child->_parent !== $this ) { - throw new DOMPDF_Exception("Child not found in this frame"); - } - - if ( $update_node ) { - $this->_node->removeChild($child->_node); - } - - if ( $child === $this->_first_child ) { - $this->_first_child = $child->_next_sibling; - } - - if ( $child === $this->_last_child ) { - $this->_last_child = $child->_prev_sibling; - } - - if ( $child->_prev_sibling ) { - $child->_prev_sibling->_next_sibling = $child->_next_sibling; - } - - if ( $child->_next_sibling ) { - $child->_next_sibling->_prev_sibling = $child->_prev_sibling; - } - - $child->_next_sibling = null; - $child->_prev_sibling = null; - $child->_parent = null; - return $child; - } - - //........................................................................ - - // Debugging function: - function __toString() { - // Skip empty text frames -// if ( $this->is_text_node() && -// preg_replace("/\s/", "", $this->_node->data) === "" ) -// return ""; - - - $str = "" . $this->_node->nodeName . ":
"; - //$str .= spl_object_hash($this->_node) . "
"; - $str .= "Id: " .$this->get_id() . "
"; - $str .= "Class: " .get_class($this) . "
"; - - if ( $this->is_text_node() ) { - $tmp = htmlspecialchars($this->_node->nodeValue); - $str .= "
'" .  mb_substr($tmp,0,70) .
-        (mb_strlen($tmp) > 70 ? "..." : "") . "'
"; - } - elseif ( $css_class = $this->_node->getAttribute("class") ) { - $str .= "CSS class: '$css_class'
"; - } - - if ( $this->_parent ) { - $str .= "\nParent:" . $this->_parent->_node->nodeName . - " (" . spl_object_hash($this->_parent->_node) . ") " . - "
"; - } - - if ( $this->_prev_sibling ) { - $str .= "Prev: " . $this->_prev_sibling->_node->nodeName . - " (" . spl_object_hash($this->_prev_sibling->_node) . ") " . - "
"; - } - - if ( $this->_next_sibling ) { - $str .= "Next: " . $this->_next_sibling->_node->nodeName . - " (" . spl_object_hash($this->_next_sibling->_node) . ") " . - "
"; - } - - $d = $this->get_decorator(); - while ($d && $d != $d->get_decorator()) { - $str .= "Decorator: " . get_class($d) . "
"; - $d = $d->get_decorator(); - } - - $str .= "Position: " . pre_r($this->_position, true); - $str .= "\nContaining block: " . pre_r($this->_containing_block, true); - $str .= "\nMargin width: " . pre_r($this->get_margin_width(), true); - $str .= "\nMargin height: " . pre_r($this->get_margin_height(), true); - - $str .= "\nStyle:
". $this->_style->__toString() . "
"; - - if ( $this->_decorator instanceof Block_Frame_Decorator ) { - $str .= "Lines:
";
-      foreach ($this->_decorator->get_line_boxes() as $line) {
-        foreach ($line->get_frames() as $frame) {
-          if ($frame instanceof Text_Frame_Decorator) {
-            $str .= "\ntext: ";
-            $str .= "'". htmlspecialchars($frame->get_text()) ."'";
-          }
-          else {
-            $str .= "\nBlock: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")";
-          }
-        }
-
-        $str .=
-          "\ny => " . $line->y . "\n" .
-          "w => " . $line->w . "\n" .
-          "h => " . $line->h . "\n" .
-          "left => " . $line->left . "\n" .
-          "right => " . $line->right . "\n";
-      }
-      $str .= "
"; - } - - $str .= "\n"; - if ( php_sapi_name() === "cli" ) { - $str = strip_tags(str_replace(array("
","",""), - array("\n","",""), - $str)); - } - - return $str; - } -} - -//------------------------------------------------------------------------ - -/** - * Linked-list IteratorAggregate - * - * @access private - * @package dompdf - */ -class FrameList implements IteratorAggregate { - protected $_frame; - - function __construct($frame) { $this->_frame = $frame; } - function getIterator() { return new FrameListIterator($this->_frame); } -} - -/** - * Linked-list Iterator - * - * Returns children in order and allows for list to change during iteration, - * provided the changes occur to or after the current element - * - * @access private - * @package dompdf - */ -class FrameListIterator implements Iterator { - - /** - * @var Frame - */ - protected $_parent; - - /** - * @var Frame - */ - protected $_cur; - - /** - * @var int - */ - protected $_num; - - function __construct(Frame $frame) { - $this->_parent = $frame; - $this->_cur = $frame->get_first_child(); - $this->_num = 0; - } - - function rewind() { - $this->_cur = $this->_parent->get_first_child(); - $this->_num = 0; - } - - /** - * @return bool - */ - function valid() { - return isset($this->_cur);// && ($this->_cur->get_prev_sibling() === $this->_prev); - } - - function key() { return $this->_num; } - - /** - * @return Frame - */ - function current() { return $this->_cur; } - - /** - * @return Frame - */ - function next() { - - $ret = $this->_cur; - if ( !$ret ) { - return null; - } - - $this->_cur = $this->_cur->get_next_sibling(); - $this->_num++; - return $ret; - } -} - -//------------------------------------------------------------------------ - -/** - * Pre-order IteratorAggregate - * - * @access private - * @package dompdf - */ -class FrameTreeList implements IteratorAggregate { - /** - * @var Frame - */ - protected $_root; - - function __construct(Frame $root) { $this->_root = $root; } - - /** - * @return FrameTreeIterator - */ - function getIterator() { return new FrameTreeIterator($this->_root); } -} - -/** - * Pre-order Iterator - * - * Returns frames in preorder traversal order (parent then children) - * - * @access private - * @package dompdf - */ -class FrameTreeIterator implements Iterator { - /** - * @var Frame - */ - protected $_root; - protected $_stack = array(); - - /** - * @var int - */ - protected $_num; - - function __construct(Frame $root) { - $this->_stack[] = $this->_root = $root; - $this->_num = 0; - } - - function rewind() { - $this->_stack = array($this->_root); - $this->_num = 0; - } - - /** - * @return bool - */ - function valid() { - return count($this->_stack) > 0; - } - - /** - * @return int - */ - function key() { - return $this->_num; - } - - /** - * @return Frame - */ - function current() { - return end($this->_stack); - } - - /** - * @return Frame - */ - function next() { - $b = end($this->_stack); - - // Pop last element - unset($this->_stack[ key($this->_stack) ]); - $this->_num++; - - // Push all children onto the stack in reverse order - if ( $c = $b->get_last_child() ) { - $this->_stack[] = $c; - while ( $c = $c->get_prev_sibling() ) { - $this->_stack[] = $c; - } - } - - return $b; - } -} - diff --git a/application/helpers/dompdf/include/frame_decorator.cls.php b/application/helpers/dompdf/include/frame_decorator.cls.php deleted file mode 100755 index 987e32ee1..000000000 --- a/application/helpers/dompdf/include/frame_decorator.cls.php +++ /dev/null @@ -1,717 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Base Frame_Decorator class - * - * @access private - * @package dompdf - */ -abstract class Frame_Decorator extends Frame { - const DEFAULT_COUNTER = "-dompdf-default-counter"; - - public $_counters = array(); // array([id] => counter_value) (for generated content) - - /** - * The root node of the DOM tree - * - * @var Frame - */ - protected $_root; - - /** - * The decorated frame - * - * @var Frame - */ - protected $_frame; - - /** - * Positioner object used to position this frame (Strategy pattern) - * - * @var Positioner - */ - protected $_positioner; - - /** - * Reflower object used to calculate frame dimensions (Strategy pattern) - * - * @var Frame_Reflower - */ - protected $_reflower; - - /** - * Reference to the current dompdf instance - * - * @var DOMPDF - */ - protected $_dompdf; - - /** - * First block parent - * - * @var Block_Frame_Decorator - */ - private $_block_parent; - - /** - * First positionned parent (position: relative | absolute | fixed) - * - * @var Frame_Decorator - */ - private $_positionned_parent; - - /** - * Class constructor - * - * @param Frame $frame The decoration target - * @param DOMPDF $dompdf The DOMPDF object - */ - function __construct(Frame $frame, DOMPDF $dompdf) { - $this->_frame = $frame; - $this->_root = null; - $this->_dompdf = $dompdf; - $frame->set_decorator($this); - } - - /** - * "Destructor": foribly free all references held by this object - * - * @param bool $recursive if true, call dispose on all children - */ - function dispose($recursive = false) { - if ( $recursive ) { - while ( $child = $this->get_first_child() ) { - $child->dispose(true); - } - } - - $this->_root = null; - unset($this->_root); - - $this->_frame->dispose(true); - $this->_frame = null; - unset($this->_frame); - - $this->_positioner = null; - unset($this->_positioner); - - $this->_reflower = null; - unset($this->_reflower); - } - - /** - * Return a copy of this frame with $node as its node - * - * @param DOMNode $node - * - * @return Frame - */ - function copy(DOMNode $node) { - $frame = new Frame($node); - $frame->set_style(clone $this->_frame->get_original_style()); - - return Frame_Factory::decorate_frame($frame, $this->_dompdf, $this->_root); - } - - /** - * Create a deep copy: copy this node and all children - * - * @return Frame - */ - function deep_copy() { - $frame = new Frame($this->get_node()->cloneNode()); - $frame->set_style(clone $this->_frame->get_original_style()); - - $deco = Frame_Factory::decorate_frame($frame, $this->_dompdf, $this->_root); - - foreach ($this->get_children() as $child) { - $deco->append_child($child->deep_copy()); - } - - return $deco; - } - - /** - * Delegate calls to decorated frame object - */ - function reset() { - $this->_frame->reset(); - - $this->_counters = array(); - - // Reset all children - foreach ($this->get_children() as $child) { - $child->reset(); - } - } - - // Getters ----------- - function get_id() { - return $this->_frame->get_id(); - } - - /** - * @return Frame - */ - function get_frame() { - return $this->_frame; - } - - /** - * @return DOMElement|DOMText - */ - function get_node() { - return $this->_frame->get_node(); - } - - /** - * @return Style - */ - function get_style() { - return $this->_frame->get_style(); - } - - /** - * @return Style - */ - function get_original_style() { - return $this->_frame->get_original_style(); - } - - /** - * @param integer $i - * - * @return array|float - */ - function get_containing_block($i = null) { - return $this->_frame->get_containing_block($i); - } - - /** - * @param integer $i - * - * @return array|float - */ - function get_position($i = null) { - return $this->_frame->get_position($i); - } - - /** - * @return DOMPDF - */ - function get_dompdf() { - return $this->_dompdf; - } - - /** - * @return float - */ - function get_margin_height() { - return $this->_frame->get_margin_height(); - } - - /** - * @return float - */ - function get_margin_width() { - return $this->_frame->get_margin_width(); - } - - /** - * @return array - */ - function get_padding_box() { - return $this->_frame->get_padding_box(); - } - - /** - * @return array - */ - function get_border_box() { - return $this->_frame->get_border_box(); - } - - /** - * @param integer $id - */ - function set_id($id) { - $this->_frame->set_id($id); - } - - /** - * @param Style $style - */ - function set_style(Style $style) { - $this->_frame->set_style($style); - } - - /** - * @param float $x - * @param float $y - * @param float $w - * @param float $h - */ - function set_containing_block($x = null, $y = null, $w = null, $h = null) { - $this->_frame->set_containing_block($x, $y, $w, $h); - } - - /** - * @param float $x - * @param float $y - */ - function set_position($x = null, $y = null) { - $this->_frame->set_position($x, $y); - } - - /** - * @return string - */ - function __toString() { - return $this->_frame->__toString(); - } - - /** - * @param Frame $child - * @param bool $update_node - */ - function prepend_child(Frame $child, $update_node = true) { - while ( $child instanceof Frame_Decorator ) { - $child = $child->_frame; - } - - $this->_frame->prepend_child($child, $update_node); - } - - /** - * @param Frame $child - * @param bool $update_node - */ - function append_child(Frame $child, $update_node = true) { - while ( $child instanceof Frame_Decorator ) { - $child = $child->_frame; - } - - $this->_frame->append_child($child, $update_node); - } - - /** - * @param Frame $new_child - * @param Frame $ref - * @param bool $update_node - */ - function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) { - while ( $new_child instanceof Frame_Decorator ) { - $new_child = $new_child->_frame; - } - - if ( $ref instanceof Frame_Decorator ) { - $ref = $ref->_frame; - } - - $this->_frame->insert_child_before($new_child, $ref, $update_node); - } - - /** - * @param Frame $new_child - * @param Frame $ref - * @param bool $update_node - */ - function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) { - while ( $new_child instanceof Frame_Decorator ) { - $new_child = $new_child->_frame; - } - - while ( $ref instanceof Frame_Decorator ) { - $ref = $ref->_frame; - } - - $this->_frame->insert_child_after($new_child, $ref, $update_node); - } - - /** - * @param Frame $child - * @param bool $update_node - * - * @return Frame - */ - function remove_child(Frame $child, $update_node = true) { - while ( $child instanceof Frame_Decorator ) { - $child = $child->_frame; - } - - return $this->_frame->remove_child($child, $update_node); - } - - /** - * @return Frame_Decorator - */ - function get_parent() { - $p = $this->_frame->get_parent(); - if ( $p && $deco = $p->get_decorator() ) { - while ( $tmp = $deco->get_decorator() ) { - $deco = $tmp; - } - - return $deco; - } - else if ( $p ) { - return $p; - } - - return null; - } - - /** - * @return Frame_Decorator - */ - function get_first_child() { - $c = $this->_frame->get_first_child(); - if ( $c && $deco = $c->get_decorator() ) { - while ( $tmp = $deco->get_decorator() ) { - $deco = $tmp; - } - - return $deco; - } - else if ( $c ) { - return $c; - } - - return null; - } - - /** - * @return Frame_Decorator - */ - function get_last_child() { - $c = $this->_frame->get_last_child(); - if ( $c && $deco = $c->get_decorator() ) { - while ( $tmp = $deco->get_decorator() ) { - $deco = $tmp; - } - - return $deco; - } - else if ( $c ) { - return $c; - } - - return null; - } - - /** - * @return Frame_Decorator - */ - function get_prev_sibling() { - $s = $this->_frame->get_prev_sibling(); - if ( $s && $deco = $s->get_decorator() ) { - while ( $tmp = $deco->get_decorator() ) { - $deco = $tmp; - } - return $deco; - } - else if ( $s ) { - return $s; - } - - return null; - } - - /** - * @return Frame_Decorator - */ - function get_next_sibling() { - $s = $this->_frame->get_next_sibling(); - if ( $s && $deco = $s->get_decorator() ) { - while ( $tmp = $deco->get_decorator() ) { - $deco = $tmp; - } - - return $deco; - } - else if ( $s ) { - return $s; - } - - return null; - } - - /** - * @return FrameTreeList - */ - function get_subtree() { - return new FrameTreeList($this); - } - - function set_positioner(Positioner $posn) { - $this->_positioner = $posn; - if ( $this->_frame instanceof Frame_Decorator ) { - $this->_frame->set_positioner($posn); - } - } - - function set_reflower(Frame_Reflower $reflower) { - $this->_reflower = $reflower; - if ( $this->_frame instanceof Frame_Decorator ) { - $this->_frame->set_reflower( $reflower ); - } - } - - /** - * @return Frame_Reflower - */ - function get_reflower() { - return $this->_reflower; - } - - /** - * @param Frame $root - */ - function set_root(Frame $root) { - $this->_root = $root; - - if ( $this->_frame instanceof Frame_Decorator ) { - $this->_frame->set_root($root); - } - } - - /** - * @return Page_Frame_Decorator - */ - function get_root() { - return $this->_root; - } - - /** - * @return Block_Frame_Decorator - */ - function find_block_parent() { - // Find our nearest block level parent - $p = $this->get_parent(); - - while ( $p ) { - if ( $p->is_block() ) { - break; - } - - $p = $p->get_parent(); - } - - return $this->_block_parent = $p; - } - - /** - * @return Frame_Decorator - */ - function find_positionned_parent() { - // Find our nearest relative positionned parent - $p = $this->get_parent(); - while ( $p ) { - if ( $p->is_positionned() ) { - break; - } - - $p = $p->get_parent(); - } - - if ( !$p ) { - $p = $this->_root->get_first_child(); // - } - - return $this->_positionned_parent = $p; - } - - /** - * split this frame at $child. - * The current frame is cloned and $child and all children following - * $child are added to the clone. The clone is then passed to the - * current frame's parent->split() method. - * - * @param Frame $child - * @param boolean $force_pagebreak - * - * @throws DOMPDF_Exception - * @return void - */ - function split(Frame $child = null, $force_pagebreak = false) { - // decrement any counters that were incremented on the current node, unless that node is the body - $style = $this->_frame->get_style(); - if ( $this->_frame->get_node()->nodeName !== "body" && $style->counter_increment && ($decrement = $style->counter_increment) !== "none" ) { - $this->decrement_counters($decrement); - } - - if ( is_null( $child ) ) { - // check for counter increment on :before content (always a child of the selected element @link Frame_Reflower::_set_content) - // this can push the current node to the next page before counter rules have bubbled up (but only if - // it's been rendered, thus the position check) - if ( !$this->is_text_node() && $this->get_node()->hasAttribute("dompdf_before_frame_id") ) { - foreach($this->_frame->get_children() as $child) { - if ( $this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id() && $child->get_position('x') !== NULL ) { - $style = $child->get_style(); - if ( $style->counter_increment && ($decrement = $style->counter_increment) !== "none" ) { - $this->decrement_counters($decrement); - } - } - } - } - $this->get_parent()->split($this, $force_pagebreak); - return; - } - - if ( $child->get_parent() !== $this ) { - throw new DOMPDF_Exception("Unable to split: frame is not a child of this one."); - } - - $node = $this->_frame->get_node(); - - $split = $this->copy( $node->cloneNode() ); - $split->reset(); - $split->get_original_style()->text_indent = 0; - $split->_splitted = true; - - // The body's properties must be kept - if ( $node->nodeName !== "body" ) { - // Style reset on the first and second parts - $style = $this->_frame->get_style(); - $style->margin_bottom = 0; - $style->padding_bottom = 0; - $style->border_bottom = 0; - - // second - $orig_style = $split->get_original_style(); - $orig_style->text_indent = 0; - $orig_style->margin_top = 0; - $orig_style->padding_top = 0; - $orig_style->border_top = 0; - } - - $this->get_parent()->insert_child_after($split, $this); - - // Add $frame and all following siblings to the new split node - $iter = $child; - while ($iter) { - $frame = $iter; - $iter = $iter->get_next_sibling(); - $frame->reset(); - $split->append_child($frame); - } - - $this->get_parent()->split($split, $force_pagebreak); - - // If this node resets a counter save the current value to use when rendering on the next page - if ( $style->counter_reset && ( $reset = $style->counter_reset ) !== "none" ) { - $vars = preg_split( '/\s+/' , trim( $reset ) , 2 ); - $split->_counters[ '__' . $vars[0] ] = $this->lookup_counter_frame( $vars[0] )->_counters[$vars[0]]; - } - } - - function reset_counter($id = self::DEFAULT_COUNTER, $value = 0) { - $this->get_parent()->_counters[$id] = intval($value); - } - - function decrement_counters($counters) { - foreach($counters as $id => $increment) { - $this->increment_counter($id, intval($increment) * -1); - } - } - - function increment_counters($counters) { - foreach($counters as $id => $increment) { - $this->increment_counter($id, intval($increment)); - } - } - - function increment_counter($id = self::DEFAULT_COUNTER, $increment = 1) { - $counter_frame = $this->lookup_counter_frame($id); - - if ( $counter_frame ) { - if ( !isset($counter_frame->_counters[$id]) ) { - $counter_frame->_counters[$id] = 0; - } - - $counter_frame->_counters[$id] += $increment; - } - } - - function lookup_counter_frame($id = self::DEFAULT_COUNTER) { - $f = $this->get_parent(); - - while( $f ) { - if( isset($f->_counters[$id]) ) { - return $f; - } - $fp = $f->get_parent(); - - if ( !$fp ) { - return $f; - } - - $f = $fp; - } - } - - // TODO: What version is the best : this one or the one in List_Bullet_Renderer ? - function counter_value($id = self::DEFAULT_COUNTER, $type = "decimal") { - $type = mb_strtolower($type); - - if ( !isset($this->_counters[$id]) ) { - $this->_counters[$id] = 0; - } - - $value = $this->_counters[$id]; - - switch ($type) { - default: - case "decimal": - return $value; - - case "decimal-leading-zero": - return str_pad($value, 2, "0"); - - case "lower-roman": - return dec2roman($value); - - case "upper-roman": - return mb_strtoupper(dec2roman($value)); - - case "lower-latin": - case "lower-alpha": - return chr( ($value % 26) + ord('a') - 1); - - case "upper-latin": - case "upper-alpha": - return chr( ($value % 26) + ord('A') - 1); - - case "lower-greek": - return unichr($value + 944); - - case "upper-greek": - return unichr($value + 912); - } - } - - final function position() { - $this->_positioner->position(); - } - - final function move($offset_x, $offset_y, $ignore_self = false) { - $this->_positioner->move($offset_x, $offset_y, $ignore_self); - } - - final function reflow(Block_Frame_Decorator $block = null) { - // Uncomment this to see the frames before they're laid out, instead of - // during rendering. - //echo $this->_frame; flush(); - $this->_reflower->reflow($block); - } - - final function get_min_max_width() { - return $this->_reflower->get_min_max_width(); - } -} diff --git a/application/helpers/dompdf/include/frame_factory.cls.php b/application/helpers/dompdf/include/frame_factory.cls.php deleted file mode 100755 index 70813d2e3..000000000 --- a/application/helpers/dompdf/include/frame_factory.cls.php +++ /dev/null @@ -1,252 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Contains frame decorating logic - * - * This class is responsible for assigning the correct {@link Frame_Decorator}, - * {@link Positioner}, and {@link Frame_Reflower} objects to {@link Frame} - * objects. This is determined primarily by the Frame's display type, but - * also by the Frame's node's type (e.g. DomElement vs. #text) - * - * @access private - * @package dompdf - */ -class Frame_Factory { - - /** - * Decorate the root Frame - * - * @param $root Frame The frame to decorate - * @param $dompdf DOMPDF The dompdf instance - * @return Page_Frame_Decorator - */ - static function decorate_root(Frame $root, DOMPDF $dompdf) { - $frame = new Page_Frame_Decorator($root, $dompdf); - $frame->set_reflower( new Page_Frame_Reflower($frame) ); - $root->set_decorator($frame); - return $frame; - } - - /** - * Decorate a Frame - * - * @param Frame $frame The frame to decorate - * @param DOMPDF $dompdf The dompdf instance - * @param Frame $root The frame to decorate - * - * @throws DOMPDF_Exception - * @return Frame_Decorator - * FIXME: this is admittedly a little smelly... - */ - static function decorate_frame(Frame $frame, DOMPDF $dompdf, Frame $root = null) { - if ( is_null($dompdf) ) { - throw new DOMPDF_Exception("The DOMPDF argument is required"); - } - - $style = $frame->get_style(); - - // Floating (and more generally out-of-flow) elements are blocks - // http://coding.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/ - if ( !$frame->is_in_flow() && in_array($style->display, Style::$INLINE_TYPES)) { - $style->display = "block"; - } - - $display = $style->display; - - switch ($display) { - - case "block": - $positioner = "Block"; - $decorator = "Block"; - $reflower = "Block"; - break; - - case "inline-block": - $positioner = "Inline"; - $decorator = "Block"; - $reflower = "Block"; - break; - - case "inline": - $positioner = "Inline"; - if ( $frame->is_text_node() ) { - $decorator = "Text"; - $reflower = "Text"; - } - else { - $enable_css_float = $dompdf->get_option("enable_css_float"); - if ( $enable_css_float && $style->float !== "none" ) { - $decorator = "Block"; - $reflower = "Block"; - } - else { - $decorator = "Inline"; - $reflower = "Inline"; - } - } - break; - - case "table": - $positioner = "Block"; - $decorator = "Table"; - $reflower = "Table"; - break; - - case "inline-table": - $positioner = "Inline"; - $decorator = "Table"; - $reflower = "Table"; - break; - - case "table-row-group": - case "table-header-group": - case "table-footer-group": - $positioner = "Null"; - $decorator = "Table_Row_Group"; - $reflower = "Table_Row_Group"; - break; - - case "table-row": - $positioner = "Null"; - $decorator = "Table_Row"; - $reflower = "Table_Row"; - break; - - case "table-cell": - $positioner = "Table_Cell"; - $decorator = "Table_Cell"; - $reflower = "Table_Cell"; - break; - - case "list-item": - $positioner = "Block"; - $decorator = "Block"; - $reflower = "Block"; - break; - - case "-dompdf-list-bullet": - if ( $style->list_style_position === "inside" ) { - $positioner = "Inline"; - } - else { - $positioner = "List_Bullet"; - } - - if ( $style->list_style_image !== "none" ) { - $decorator = "List_Bullet_Image"; - } - else { - $decorator = "List_Bullet"; - } - - $reflower = "List_Bullet"; - break; - - case "-dompdf-image": - $positioner = "Inline"; - $decorator = "Image"; - $reflower = "Image"; - break; - - case "-dompdf-br": - $positioner = "Inline"; - $decorator = "Inline"; - $reflower = "Inline"; - break; - - default: - // FIXME: should throw some sort of warning or something? - case "none": - if ( $style->_dompdf_keep !== "yes" ) { - // Remove the node and the frame - $frame->get_parent()->remove_child($frame); - return; - } - - $positioner = "Null"; - $decorator = "Null"; - $reflower = "Null"; - break; - } - - // Handle CSS position - $position = $style->position; - - if ( $position === "absolute" ) { - $positioner = "Absolute"; - } - else if ( $position === "fixed" ) { - $positioner = "Fixed"; - } - - $node = $frame->get_node(); - - // Handle nodeName - if ( $node->nodeName === "img" ) { - $style->display = "-dompdf-image"; - $decorator = "Image"; - $reflower = "Image"; - } - - $positioner .= "_Positioner"; - $decorator .= "_Frame_Decorator"; - $reflower .= "_Frame_Reflower"; - - $deco = new $decorator($frame, $dompdf); - - $deco->set_positioner( new $positioner($deco) ); - $deco->set_reflower( new $reflower($deco) ); - - if ( $root ) { - $deco->set_root($root); - } - - if ( $display === "list-item" ) { - // Insert a list-bullet frame - $xml = $dompdf->get_dom(); - $bullet_node = $xml->createElement("bullet"); // arbitrary choice - $b_f = new Frame($bullet_node); - - $node = $frame->get_node(); - $parent_node = $node->parentNode; - - if ( $parent_node ) { - if ( !$parent_node->hasAttribute("dompdf-children-count") ) { - $xpath = new DOMXPath($xml); - $count = $xpath->query("li", $parent_node)->length; - $parent_node->setAttribute("dompdf-children-count", $count); - } - - if ( is_numeric($node->getAttribute("value")) ) { - $index = intval($node->getAttribute("value")); - } - else { - if ( !$parent_node->hasAttribute("dompdf-counter") ) { - $index = ($parent_node->hasAttribute("start") ? $parent_node->getAttribute("start") : 1); - } - else { - $index = $parent_node->getAttribute("dompdf-counter")+1; - } - } - - $parent_node->setAttribute("dompdf-counter", $index); - $bullet_node->setAttribute("dompdf-counter", $index); - } - - $new_style = $dompdf->get_css()->create_style(); - $new_style->display = "-dompdf-list-bullet"; - $new_style->inherit($style); - $b_f->set_style($new_style); - - $deco->prepend_child( Frame_Factory::decorate_frame($b_f, $dompdf, $root) ); - } - - return $deco; - } -} diff --git a/application/helpers/dompdf/include/frame_reflower.cls.php b/application/helpers/dompdf/include/frame_reflower.cls.php deleted file mode 100755 index 576039e1f..000000000 --- a/application/helpers/dompdf/include/frame_reflower.cls.php +++ /dev/null @@ -1,458 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Base reflower class - * - * Reflower objects are responsible for determining the width and height of - * individual frames. They also create line and page breaks as necessary. - * - * @access private - * @package dompdf - */ -abstract class Frame_Reflower { - - /** - * Frame for this reflower - * - * @var Frame - */ - protected $_frame; - - /** - * Cached min/max size - * - * @var array - */ - protected $_min_max_cache; - - function __construct(Frame $frame) { - $this->_frame = $frame; - $this->_min_max_cache = null; - } - - function dispose() { - clear_object($this); - } - - /** - * @return DOMPDF - */ - function get_dompdf() { - return $this->_frame->get_dompdf(); - } - - /** - * Collapse frames margins - * http://www.w3.org/TR/CSS2/box.html#collapsing-margins - */ - protected function _collapse_margins() { - $frame = $this->_frame; - $cb = $frame->get_containing_block(); - $style = $frame->get_style(); - - if ( !$frame->is_in_flow() ) { - return; - } - - $t = $style->length_in_pt($style->margin_top, $cb["h"]); - $b = $style->length_in_pt($style->margin_bottom, $cb["h"]); - - // Handle 'auto' values - if ( $t === "auto" ) { - $style->margin_top = "0pt"; - $t = 0; - } - - if ( $b === "auto" ) { - $style->margin_bottom = "0pt"; - $b = 0; - } - - // Collapse vertical margins: - $n = $frame->get_next_sibling(); - if ( $n && !$n->is_block() ) { - while ( $n = $n->get_next_sibling() ) { - if ( $n->is_block() ) { - break; - } - - if ( !$n->get_first_child() ) { - $n = null; - break; - } - } - } - - if ( $n ) { - $n_style = $n->get_style(); - $b = max($b, $n_style->length_in_pt($n_style->margin_top, $cb["h"])); - $n_style->margin_top = "0pt"; - $style->margin_bottom = $b."pt"; - } - - // Collapse our first child's margin - /*$f = $this->_frame->get_first_child(); - if ( $f && !$f->is_block() ) { - while ( $f = $f->get_next_sibling() ) { - if ( $f->is_block() ) { - break; - } - - if ( !$f->get_first_child() ) { - $f = null; - break; - } - } - } - - // Margin are collapsed only between block elements - if ( $f ) { - $f_style = $f->get_style(); - $t = max($t, $f_style->length_in_pt($f_style->margin_top, $cb["h"])); - $style->margin_top = $t."pt"; - $f_style->margin_bottom = "0pt"; - }*/ - } - - //........................................................................ - - abstract function reflow(Block_Frame_Decorator $block = null); - - //........................................................................ - - // Required for table layout: Returns an array(0 => min, 1 => max, "min" - // => min, "max" => max) of the minimum and maximum widths of this frame. - // This provides a basic implementation. Child classes should override - // this if necessary. - 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" && !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); - } - - /** - * Parses a CSS string containing quotes and escaped hex characters - * - * @param $string string The CSS string to parse - * @param $single_trim - * @return string - */ - protected function _parse_string($string, $single_trim = false) { - if ( $single_trim ) { - $string = preg_replace('/^[\"\']/', "", $string); - $string = preg_replace('/[\"\']$/', "", $string); - } - else { - $string = trim($string, "'\""); - } - - $string = str_replace(array("\\\n",'\\"',"\\'"), - array("",'"',"'"), $string); - - // Convert escaped hex characters into ascii characters (e.g. \A => newline) - $string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/", - create_function('$matches', - 'return unichr(hexdec($matches[1]));'), - $string); - return $string; - } - - /** - * Parses a CSS "quotes" property - * - * @return array|null An array of pairs of quotes - */ - protected function _parse_quotes() { - - // Matches quote types - $re = '/(\'[^\']*\')|(\"[^\"]*\")/'; - - $quotes = $this->_frame->get_style()->quotes; - - // split on spaces, except within quotes - if ( !preg_match_all($re, "$quotes", $matches, PREG_SET_ORDER) ) { - return null; - } - - $quotes_array = array(); - foreach($matches as &$_quote){ - $quotes_array[] = $this->_parse_string($_quote[0], true); - } - - if ( empty($quotes_array) ) { - $quotes_array = array('"', '"'); - } - - return array_chunk($quotes_array, 2); - } - - /** - * Parses the CSS "content" property - * - * @return string|null The resulting string - */ - protected function _parse_content() { - - // Matches generated content - $re = "/\n". - "\s(counters?\\([^)]*\\))|\n". - "\A(counters?\\([^)]*\\))|\n". - "\s([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?_frame->get_style()->content; - - $quotes = $this->_parse_quotes(); - - // split on spaces, except within quotes - if ( !preg_match_all($re, $content, $matches, PREG_SET_ORDER) ) { - return null; - } - - $text = ""; - - foreach ($matches as $match) { - - if ( isset($match[2]) && $match[2] !== "" ) { - $match[1] = $match[2]; - } - - if ( isset($match[6]) && $match[6] !== "" ) { - $match[4] = $match[6]; - } - - if ( isset($match[8]) && $match[8] !== "" ) { - $match[7] = $match[8]; - } - - if ( isset($match[1]) && $match[1] !== "" ) { - - // counters?(...) - $match[1] = mb_strtolower(trim($match[1])); - - // Handle counter() references: - // http://www.w3.org/TR/CSS21/generate.html#content - - $i = mb_strpos($match[1], ")"); - if ( $i === false ) { - continue; - } - - preg_match( '/(counters?)(^\()*?\(\s*([^\s,]+)\s*(,\s*["\']?([^"\'\)]+)["\']?\s*(,\s*([^\s)]+)\s*)?)?\)/i' , $match[1] , $args ); - $counter_id = $args[3]; - if ( strtolower( $args[1] ) == 'counter' ) { - // counter(name [,style]) - if ( isset( $args[5] ) ) { - $type = trim( $args[5] ); - } - else { - $type = null; - } - $p = $this->_frame->lookup_counter_frame( $counter_id ); - - $text .= $p->counter_value($counter_id, $type); - - } - else if ( strtolower( $args[1] ) == 'counters' ) { - // counters(name, string [,style]) - if ( isset($args[5]) ) { - $string = $this->_parse_string( $args[5] ); - } - else { - $string = ""; - } - - if ( isset( $args[7] ) ) { - $type = trim( $args[7] ); - } - else { - $type = null; - } - - $p = $this->_frame->lookup_counter_frame($counter_id); - $tmp = array(); - while ($p) { - // We only want to use the counter values when they actually increment the counter - if ( array_key_exists( $counter_id , $p->_counters ) ) { - array_unshift( $tmp , $p->counter_value($counter_id, $type) ); - } - $p = $p->lookup_counter_frame($counter_id); - - } - $text .= implode( $string , $tmp ); - - } - else { - // countertops? - continue; - } - - } - else if ( isset($match[4]) && $match[4] !== "" ) { - // String match - $text .= $this->_parse_string($match[4]); - } - else if ( isset($match[7]) && $match[7] !== "" ) { - // Directive match - - if ( $match[7] === "open-quote" ) { - // FIXME: do something here - $text .= $quotes[0][0]; - } - else if ( $match[7] === "close-quote" ) { - // FIXME: do something else here - $text .= $quotes[0][1]; - } - else if ( $match[7] === "no-open-quote" ) { - // FIXME: - } - else if ( $match[7] === "no-close-quote" ) { - // FIXME: - } - else if ( mb_strpos($match[7],"attr(") === 0 ) { - - $i = mb_strpos($match[7],")"); - if ( $i === false ) { - continue; - } - - $attr = mb_substr($match[7], 5, $i - 5); - if ( $attr == "" ) { - continue; - } - - $text .= $this->_frame->get_parent()->get_node()->getAttribute($attr); - } - else { - continue; - } - } - } - - return $text; - } - - /** - * Sets the generated content of a generated frame - */ - protected function _set_content(){ - $frame = $this->_frame; - $style = $frame->get_style(); - - // if the element was pushed to a new page use the saved counter value, otherwise use the CSS reset value - if ( $style->counter_reset && ($reset = $style->counter_reset) !== "none" ) { - $vars = preg_split('/\s+/', trim($reset), 2); - $frame->reset_counter( $vars[0] , ( isset($frame->_counters['__'.$vars[0]]) ? $frame->_counters['__'.$vars[0]] : ( isset($vars[1]) ? $vars[1] : 0 ) ) ); - } - - if ( $style->counter_increment && ($increment = $style->counter_increment) !== "none" ) { - $frame->increment_counters($increment); - } - - if ( $style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated" ) { - $content = $this->_parse_content(); - // add generated content to the font subset - // FIXME: This is currently too late because the font subset has already been generated. - // See notes in issue #750. - if ( $frame->get_dompdf()->get_option("enable_font_subsetting") && $frame->get_dompdf()->get_canvas() instanceof CPDF_Adapter ) { - $frame->get_dompdf()->get_canvas()->register_string_subset($style->font_family, $content); - } - - $node = $frame->get_node()->ownerDocument->createTextNode($content); - - $new_style = $style->get_stylesheet()->create_style(); - $new_style->inherit($style); - - $new_frame = new Frame($node); - $new_frame->set_style($new_style); - - Frame_Factory::decorate_frame($new_frame, $frame->get_dompdf(), $frame->get_root()); - $frame->append_child($new_frame); - } - } -} diff --git a/application/helpers/dompdf/include/frame_tree.cls.php b/application/helpers/dompdf/include/frame_tree.cls.php deleted file mode 100755 index 257ca097e..000000000 --- a/application/helpers/dompdf/include/frame_tree.cls.php +++ /dev/null @@ -1,241 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Represents an entire document as a tree of frames - * - * The Frame_Tree consists of {@link Frame} objects each tied to specific - * DOMNode objects in a specific DomDocument. The Frame_Tree has the same - * structure as the DomDocument, but adds additional capabalities for - * styling and layout. - * - * @package dompdf - * @access protected - */ -class Frame_Tree { - - /** - * Tags to ignore while parsing the tree - * - * @var array - */ - static protected $_HIDDEN_TAGS = array("area", "base", "basefont", "head", "style", - "meta", "title", "colgroup", - "noembed", "noscript", "param", "#comment"); - /** - * The main DomDocument - * - * @see http://ca2.php.net/manual/en/ref.dom.php - * @var DomDocument - */ - protected $_dom; - - /** - * The root node of the FrameTree. - * - * @var Frame - */ - protected $_root; - - /** - * Subtrees of absolutely positioned elements - * - * @var array of Frames - */ - protected $_absolute_frames; - - /** - * A mapping of {@link Frame} objects to DOMNode objects - * - * @var array - */ - protected $_registry; - - - /** - * Class constructor - * - * @param DomDocument $dom the main DomDocument object representing the current html document - */ - function __construct(DomDocument $dom) { - $this->_dom = $dom; - $this->_root = null; - $this->_registry = array(); - } - - function __destruct() { - clear_object($this); - } - - /** - * Returns the DomDocument object representing the curent html document - * - * @return DOMDocument - */ - function get_dom() { - return $this->_dom; - } - - /** - * Returns the root frame of the tree - * - * @return Page_Frame_Decorator - */ - function get_root() { - return $this->_root; - } - - /** - * Returns a specific frame given its id - * - * @param string $id - * @return Frame - */ - function get_frame($id) { - return isset($this->_registry[$id]) ? $this->_registry[$id] : null; - } - - /** - * Returns a post-order iterator for all frames in the tree - * - * @return FrameTreeList|Frame[] - */ - function get_frames() { - return new FrameTreeList($this->_root); - } - - /** - * Builds the tree - */ - function build_tree() { - $html = $this->_dom->getElementsByTagName("html")->item(0); - if ( is_null($html) ) { - $html = $this->_dom->firstChild; - } - - if ( is_null($html) ) { - throw new DOMPDF_Exception("Requested HTML document contains no data."); - } - - $this->fix_tables(); - - $this->_root = $this->_build_tree_r($html); - } - - /** - * Adds missing TBODYs around TR - */ - protected function fix_tables(){ - $xp = new DOMXPath($this->_dom); - - // Move table caption before the table - // FIXME find a better way to deal with it... - $captions = $xp->query("//table/caption"); - foreach($captions as $caption) { - $table = $caption->parentNode; - $table->parentNode->insertBefore($caption, $table); - } - - $rows = $xp->query("//table/tr"); - foreach($rows as $row) { - $tbody = $this->_dom->createElement("tbody"); - $tbody = $row->parentNode->insertBefore($tbody, $row); - $tbody->appendChild($row); - } - } - - /** - * Recursively adds {@link Frame} objects to the tree - * - * Recursively build a tree of Frame objects based on a dom tree. - * No layout information is calculated at this time, although the - * tree may be adjusted (i.e. nodes and frames for generated content - * and images may be created). - * - * @param DOMNode $node the current DOMNode being considered - * @return Frame - */ - protected function _build_tree_r(DOMNode $node) { - - $frame = new Frame($node); - $id = $frame->get_id(); - $this->_registry[ $id ] = $frame; - - if ( !$node->hasChildNodes() ) { - return $frame; - } - - // Fixes 'cannot access undefined property for object with - // overloaded access', fix by Stefan radulian - // - //foreach ($node->childNodes as $child) { - - // Store the children in an array so that the tree can be modified - $children = array(); - for ($i = 0; $i < $node->childNodes->length; $i++) { - $children[] = $node->childNodes->item($i); - } - - foreach ($children as $child) { - $node_name = mb_strtolower($child->nodeName); - - // Skip non-displaying nodes - if ( in_array($node_name, self::$_HIDDEN_TAGS) ) { - if ( $node_name !== "head" && $node_name !== "style" ) { - $child->parentNode->removeChild($child); - } - - continue; - } - - // Skip empty text nodes - if ( $node_name === "#text" && $child->nodeValue == "" ) { - $child->parentNode->removeChild($child); - continue; - } - - // Skip empty image nodes - if ( $node_name === "img" && $child->getAttribute("src") == "" ) { - $child->parentNode->removeChild($child); - continue; - } - - $frame->append_child($this->_build_tree_r($child), false); - } - - return $frame; - } - - public function insert_node(DOMNode $node, DOMNode $new_node, $pos) { - if ( $pos === "after" || !$node->firstChild ) { - $node->appendChild($new_node); - } - else { - $node->insertBefore($new_node, $node->firstChild); - } - - $this->_build_tree_r($new_node); - - $frame_id = $new_node->getAttribute("frame_id"); - $frame = $this->get_frame($frame_id); - - $parent_id = $node->getAttribute("frame_id"); - $parent = $this->get_frame($parent_id); - - if ( $parent ) { - if ( $pos === "before" ) { - $parent->prepend_child($frame, false); - } - else { - $parent->append_child($frame, false); - } - } - - return $frame_id; - } -} diff --git a/application/helpers/dompdf/include/functions.inc.php b/application/helpers/dompdf/include/functions.inc.php deleted file mode 100755 index 8e0ab02c7..000000000 --- a/application/helpers/dompdf/include/functions.inc.php +++ /dev/null @@ -1,1054 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -if ( !defined('PHP_VERSION_ID') ) { - $version = explode('.', PHP_VERSION); - define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); -} - -/** - * Defined a constant if not already defined - * - * @param string $name The constant name - * @param mixed $value The value - */ -function def($name, $value = true) { - if ( !defined($name) ) { - define($name, $value); - } -} - -if ( !function_exists("pre_r") ) { -/** - * print_r wrapper for html/cli output - * - * Wraps print_r() output in < pre > tags if the current sapi is not 'cli'. - * Returns the output string instead of displaying it if $return is true. - * - * @param mixed $mixed variable or expression to display - * @param bool $return - * - * @return string - */ -function pre_r($mixed, $return = false) { - if ( $return ) { - return "
" . print_r($mixed, true) . "
"; - } - - if ( php_sapi_name() !== "cli" ) { - echo "
";
-  }
-  
-  print_r($mixed);
-
-  if ( php_sapi_name() !== "cli" ) {
-    echo "
"; - } - else { - echo "\n"; - } - - flush(); - -} -} - -if ( !function_exists("pre_var_dump") ) { -/** - * var_dump wrapper for html/cli output - * - * Wraps var_dump() output in < pre > tags if the current sapi is not 'cli'. - * - * @param mixed $mixed variable or expression to display. - */ -function pre_var_dump($mixed) { - if ( php_sapi_name() !== "cli" ) { - echo "
";
-  }
-    
-  var_dump($mixed);
-  
-  if ( php_sapi_name() !== "cli" ) {
-    echo "
"; - } -} -} - -if ( !function_exists("d") ) { -/** - * generic debug function - * - * Takes everything and does its best to give a good debug output - * - * @param mixed $mixed variable or expression to display. - */ -function d($mixed) { - if ( php_sapi_name() !== "cli" ) { - echo "
";
-  }
-    
-  // line
-  if ( $mixed instanceof Line_Box ) {
-    echo $mixed;
-  }
-  
-  // other
-  else {
-    var_export($mixed);
-  }
-  
-  if ( php_sapi_name() !== "cli" ) {
-    echo "
"; - } -} -} - -/** - * builds a full url given a protocol, hostname, base path and url - * - * @param string $protocol - * @param string $host - * @param string $base_path - * @param string $url - * @return string - * - * Initially the trailing slash of $base_path was optional, and conditionally appended. - * However on dynamically created sites, where the page is given as url parameter, - * the base path might not end with an url. - * Therefore do not append a slash, and **require** the $base_url to ending in a slash - * when needed. - * Vice versa, on using the local file system path of a file, make sure that the slash - * is appended (o.k. also for Windows) - */ -function build_url($protocol, $host, $base_path, $url) { - if ( strlen($url) == 0 ) { - //return $protocol . $host . rtrim($base_path, "/\\") . "/"; - return $protocol . $host . $base_path; - } - - // Is the url already fully qualified or a Data URI? - if ( mb_strpos($url, "://") !== false || mb_strpos($url, "data:") === 0 ) { - return $url; - } - - $ret = $protocol; - - if ( !in_array(mb_strtolower($protocol), array("http://", "https://", "ftp://", "ftps://")) ) { - //On Windows local file, an abs path can begin also with a '\' or a drive letter and colon - //drive: followed by a relative path would be a drive specific default folder. - //not known in php app code, treat as abs path - //($url[1] !== ':' || ($url[2]!=='\\' && $url[2]!=='/')) - if ( $url[0] !== '/' && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || ($url[0] !== '\\' && $url[1] !== ':')) ) { - // For rel path and local acess we ignore the host, and run the path through realpath() - $ret .= realpath($base_path).'/'; - } - $ret .= $url; - $ret = preg_replace('/\?(.*)$/', "", $ret); - return $ret; - } - - //remote urls with backslash in html/css are not really correct, but lets be genereous - if ( $url[0] === '/' || $url[0] === '\\' ) { - // Absolute path - $ret .= $host . $url; - } - else { - // Relative path - //$base_path = $base_path !== "" ? rtrim($base_path, "/\\") . "/" : ""; - $ret .= $host . $base_path . $url; - } - - return $ret; - -} - -/** - * parse a full url or pathname and return an array(protocol, host, path, - * file + query + fragment) - * - * @param string $url - * @return array - */ -function explode_url($url) { - $protocol = ""; - $host = ""; - $path = ""; - $file = ""; - - $arr = parse_url($url); - - // Exclude windows drive letters... - if ( isset($arr["scheme"]) && $arr["scheme"] !== "file" && strlen($arr["scheme"]) > 1 ) { - $protocol = $arr["scheme"] . "://"; - - if ( isset($arr["user"]) ) { - $host .= $arr["user"]; - - if ( isset($arr["pass"]) ) { - $host .= ":" . $arr["pass"]; - } - - $host .= "@"; - } - - if ( isset($arr["host"]) ) { - $host .= $arr["host"]; - } - - if ( isset($arr["port"]) ) { - $host .= ":" . $arr["port"]; - } - - if ( isset($arr["path"]) && $arr["path"] !== "" ) { - // Do we have a trailing slash? - if ( $arr["path"][ mb_strlen($arr["path"]) - 1 ] === "/" ) { - $path = $arr["path"]; - $file = ""; - } - else { - $path = rtrim(dirname($arr["path"]), '/\\') . "/"; - $file = basename($arr["path"]); - } - } - - if ( isset($arr["query"]) ) { - $file .= "?" . $arr["query"]; - } - - if ( isset($arr["fragment"]) ) { - $file .= "#" . $arr["fragment"]; - } - - } - else { - - $i = mb_strpos($url, "file://"); - if ( $i !== false ) { - $url = mb_substr($url, $i + 7); - } - - $protocol = ""; // "file://"; ? why doesn't this work... It's because of - // network filenames like //COMPU/SHARENAME - - $host = ""; // localhost, really - $file = basename($url); - - $path = dirname($url); - - // Check that the path exists - if ( $path !== false ) { - $path .= '/'; - - } - else { - // generate a url to access the file if no real path found. - $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://'; - - $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : php_uname("n"); - - if ( substr($arr["path"], 0, 1) === '/' ) { - $path = dirname($arr["path"]); - } - else { - $path = '/' . rtrim(dirname($_SERVER["SCRIPT_NAME"]), '/') . '/' . $arr["path"]; - } - } - } - - $ret = array($protocol, $host, $path, $file, - "protocol" => $protocol, - "host" => $host, - "path" => $path, - "file" => $file); - return $ret; -} - -/** - * Converts decimal numbers to roman numerals - * - * @param int $num - * - * @throws DOMPDF_Exception - * @return string - */ -function dec2roman($num) { - - static $ones = array("", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"); - static $tens = array("", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"); - static $hund = array("", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"); - static $thou = array("", "m", "mm", "mmm"); - - if ( !is_numeric($num) ) { - throw new DOMPDF_Exception("dec2roman() requires a numeric argument."); - } - - if ( $num > 4000 || $num < 0 ) { - return "(out of range)"; - } - - $num = strrev((string)$num); - - $ret = ""; - switch (mb_strlen($num)) { - case 4: $ret .= $thou[$num[3]]; - case 3: $ret .= $hund[$num[2]]; - case 2: $ret .= $tens[$num[1]]; - case 1: $ret .= $ones[$num[0]]; - default: break; - } - - return $ret; -} - -/** - * Determines whether $value is a percentage or not - * - * @param float $value - * - * @return bool - */ -function is_percent($value) { - return false !== mb_strpos($value, "%"); -} - -/** - * Parses a data URI scheme - * http://en.wikipedia.org/wiki/Data_URI_scheme - * - * @param string $data_uri The data URI to parse - * - * @return array The result with charset, mime type and decoded data - */ -function parse_data_uri($data_uri) { - if (!preg_match('/^data:(?P[a-z0-9\/+-.]+)(;charset=(?P[a-z0-9-])+)?(?P;base64)?\,(?P.*)?/i', $data_uri, $match)) { - return false; - } - - $match['data'] = rawurldecode($match['data']); - $result = array( - 'charset' => $match['charset'] ? $match['charset'] : 'US-ASCII', - 'mime' => $match['mime'] ? $match['mime'] : 'text/plain', - 'data' => $match['base64'] ? base64_decode($match['data']) : $match['data'], - ); - - return $result; -} - -/** - * mb_string compatibility - */ -if (!extension_loaded('mbstring')) { - def('MB_OVERLOAD_MAIL', 1); - def('MB_OVERLOAD_STRING', 2); - def('MB_OVERLOAD_REGEX', 4); - def('MB_CASE_UPPER', 0); - def('MB_CASE_LOWER', 1); - def('MB_CASE_TITLE', 2); - - if (!function_exists('mb_convert_encoding')) { - function mb_convert_encoding($data, $to_encoding, $from_encoding = 'UTF-8') { - if (str_replace('-', '', strtolower($to_encoding)) === 'utf8') { - return utf8_encode($data); - } - - return utf8_decode($data); - } - } - - if (!function_exists('mb_detect_encoding')) { - function mb_detect_encoding($data, $encoding_list = array('iso-8859-1'), $strict = false) { - return 'iso-8859-1'; - } - } - - if (!function_exists('mb_detect_order')) { - function mb_detect_order($encoding_list = array('iso-8859-1')) { - return 'iso-8859-1'; - } - } - - if (!function_exists('mb_internal_encoding')) { - function mb_internal_encoding($encoding = null) { - if (isset($encoding)) { - return true; - } - - return 'iso-8859-1'; - } - } - - if (!function_exists('mb_strlen')) { - function mb_strlen($str, $encoding = 'iso-8859-1') { - switch (str_replace('-', '', strtolower($encoding))) { - case "utf8": return strlen(utf8_encode($str)); - case "8bit": return strlen($str); - default: return strlen(utf8_decode($str)); - } - } - } - - if (!function_exists('mb_strpos')) { - function mb_strpos($haystack, $needle, $offset = 0) { - return strpos($haystack, $needle, $offset); - } - } - - if (!function_exists('mb_strrpos')) { - function mb_strrpos($haystack, $needle, $offset = 0) { - return strrpos($haystack, $needle, $offset); - } - } - - if (!function_exists('mb_strtolower')) { - function mb_strtolower( $str ) { - return strtolower($str); - } - } - - if (!function_exists('mb_strtoupper')) { - function mb_strtoupper( $str ) { - return strtoupper($str); - } - } - - if (!function_exists('mb_substr')) { - function mb_substr($string, $start, $length = null, $encoding = 'iso-8859-1') { - if ( is_null($length) ) { - return substr($string, $start); - } - - return substr($string, $start, $length); - } - } - - if (!function_exists('mb_substr_count')) { - function mb_substr_count($haystack, $needle, $encoding = 'iso-8859-1') { - return substr_count($haystack, $needle); - } - } - - if (!function_exists('mb_encode_numericentity')) { - function mb_encode_numericentity($str, $convmap, $encoding) { - return htmlspecialchars($str); - } - } - - if (!function_exists('mb_convert_case')) { - function mb_convert_case($str, $mode = MB_CASE_UPPER, $encoding = array()) { - switch($mode) { - case MB_CASE_UPPER: return mb_strtoupper($str); - case MB_CASE_LOWER: return mb_strtolower($str); - case MB_CASE_TITLE: return ucwords(mb_strtolower($str)); - default: return $str; - } - } - } - - if (!function_exists('mb_list_encodings')) { - function mb_list_encodings() { - return array( - "ISO-8859-1", - "UTF-8", - "8bit", - ); - } - } -} - -/** - * Decoder for RLE8 compression in windows bitmaps - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp - * - * @param string $str Data to decode - * @param integer $width Image width - * - * @return string - */ -function rle8_decode ($str, $width){ - $lineWidth = $width + (3 - ($width-1) % 4); - $out = ''; - $cnt = strlen($str); - - for ($i = 0; $i <$cnt; $i++) { - $o = ord($str[$i]); - switch ($o){ - case 0: # ESCAPE - $i++; - switch (ord($str[$i])){ - case 0: # NEW LINE - $padCnt = $lineWidth - strlen($out)%$lineWidth; - if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line - break; - case 1: # END OF FILE - $padCnt = $lineWidth - strlen($out)%$lineWidth; - if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line - break 3; - case 2: # DELTA - $i += 2; - break; - default: # ABSOLUTE MODE - $num = ord($str[$i]); - for ($j = 0; $j < $num; $j++) - $out .= $str[++$i]; - if ($num % 2) $i++; - } - break; - default: - $out .= str_repeat($str[++$i], $o); - } - } - return $out; -} - -/** - * Decoder for RLE4 compression in windows bitmaps - * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp - * - * @param string $str Data to decode - * @param integer $width Image width - * - * @return string - */ -function rle4_decode ($str, $width) { - $w = floor($width/2) + ($width % 2); - $lineWidth = $w + (3 - ( ($width-1) / 2) % 4); - $pixels = array(); - $cnt = strlen($str); - $c = 0; - - for ($i = 0; $i < $cnt; $i++) { - $o = ord($str[$i]); - switch ($o) { - case 0: # ESCAPE - $i++; - switch (ord($str[$i])){ - case 0: # NEW LINE - while (count($pixels)%$lineWidth != 0) { - $pixels[] = 0; - } - break; - case 1: # END OF FILE - while (count($pixels)%$lineWidth != 0) { - $pixels[] = 0; - } - break 3; - case 2: # DELTA - $i += 2; - break; - default: # ABSOLUTE MODE - $num = ord($str[$i]); - for ($j = 0; $j < $num; $j++) { - if ($j%2 == 0) { - $c = ord($str[++$i]); - $pixels[] = ($c & 240)>>4; - } - else { - $pixels[] = $c & 15; - } - } - - if ($num % 2 == 0) { - $i++; - } - } - break; - default: - $c = ord($str[++$i]); - for ($j = 0; $j < $o; $j++) { - $pixels[] = ($j%2==0 ? ($c & 240)>>4 : $c & 15); - } - } - } - - $out = ''; - if (count($pixels)%2) { - $pixels[] = 0; - } - - $cnt = count($pixels)/2; - - for ($i = 0; $i < $cnt; $i++) { - $out .= chr(16*$pixels[2*$i] + $pixels[2*$i+1]); - } - - return $out; -} - -if ( !function_exists("imagecreatefrombmp") ) { - -/** - * Credit goes to mgutt - * http://www.programmierer-forum.de/function-imagecreatefrombmp-welche-variante-laeuft-t143137.htm - * Modified by Fabien Menager to support RGB555 BMP format - */ -function imagecreatefrombmp($filename) { - if (!function_exists("imagecreatetruecolor")) { - trigger_error("The PHP GD extension is required, but is not installed.", E_ERROR); - return false; - } - - // version 1.00 - if (!($fh = fopen($filename, 'rb'))) { - trigger_error('imagecreatefrombmp: Can not open ' . $filename, E_USER_WARNING); - return false; - } - - $bytes_read = 0; - - // read file header - $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14)); - - // check for bitmap - if ($meta['type'] != 19778) { - trigger_error('imagecreatefrombmp: ' . $filename . ' is not a bitmap!', E_USER_WARNING); - return false; - } - - // read image header - $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40)); - $bytes_read += 40; - - // read additional bitfield header - if ($meta['compression'] == 3) { - $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12)); - $bytes_read += 12; - } - - // set bytes and padding - $meta['bytes'] = $meta['bits'] / 8; - $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4)- floor($meta['width'] * $meta['bytes'] / 4))); - if ($meta['decal'] == 4) { - $meta['decal'] = 0; - } - - // obtain imagesize - if ($meta['imagesize'] < 1) { - $meta['imagesize'] = $meta['filesize'] - $meta['offset']; - // in rare cases filesize is equal to offset so we need to read physical size - if ($meta['imagesize'] < 1) { - $meta['imagesize'] = @filesize($filename) - $meta['offset']; - if ($meta['imagesize'] < 1) { - trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING); - return false; - } - } - } - - // calculate colors - $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors']; - - // read color palette - $palette = array(); - if ($meta['bits'] < 16) { - $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4)); - // in rare cases the color value is signed - if ($palette[1] < 0) { - foreach ($palette as $i => $color) { - $palette[$i] = $color + 16777216; - } - } - } - - // ignore extra bitmap headers - if ($meta['headersize'] > $bytes_read) { - fread($fh, $meta['headersize'] - $bytes_read); - } - - // create gd image - $im = imagecreatetruecolor($meta['width'], $meta['height']); - $data = fread($fh, $meta['imagesize']); - - // uncompress data - switch ($meta['compression']) { - case 1: $data = rle8_decode($data, $meta['width']); break; - case 2: $data = rle4_decode($data, $meta['width']); break; - } - - $p = 0; - $vide = chr(0); - $y = $meta['height'] - 1; - $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!'; - - // loop through the image data beginning with the lower left corner - while ($y >= 0) { - $x = 0; - while ($x < $meta['width']) { - switch ($meta['bits']) { - case 32: - case 24: - if (!($part = substr($data, $p, 3 /*$meta['bytes']*/))) { - trigger_error($error, E_USER_WARNING); - return $im; - } - $color = unpack('V', $part . $vide); - break; - case 16: - if (!($part = substr($data, $p, 2 /*$meta['bytes']*/))) { - trigger_error($error, E_USER_WARNING); - return $im; - } - $color = unpack('v', $part); - - if (empty($meta['rMask']) || $meta['rMask'] != 0xf800) { - $color[1] = (($color[1] & 0x7c00) >> 7) * 65536 + (($color[1] & 0x03e0) >> 2) * 256 + (($color[1] & 0x001f) << 3); // 555 - } - else { - $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); // 565 - } - break; - case 8: - $color = unpack('n', $vide . substr($data, $p, 1)); - $color[1] = $palette[ $color[1] + 1 ]; - break; - case 4: - $color = unpack('n', $vide . substr($data, floor($p), 1)); - $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F; - $color[1] = $palette[ $color[1] + 1 ]; - break; - case 1: - $color = unpack('n', $vide . substr($data, floor($p), 1)); - switch (($p * 8) % 8) { - case 0: $color[1] = $color[1] >> 7; break; - case 1: $color[1] = ($color[1] & 0x40) >> 6; break; - case 2: $color[1] = ($color[1] & 0x20) >> 5; break; - case 3: $color[1] = ($color[1] & 0x10) >> 4; break; - case 4: $color[1] = ($color[1] & 0x8 ) >> 3; break; - case 5: $color[1] = ($color[1] & 0x4 ) >> 2; break; - case 6: $color[1] = ($color[1] & 0x2 ) >> 1; break; - case 7: $color[1] = ($color[1] & 0x1 ); break; - } - $color[1] = $palette[ $color[1] + 1 ]; - break; - default: - trigger_error('imagecreatefrombmp: ' . $filename . ' has ' . $meta['bits'] . ' bits and this is not supported!', E_USER_WARNING); - return false; - } - imagesetpixel($im, $x, $y, $color[1]); - $x++; - $p += $meta['bytes']; - } - $y--; - $p += $meta['decal']; - } - fclose($fh); - return $im; -} -} - -/** - * getimagesize doesn't give a good size for 32bit BMP image v5 - * - * @param string $filename - * @return array The same format as getimagesize($filename) - */ -function dompdf_getimagesize($filename) { - static $cache = array(); - - if ( isset($cache[$filename]) ) { - return $cache[$filename]; - } - - list($width, $height, $type) = getimagesize($filename); - - if ( $width == null || $height == null ) { - $data = file_get_contents($filename, null, null, 0, 26); - - if ( substr($data, 0, 2) === "BM" ) { - $meta = unpack('vtype/Vfilesize/Vreserved/Voffset/Vheadersize/Vwidth/Vheight', $data); - $width = (int)$meta['width']; - $height = (int)$meta['height']; - $type = IMAGETYPE_BMP; - } - } - - return $cache[$filename] = array($width, $height, $type); -} - -/** - * Converts a CMYK color to RGB - * - * @param float|float[] $c - * @param float $m - * @param float $y - * @param float $k - * - * @return float[] - */ -function cmyk_to_rgb($c, $m = null, $y = null, $k = null) { - if (is_array($c)) { - list($c, $m, $y, $k) = $c; - } - - $c *= 255; - $m *= 255; - $y *= 255; - $k *= 255; - - $r = (1 - round(2.55 * ($c+$k))) ; - $g = (1 - round(2.55 * ($m+$k))) ; - $b = (1 - round(2.55 * ($y+$k))) ; - - if ($r < 0) $r = 0; - if ($g < 0) $g = 0; - if ($b < 0) $b = 0; - - return array( - $r, $g, $b, - "r" => $r, "g" => $g, "b" => $b - ); -} - -function unichr($c) { - if ($c <= 0x7F) { - return chr($c); - } - else if ($c <= 0x7FF) { - return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F); - } - else if ($c <= 0xFFFF) { - return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F) - . chr(0x80 | $c & 0x3F); - } - else if ($c <= 0x10FFFF) { - return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F) - . chr(0x80 | $c >> 6 & 0x3F) - . chr(0x80 | $c & 0x3F); - } - return false; -} - -if ( !function_exists("date_default_timezone_get") ) { - function date_default_timezone_get() { - return ""; - } - - function date_default_timezone_set($timezone_identifier) { - return true; - } -} - -/** - * Stores warnings in an array for display later - * This function allows warnings generated by the DomDocument parser - * and CSS loader ({@link Stylesheet}) to be captured and displayed - * later. Without this function, errors are displayed immediately and - * PDF streaming is impossible. - * @see http://www.php.net/manual/en/function.set-error_handler.php - * - * @param int $errno - * @param string $errstr - * @param string $errfile - * @param string $errline - * - * @throws DOMPDF_Exception - */ -function record_warnings($errno, $errstr, $errfile, $errline) { - - // Not a warning or notice - if ( !($errno & (E_WARNING | E_NOTICE | E_USER_NOTICE | E_USER_WARNING )) ) { - throw new DOMPDF_Exception($errstr . " $errno"); - } - - global $_dompdf_warnings; - global $_dompdf_show_warnings; - - if ( $_dompdf_show_warnings ) { - echo $errstr . "\n"; - } - - $_dompdf_warnings[] = $errstr; -} - -/** - * Print a useful backtrace - */ -function bt() { - if ( php_sapi_name() !== "cli") { - echo "
";
-  }
-    
-  $bt = debug_backtrace();
-
-  array_shift($bt); // remove actual bt() call
-  echo "\n";
-
-  $i = 0;
-  foreach ($bt as $call) {
-    $file = basename($call["file"]) . " (" . $call["line"] . ")";
-    if ( isset($call["class"]) ) {
-      $func = $call["class"] . "->" . $call["function"] . "()";
-    }
-    else {
-      $func = $call["function"] . "()";
-    }
-
-    echo "#" . str_pad($i, 2, " ", STR_PAD_RIGHT) . ": " . str_pad($file.":", 42) . " $func\n";
-    $i++;
-  }
-  echo "\n";
-  
-  if ( php_sapi_name() !== "cli") {
-    echo "
"; - } -} - -/** - * Print debug messages - * - * @param string $type The type of debug messages to print - * @param string $msg The message to show - */ -function dompdf_debug($type, $msg) { - global $_DOMPDF_DEBUG_TYPES, $_dompdf_show_warnings, $_dompdf_debug; - if ( isset($_DOMPDF_DEBUG_TYPES[$type]) && ($_dompdf_show_warnings || $_dompdf_debug) ) { - $arr = debug_backtrace(); - - echo basename($arr[0]["file"]) . " (" . $arr[0]["line"] ."): " . $arr[1]["function"] . ": "; - pre_r($msg); - } -} - -if ( !function_exists("print_memusage") ) { -/** - * Dump memory usage - */ -function print_memusage() { - global $memusage; - echo "Memory Usage\n"; - $prev = 0; - $initial = reset($memusage); - echo str_pad("Initial:", 40) . $initial . "\n\n"; - - foreach ($memusage as $key=>$mem) { - $mem -= $initial; - echo str_pad("$key:" , 40); - echo str_pad("$mem", 12) . "(diff: " . ($mem - $prev) . ")\n"; - $prev = $mem; - } - - echo "\n" . str_pad("Total:", 40) . memory_get_usage() . "\n"; -} -} - -if ( !function_exists("enable_mem_profile") ) { -/** - * Initialize memory profiling code - */ -function enable_mem_profile() { - global $memusage; - $memusage = array("Startup" => memory_get_usage()); - register_shutdown_function("print_memusage"); -} -} - -if ( !function_exists("mark_memusage") ) { -/** - * Record the current memory usage - * - * @param string $location a meaningful location - */ -function mark_memusage($location) { - global $memusage; - if ( isset($memusage) ) { - $memusage[$location] = memory_get_usage(); - } -} -} - -if ( !function_exists('sys_get_temp_dir')) { -/** - * Find the current system temporary directory - * - * @link http://us.php.net/manual/en/function.sys-get-temp-dir.php#85261 - */ -function sys_get_temp_dir() { - if (!empty($_ENV['TMP'])) { - return realpath($_ENV['TMP']); - } - - if (!empty($_ENV['TMPDIR'])) { - return realpath( $_ENV['TMPDIR']); - } - - if (!empty($_ENV['TEMP'])) { - return realpath( $_ENV['TEMP']); - } - - $tempfile=tempnam(uniqid(rand(), true), ''); - if (file_exists($tempfile)) { - unlink($tempfile); - return realpath(dirname($tempfile)); - } -} -} - -if ( function_exists("memory_get_peak_usage") ) { - function DOMPDF_memory_usage(){ - return memory_get_peak_usage(true); - } -} -else if ( function_exists("memory_get_usage") ) { - function DOMPDF_memory_usage(){ - return memory_get_usage(true); - } -} -else { - function DOMPDF_memory_usage(){ - return "N/A"; - } -} - -if ( function_exists("curl_init") ) { - function DOMPDF_fetch_url($url, &$headers = null) { - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_TIMEOUT, 10); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HEADER, true); - - $data = curl_exec($ch); - $raw_headers = substr($data, 0, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); - $headers = preg_split("/[\n\r]+/", trim($raw_headers)); - $data = substr($data, curl_getinfo($ch, CURLINFO_HEADER_SIZE)); - curl_close($ch); - - return $data; - } -} -else { - function DOMPDF_fetch_url($url, &$headers = null) { - $data = file_get_contents($url); - $headers = $http_response_header; - - return $data; - } -} - -/** - * Affect null to the unused objects - * @param mixed $object - */ -if ( PHP_VERSION_ID < 50300 ) { - function clear_object(&$object) { - if ( is_object($object) ) { - foreach ($object as &$value) { - clear_object($value); - } - } - - $object = null; - unset($object); - } -} -else { - function clear_object(&$object) { - // void - } -} diff --git a/application/helpers/dompdf/include/gd_adapter.cls.php b/application/helpers/dompdf/include/gd_adapter.cls.php deleted file mode 100755 index de5c1e452..000000000 --- a/application/helpers/dompdf/include/gd_adapter.cls.php +++ /dev/null @@ -1,840 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Image rendering interface - * - * Renders to an image format supported by GD (jpeg, gif, png, xpm). - * Not super-useful day-to-day but handy nonetheless - * - * @package dompdf - */ -class GD_Adapter implements Canvas { - /** - * @var DOMPDF - */ - private $_dompdf; - - /** - * Resource handle for the image - * - * @var resource - */ - private $_img; - - /** - * Image width in pixels - * - * @var int - */ - private $_width; - - /** - * Image height in pixels - * - * @var int - */ - private $_height; - - /** - * Current page number - * - * @var int - */ - private $_page_number; - - /** - * Total number of pages - * - * @var int - */ - private $_page_count; - - /** - * Image antialias factor - * - * @var float - */ - private $_aa_factor; - - /** - * Allocated colors - * - * @var array - */ - private $_colors; - - /** - * Background color - * - * @var int - */ - private $_bg_color; - - /** - * Class constructor - * - * @param mixed $size The size of image to create: array(x1,y1,x2,y2) or "letter", "legal", etc. - * @param string $orientation The orientation of the document (either 'landscape' or 'portrait') - * @param DOMPDF $dompdf - * @param float $aa_factor Anti-aliasing factor, 1 for no AA - * @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1 - */ - function __construct($size, $orientation = "portrait", DOMPDF $dompdf, $aa_factor = 1.0, $bg_color = array(1,1,1,0) ) { - - if ( !is_array($size) ) { - $size = strtolower($size); - - if ( isset(CPDF_Adapter::$PAPER_SIZES[$size]) ) { - $size = CPDF_Adapter::$PAPER_SIZES[$size]; - } - else { - $size = CPDF_Adapter::$PAPER_SIZES["letter"]; - } - } - - if ( strtolower($orientation) === "landscape" ) { - list($size[2],$size[3]) = array($size[3],$size[2]); - } - - $this->_dompdf = $dompdf; - - if ( $aa_factor < 1 ) { - $aa_factor = 1; - } - - $this->_aa_factor = $aa_factor; - - $size[2] *= $aa_factor; - $size[3] *= $aa_factor; - - $this->_width = $size[2] - $size[0]; - $this->_height = $size[3] - $size[1]; - - $this->_img = imagecreatetruecolor($this->_width, $this->_height); - - if ( is_null($bg_color) || !is_array($bg_color) ) { - // Pure white bg - $bg_color = array(1,1,1,0); - } - - $this->_bg_color = $this->_allocate_color($bg_color); - imagealphablending($this->_img, true); - imagesavealpha($this->_img, true); - imagefill($this->_img, 0, 0, $this->_bg_color); - - } - - function get_dompdf(){ - return $this->_dompdf; - } - - /** - * Return the GF image resource - * - * @return resource - */ - function get_image() { return $this->_img; } - - /** - * Return the image's width in pixels - * - * @return float - */ - function get_width() { return $this->_width / $this->_aa_factor; } - - /** - * Return the image's height in pixels - * - * @return float - */ - function get_height() { return $this->_height / $this->_aa_factor; } - - /** - * Returns the current page number - * @return int - */ - function get_page_number() { return $this->_page_number; } - - /** - * Returns the total number of pages in the document - * @return int - */ - function get_page_count() { return $this->_page_count; } - - /** - * Sets the current page number - * - * @param int $num - */ - function set_page_number($num) { $this->_page_number = $num; } - - /** - * Sets the page count - * - * @param int $count - */ - function set_page_count($count) { $this->_page_count = $count; } - - /** - * Sets the opacity - * - * @param $opacity - * @param $mode - */ - function set_opacity($opacity, $mode = "Normal") { - // FIXME - } - - /** - * Allocate a new color. Allocate with GD as needed and store - * previously allocated colors in $this->_colors. - * - * @param array $color The new current color - * @return int The allocated color - */ - private function _allocate_color($color) { - - if ( isset($color["c"]) ) { - $color = cmyk_to_rgb($color); - } - - // Full opacity if no alpha set - if ( !isset($color[3]) ) - $color[3] = 0; - - list($r,$g,$b,$a) = $color; - - $r *= 255; - $g *= 255; - $b *= 255; - $a *= 127; - - // Clip values - $r = $r > 255 ? 255 : $r; - $g = $g > 255 ? 255 : $g; - $b = $b > 255 ? 255 : $b; - $a = $a > 127 ? 127 : $a; - - $r = $r < 0 ? 0 : $r; - $g = $g < 0 ? 0 : $g; - $b = $b < 0 ? 0 : $b; - $a = $a < 0 ? 0 : $a; - - $key = sprintf("#%02X%02X%02X%02X", $r, $g, $b, $a); - - if ( isset($this->_colors[$key]) ) - return $this->_colors[$key]; - - if ( $a != 0 ) - $this->_colors[$key] = imagecolorallocatealpha($this->_img, $r, $g, $b, $a); - else - $this->_colors[$key] = imagecolorallocate($this->_img, $r, $g, $b); - - return $this->_colors[$key]; - - } - - /** - * Draws a line from x1,y1 to x2,y2 - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the format of the - * $style parameter (aka dash). - * - * @param float $x1 - * @param float $y1 - * @param float $x2 - * @param float $y2 - * @param array $color - * @param float $width - * @param array $style - */ - function line($x1, $y1, $x2, $y2, $color, $width, $style = null) { - - // Scale by the AA factor - $x1 *= $this->_aa_factor; - $y1 *= $this->_aa_factor; - $x2 *= $this->_aa_factor; - $y2 *= $this->_aa_factor; - $width *= $this->_aa_factor; - - $c = $this->_allocate_color($color); - - // Convert the style array if required - if ( !is_null($style) ) { - $gd_style = array(); - - if ( count($style) == 1 ) { - for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) { - $gd_style[] = $c; - } - - for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) { - $gd_style[] = $this->_bg_color; - } - - } else { - - $i = 0; - foreach ($style as $length) { - - if ( $i % 2 == 0 ) { - // 'On' pattern - for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) - $gd_style[] = $c; - - } else { - // Off pattern - for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) - $gd_style[] = $this->_bg_color; - - } - $i++; - } - } - - imagesetstyle($this->_img, $gd_style); - $c = IMG_COLOR_STYLED; - } - - imagesetthickness($this->_img, $width); - - imageline($this->_img, $x1, $y1, $x2, $y2, $c); - - } - - function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array()) { - // @todo - } - - /** - * Draws a rectangle at x1,y1 with width w and height h - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - * @param array $color - * @param float $width - * @param array $style - */ - function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) { - - // Scale by the AA factor - $x1 *= $this->_aa_factor; - $y1 *= $this->_aa_factor; - $w *= $this->_aa_factor; - $h *= $this->_aa_factor; - - $c = $this->_allocate_color($color); - - // Convert the style array if required - if ( !is_null($style) ) { - $gd_style = array(); - - foreach ($style as $length) { - for ($i = 0; $i < $length; $i++) { - $gd_style[] = $c; - } - } - - imagesetstyle($this->_img, $gd_style); - $c = IMG_COLOR_STYLED; - } - - imagesetthickness($this->_img, $width); - - imagerectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c); - - } - - /** - * Draws a filled rectangle at x1,y1 with width w and height h - * - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - * @param array $color - */ - function filled_rectangle($x1, $y1, $w, $h, $color) { - - // Scale by the AA factor - $x1 *= $this->_aa_factor; - $y1 *= $this->_aa_factor; - $w *= $this->_aa_factor; - $h *= $this->_aa_factor; - - $c = $this->_allocate_color($color); - - imagefilledrectangle($this->_img, $x1, $y1, $x1 + $w, $y1 + $h, $c); - - } - - /** - * Starts a clipping rectangle at x1,y1 with width w and height h - * - * @param float $x1 - * @param float $y1 - * @param float $w - * @param float $h - */ - function clipping_rectangle($x1, $y1, $w, $h) { - // @todo - } - - function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) { - // @todo - } - - /** - * Ends the last clipping shape - */ - function clipping_end() { - // @todo - } - - function save() { - // @todo - } - - function restore() { - // @todo - } - - function rotate($angle, $x, $y) { - // @todo - } - - function skew($angle_x, $angle_y, $x, $y) { - // @todo - } - - function scale($s_x, $s_y, $x, $y) { - // @todo - } - - function translate($t_x, $t_y) { - // @todo - } - - function transform($a, $b, $c, $d, $e, $f) { - // @todo - } - - /** - * Draws a polygon - * - * The polygon is formed by joining all the points stored in the $points - * array. $points has the following structure: - * - * array(0 => x1, - * 1 => y1, - * 2 => x2, - * 3 => y2, - * ... - * ); - * - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param array $points - * @param array $color - * @param float $width - * @param array $style - * @param bool $fill Fills the polygon if true - */ - function polygon($points, $color, $width = null, $style = null, $fill = false) { - - // Scale each point by the AA factor - foreach (array_keys($points) as $i) - $points[$i] *= $this->_aa_factor; - - $c = $this->_allocate_color($color); - - // Convert the style array if required - if ( !is_null($style) && !$fill ) { - $gd_style = array(); - - foreach ($style as $length) { - for ($i = 0; $i < $length; $i++) { - $gd_style[] = $c; - } - } - - imagesetstyle($this->_img, $gd_style); - $c = IMG_COLOR_STYLED; - } - - imagesetthickness($this->_img, $width); - - if ( $fill ) - imagefilledpolygon($this->_img, $points, count($points) / 2, $c); - else - imagepolygon($this->_img, $points, count($points) / 2, $c); - - } - - /** - * Draws a circle at $x,$y with radius $r - * - * See {@link Style::munge_color()} for the format of the color array. - * See {@link Cpdf::setLineStyle()} for a description of the $style - * parameter (aka dash) - * - * @param float $x - * @param float $y - * @param float $r - * @param array $color - * @param float $width - * @param array $style - * @param bool $fill Fills the circle if true - */ - function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) { - - // Scale by the AA factor - $x *= $this->_aa_factor; - $y *= $this->_aa_factor; - $r *= $this->_aa_factor; - - $c = $this->_allocate_color($color); - - // Convert the style array if required - if ( !is_null($style) && !$fill ) { - $gd_style = array(); - - foreach ($style as $length) { - for ($i = 0; $i < $length; $i++) { - $gd_style[] = $c; - } - } - - imagesetstyle($this->_img, $gd_style); - $c = IMG_COLOR_STYLED; - } - - imagesetthickness($this->_img, $width); - - if ( $fill ) - imagefilledellipse($this->_img, $x, $y, $r, $r, $c); - else - imageellipse($this->_img, $x, $y, $r, $r, $c); - - } - - /** - * Add an image to the pdf. - * The image is placed at the specified x and y coordinates with the - * given width and height. - * - * @param string $img_url the path to the image - * @param float $x x position - * @param float $y y position - * @param int $w width (in pixels) - * @param int $h height (in pixels) - * @param string $resolution - * - * @return void - * @internal param string $img_type the type (e.g. extension) of the image - */ - function image($img_url, $x, $y, $w, $h, $resolution = "normal") { - $img_type = Image_Cache::detect_type($img_url); - $img_ext = Image_Cache::type_to_ext($img_type); - - if ( !$img_ext ) { - return; - } - - $func = "imagecreatefrom$img_ext"; - $src = @$func($img_url); - - if ( !$src ) { - return; // Probably should add to $_dompdf_errors or whatever here - } - - // Scale by the AA factor - $x *= $this->_aa_factor; - $y *= $this->_aa_factor; - - $w *= $this->_aa_factor; - $h *= $this->_aa_factor; - - $img_w = imagesx($src); - $img_h = imagesy($src); - - imagecopyresampled($this->_img, $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h); - - } - - /** - * Writes text at the specified x and y coordinates - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x - * @param float $y - * @param string $text the text to write - * @param string $font the font file to use - * @param float $size the font size, in points - * @param array $color - * @param float $word_spacing word spacing adjustment - * @param float $char_spacing - * @param float $angle Text angle - * - * @return void - */ - function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0) { - - // Scale by the AA factor - $x *= $this->_aa_factor; - $y *= $this->_aa_factor; - $size *= $this->_aa_factor; - - $h = $this->get_font_height($font, $size); - $c = $this->_allocate_color($color); - - $text = mb_encode_numericentity($text, array(0x0080, 0xff, 0, 0xff), 'UTF-8'); - - $font = $this->get_ttf_file($font); - - // FIXME: word spacing - @imagettftext($this->_img, $size, $angle, $x, $y + $h, $c, $font, $text); - - } - - function javascript($code) { - // Not implemented - } - - /** - * Add a named destination (similar to ... in html) - * - * @param string $anchorname The name of the named destination - */ - function add_named_dest($anchorname) { - // Not implemented - } - - /** - * Add a link to the pdf - * - * @param string $url The url to link to - * @param float $x The x position of the link - * @param float $y The y position of the link - * @param float $width The width of the link - * @param float $height The height of the link - */ - function add_link($url, $x, $y, $width, $height) { - // Not implemented - } - - /** - * Add meta information to the PDF - * - * @param string $label label of the value (Creator, Producer, etc.) - * @param string $value the text to set - */ - function add_info($label, $value) { - // N/A - } - - function set_default_view($view, $options = array()) { - // N/A - } - - /** - * Calculates text size, in points - * - * @param string $text the text to be sized - * @param string $font the desired font - * @param float $size the desired font size - * @param float $word_spacing word spacing, if any - * @param float $char_spacing char spacing, if any - * - * @return float - */ - function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) { - $font = $this->get_ttf_file($font); - - $text = mb_encode_numericentity($text, array(0x0080, 0xffff, 0, 0xffff), 'UTF-8'); - - // FIXME: word spacing - list($x1,,$x2) = @imagettfbbox($size, 0, $font, $text); - return $x2 - $x1; - } - - function get_ttf_file($font) { - if ( strpos($font, '.ttf') === false ) - $font .= ".ttf"; - - /*$filename = substr(strtolower(basename($font)), 0, -4); - - if ( in_array($filename, DOMPDF::$native_fonts) ) { - return "arial.ttf"; - }*/ - - return $font; - } - - /** - * Calculates font height, in points - * - * @param string $font - * @param float $size - * @return float - */ - function get_font_height($font, $size) { - $font = $this->get_ttf_file($font); - $ratio = $this->_dompdf->get_option("font_height_ratio"); - - // FIXME: word spacing - list(,$y2,,,,$y1) = imagettfbbox($size, 0, $font, "MXjpqytfhl"); // Test string with ascenders, descenders and caps - return ($y2 - $y1) * $ratio; - } - - function get_font_baseline($font, $size) { - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $this->get_font_height($font, $size) / $ratio; - } - - /** - * Starts a new page - * - * Subsequent drawing operations will appear on the new page. - */ - function new_page() { - $this->_page_number++; - $this->_page_count++; - } - - function open_object(){ - // N/A - } - - function close_object(){ - // N/A - } - - function add_object(){ - // N/A - } - - function page_text(){ - // N/A - } - - /** - * Streams the image directly to the browser - * - * @param string $filename the name of the image file (ignored) - * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only) - */ - function stream($filename, $options = null) { - - // Perform any antialiasing - if ( $this->_aa_factor != 1 ) { - $dst_w = $this->_width / $this->_aa_factor; - $dst_h = $this->_height / $this->_aa_factor; - $dst = imagecreatetruecolor($dst_w, $dst_h); - imagecopyresampled($dst, $this->_img, 0, 0, 0, 0, - $dst_w, $dst_h, - $this->_width, $this->_height); - } else { - $dst = $this->_img; - } - - if ( !isset($options["type"]) ) - $options["type"] = "png"; - - $type = strtolower($options["type"]); - - header("Cache-Control: private"); - - switch ($type) { - - case "jpg": - case "jpeg": - if ( !isset($options["quality"]) ) - $options["quality"] = 75; - - header("Content-type: image/jpeg"); - imagejpeg($dst, '', $options["quality"]); - break; - - case "png": - default: - header("Content-type: image/png"); - imagepng($dst); - break; - } - - if ( $this->_aa_factor != 1 ) - imagedestroy($dst); - } - - /** - * Returns the PNG as a string - * - * @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only) - * @return string - */ - function output($options = null) { - - if ( $this->_aa_factor != 1 ) { - $dst_w = $this->_width / $this->_aa_factor; - $dst_h = $this->_height / $this->_aa_factor; - $dst = imagecreatetruecolor($dst_w, $dst_h); - imagecopyresampled($dst, $this->_img, 0, 0, 0, 0, - $dst_w, $dst_h, - $this->_width, $this->_height); - } else { - $dst = $this->_img; - } - - if ( !isset($options["type"]) ) - $options["type"] = "png"; - - $type = $options["type"]; - - ob_start(); - - switch ($type) { - - case "jpg": - case "jpeg": - if ( !isset($options["quality"]) ) - $options["quality"] = 75; - - imagejpeg($dst, '', $options["quality"]); - break; - - case "png": - default: - imagepng($dst); - break; - } - - $image = ob_get_clean(); - - if ( $this->_aa_factor != 1 ) - imagedestroy($dst); - - return $image; - } - - -} diff --git a/application/helpers/dompdf/include/image_cache.cls.php b/application/helpers/dompdf/include/image_cache.cls.php deleted file mode 100755 index 7d7e5603b..000000000 --- a/application/helpers/dompdf/include/image_cache.cls.php +++ /dev/null @@ -1,183 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Static class that resolves image urls and downloads and caches - * remote images if required. - * - * @access private - * @package dompdf - */ -class Image_Cache { - - /** - * Array of downloaded images. Cached so that identical images are - * not needlessly downloaded. - * - * @var array - */ - static protected $_cache = array(); - - /** - * The url to the "broken image" used when images can't be loade - * - * @var string - */ - public static $broken_image; - - /** - * Resolve and fetch an image for use. - * - * @param string $url The url of the image - * @param string $protocol Default protocol if none specified in $url - * @param string $host Default host if none specified in $url - * @param string $base_path Default path if none specified in $url - * @param DOMPDF $dompdf The DOMPDF instance - * - * @throws DOMPDF_Image_Exception - * @return array An array with two elements: The local path to the image and the image extension - */ - static function resolve_url($url, $protocol, $host, $base_path, DOMPDF $dompdf) { - $parsed_url = explode_url($url); - $message = null; - - $remote = ($protocol && $protocol !== "file://") || ($parsed_url['protocol'] != ""); - - $data_uri = strpos($parsed_url['protocol'], "data:") === 0; - $full_url = null; - $enable_remote = $dompdf->get_option("enable_remote"); - - try { - - // Remote not allowed and is not DataURI - if ( !$enable_remote && $remote && !$data_uri ) { - throw new DOMPDF_Image_Exception("DOMPDF_ENABLE_REMOTE is set to FALSE"); - } - - // Remote allowed or DataURI - else if ( $enable_remote && $remote || $data_uri ) { - // Download remote files to a temporary directory - $full_url = build_url($protocol, $host, $base_path, $url); - - // From cache - if ( isset(self::$_cache[$full_url]) ) { - $resolved_url = self::$_cache[$full_url]; - } - - // From remote - else { - $tmp_dir = $dompdf->get_option("temp_dir"); - $resolved_url = tempnam($tmp_dir, "ca_dompdf_img_"); - $image = ""; - - if ($data_uri) { - if ($parsed_data_uri = parse_data_uri($url)) { - $image = $parsed_data_uri['data']; - } - } - else { - set_error_handler("record_warnings"); - $image = file_get_contents($full_url); - restore_error_handler(); - } - - // Image not found or invalid - if ( strlen($image) == 0 ) { - $msg = ($data_uri ? "Data-URI could not be parsed" : "Image not found"); - throw new DOMPDF_Image_Exception($msg); - } - - // Image found, put in cache and process - else { - //e.g. fetch.php?media=url.jpg&cache=1 - //- Image file name might be one of the dynamic parts of the url, don't strip off! - //- a remote url does not need to have a file extension at all - //- local cached file does not have a matching file extension - //Therefore get image type from the content - file_put_contents($resolved_url, $image); - } - } - } - - // Not remote, local image - else { - $resolved_url = build_url($protocol, $host, $base_path, $url); - } - - // Check if the local file is readable - if ( !is_readable($resolved_url) || !filesize($resolved_url) ) { - throw new DOMPDF_Image_Exception("Image not readable or empty"); - } - - // Check is the file is an image - else { - list($width, $height, $type) = dompdf_getimagesize($resolved_url); - - // Known image type - if ( $width && $height && in_array($type, array(IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_BMP)) ) { - //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup. - //Only execute on successful caching of remote image. - if ( $enable_remote && $remote || $data_uri ) { - self::$_cache[$full_url] = $resolved_url; - } - } - - // Unknown image type - else { - throw new DOMPDF_Image_Exception("Image type unknown"); - } - } - } - catch(DOMPDF_Image_Exception $e) { - $resolved_url = self::$broken_image; - $type = IMAGETYPE_PNG; - $message = $e->getMessage()." \n $url"; - } - - return array($resolved_url, $type, $message); - } - - /** - * Unlink all cached images (i.e. temporary images either downloaded - * or converted) - */ - static function clear() { - if ( empty(self::$_cache) || DEBUGKEEPTEMP ) return; - - foreach ( self::$_cache as $file ) { - if (DEBUGPNG) print "[clear unlink $file]"; - unlink($file); - } - - self::$_cache = array(); - } - - static function detect_type($file) { - list(, , $type) = dompdf_getimagesize($file); - return $type; - } - - static function type_to_ext($type) { - $image_types = array( - IMAGETYPE_GIF => "gif", - IMAGETYPE_PNG => "png", - IMAGETYPE_JPEG => "jpeg", - IMAGETYPE_BMP => "bmp", - ); - - return (isset($image_types[$type]) ? $image_types[$type] : null); - } - - static function is_broken($url) { - return $url === self::$broken_image; - } -} - -Image_Cache::$broken_image = DOMPDF_LIB_DIR . "/res/broken_image.png"; diff --git a/application/helpers/dompdf/include/image_frame_decorator.cls.php b/application/helpers/dompdf/include/image_frame_decorator.cls.php deleted file mode 100755 index b5a7983aa..000000000 --- a/application/helpers/dompdf/include/image_frame_decorator.cls.php +++ /dev/null @@ -1,80 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for image layout and rendering - * - * @access private - * @package dompdf - */ -class Image_Frame_Decorator extends Frame_Decorator { - - /** - * The path to the image file (note that remote images are - * downloaded locally to DOMPDF_TEMP_DIR). - * - * @var string - */ - protected $_image_url; - - /** - * The image's file error message - * - * @var string - */ - protected $_image_msg; - - /** - * Class constructor - * - * @param Frame $frame the frame to decorate - * @param DOMPDF $dompdf the document's dompdf object (required to resolve relative & remote urls) - */ - function __construct(Frame $frame, DOMPDF $dompdf) { - parent::__construct($frame, $dompdf); - $url = $frame->get_node()->getAttribute("src"); - - $debug_png = $dompdf->get_option("debug_png"); - if ($debug_png) print '[__construct '.$url.']'; - - list($this->_image_url, /*$type*/, $this->_image_msg) = Image_Cache::resolve_url( - $url, - $dompdf->get_protocol(), - $dompdf->get_host(), - $dompdf->get_base_path(), - $dompdf - ); - - if ( Image_Cache::is_broken($this->_image_url) && - $alt = $frame->get_node()->getAttribute("alt") ) { - $style = $frame->get_style(); - $style->width = (4/3)*Font_Metrics::get_text_width($alt, $style->font_family, $style->font_size, $style->word_spacing); - $style->height = Font_Metrics::get_font_height($style->font_family, $style->font_size); - } - } - - /** - * Return the image's url - * - * @return string The url of this image - */ - function get_image_url() { - return $this->_image_url; - } - - /** - * Return the image's error message - * - * @return string The image's error message - */ - function get_image_msg() { - return $this->_image_msg; - } - -} diff --git a/application/helpers/dompdf/include/image_frame_reflower.cls.php b/application/helpers/dompdf/include/image_frame_reflower.cls.php deleted file mode 100755 index 5797b8243..000000000 --- a/application/helpers/dompdf/include/image_frame_reflower.cls.php +++ /dev/null @@ -1,186 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Image reflower class - * - * @access private - * @package dompdf - */ -class Image_Frame_Reflower extends Frame_Reflower { - - function __construct(Image_Frame_Decorator $frame) { - parent::__construct($frame); - } - - function reflow(Block_Frame_Decorator $block = null) { - $this->_frame->position(); - - //FLOAT - //$frame = $this->_frame; - //$page = $frame->get_root(); - - //$enable_css_float = $this->get_dompdf()->get_option("enable_css_float"); - //if ($enable_css_float && $frame->get_style()->float !== "none" ) { - // $page->add_floating_frame($this); - //} - // Set the frame's width - $this->get_min_max_width(); - - if ( $block ) { - $block->add_frame_to_line($this->_frame); - } - } - - function get_min_max_width() { - if (DEBUGPNG) { - // Determine the image's size. Time consuming. Only when really needed? - list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url()); - print "get_min_max_width() ". - $this->_frame->get_style()->width.' '. - $this->_frame->get_style()->height.';'. - $this->_frame->get_parent()->get_style()->width." ". - $this->_frame->get_parent()->get_style()->height.";". - $this->_frame->get_parent()->get_parent()->get_style()->width.' '. - $this->_frame->get_parent()->get_parent()->get_style()->height.';'. - $img_width. ' '. - $img_height.'|' ; - } - - $style = $this->_frame->get_style(); - - $width_forced = true; - $height_forced = true; - - //own style auto or invalid value: use natural size in px - //own style value: ignore suffix text including unit, use given number as px - //own style %: walk up parent chain until found available space in pt; fill available space - // - //special ignored unit: e.g. 10ex: e treated as exponent; x ignored; 10e completely invalid ->like auto - - $width = ($style->width > 0 ? $style->width : 0); - if ( is_percent($width) ) { - $t = 0.0; - for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) { - $f_style = $f->get_style(); - $t = $f_style->length_in_pt($f_style->width); - if ($t != 0) { - break; - } - } - $width = ((float)rtrim($width,"%") * $t)/100; //maybe 0 - } elseif ( !mb_strpos($width, 'pt') ) { - // Don't set image original size if "%" branch was 0 or size not given. - // Otherwise aspect changed on %/auto combination for width/height - // Resample according to px per inch - // See also List_Bullet_Image_Frame_Decorator::__construct - $width = $style->length_in_pt($width); - } - - $height = ($style->height > 0 ? $style->height : 0); - if ( is_percent($height) ) { - $t = 0.0; - for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) { - $f_style = $f->get_style(); - $t = $f_style->length_in_pt($f_style->height); - if ($t != 0) { - break; - } - } - $height = ((float)rtrim($height,"%") * $t)/100; //maybe 0 - } elseif ( !mb_strpos($height, 'pt') ) { - // Don't set image original size if "%" branch was 0 or size not given. - // Otherwise aspect changed on %/auto combination for width/height - // Resample according to px per inch - // See also List_Bullet_Image_Frame_Decorator::__construct - $height = $style->length_in_pt($height); - } - - if ($width == 0 || $height == 0) { - // Determine the image's size. Time consuming. Only when really needed! - list($img_width, $img_height) = dompdf_getimagesize($this->_frame->get_image_url()); - - // don't treat 0 as error. Can be downscaled or can be catched elsewhere if image not readable. - // Resample according to px per inch - // See also List_Bullet_Image_Frame_Decorator::__construct - if ($width == 0 && $height == 0) { - $dpi = $this->_frame->get_dompdf()->get_option("dpi"); - $width = (float)($img_width * 72) / $dpi; - $height = (float)($img_height * 72) / $dpi; - $width_forced = false; - $height_forced = false; - } elseif ($height == 0 && $width != 0) { - $height_forced = false; - $height = ($width / $img_width) * $img_height; //keep aspect ratio - } elseif ($width == 0 && $height != 0) { - $width_forced = false; - $width = ($height / $img_height) * $img_width; //keep aspect ratio - } - } - - // Handle min/max width/height - if ( $style->min_width !== "none" || - $style->max_width !== "none" || - $style->min_height !== "none" || - $style->max_height !== "none" ) { - - list(/*$x*/, /*$y*/, $w, $h) = $this->_frame->get_containing_block(); - - $min_width = $style->length_in_pt($style->min_width, $w); - $max_width = $style->length_in_pt($style->max_width, $w); - $min_height = $style->length_in_pt($style->min_height, $h); - $max_height = $style->length_in_pt($style->max_height, $h); - - if ( $max_width !== "none" && $width > $max_width ) { - if ( !$height_forced ) { - $height *= $max_width / $width; - } - - $width = $max_width; - } - - if ( $min_width !== "none" && $width < $min_width ) { - if ( !$height_forced ) { - $height *= $min_width / $width; - } - - $width = $min_width; - } - - if ( $max_height !== "none" && $height > $max_height ) { - if ( !$width_forced ) { - $width *= $max_height / $height; - } - - $height = $max_height; - } - - if ( $min_height !== "none" && $height < $min_height ) { - if ( !$width_forced ) { - $width *= $min_height / $height; - } - - $height = $min_height; - } - } - - if (DEBUGPNG) print $width.' '.$height.';'; - - $style->width = $width . "pt"; - $style->height = $height . "pt"; - - $style->min_width = "none"; - $style->max_width = "none"; - $style->min_height = "none"; - $style->max_height = "none"; - - return array( $width, $width, "min" => $width, "max" => $width); - - } -} diff --git a/application/helpers/dompdf/include/image_renderer.cls.php b/application/helpers/dompdf/include/image_renderer.cls.php deleted file mode 100755 index 561b70153..000000000 --- a/application/helpers/dompdf/include/image_renderer.cls.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Image renderer - * - * @access private - * @package dompdf - */ -class Image_Renderer extends Block_Renderer { - - 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 ( Image_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 (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) { - $this->_debug_layout($frame->get_border_box(), "blue"); - if (DEBUG_LAYOUT_PADDINGBOX) { - $this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5)); - } - } - } -} diff --git a/application/helpers/dompdf/include/inline_frame_decorator.cls.php b/application/helpers/dompdf/include/inline_frame_decorator.cls.php deleted file mode 100755 index ce79bab08..000000000 --- a/application/helpers/dompdf/include/inline_frame_decorator.cls.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for inline layout - * - * @access private - * @package dompdf - */ -class Inline_Frame_Decorator extends Frame_Decorator { - - function __construct(Frame $frame, DOMPDF $dompdf) { parent::__construct($frame, $dompdf); } - - function split(Frame $frame = null, $force_pagebreak = false) { - - if ( is_null($frame) ) { - $this->get_parent()->split($this, $force_pagebreak); - return; - } - - if ( $frame->get_parent() !== $this ) - throw new DOMPDF_Exception("Unable to split: frame is not a child of this one."); - - $split = $this->copy( $this->_frame->get_node()->cloneNode() ); - $this->get_parent()->insert_child_after($split, $this); - - // Unset the current node's right style properties - $style = $this->_frame->get_style(); - $style->margin_right = 0; - $style->padding_right = 0; - $style->border_right_width = 0; - - // Unset the split node's left style properties since we don't want them - // to propagate - $style = $split->get_style(); - $style->margin_left = 0; - $style->padding_left = 0; - $style->border_left_width = 0; - - //On continuation of inline element on next line, - //don't repeat non-vertically repeatble background images - //See e.g. in testcase image_variants, long desriptions - if ( ($url = $style->background_image) && $url !== "none" - && ($repeat = $style->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-y" - ) { - $style->background_image = "none"; - } - - // Add $frame and all following siblings to the new split node - $iter = $frame; - while ($iter) { - $frame = $iter; - $iter = $iter->get_next_sibling(); - $frame->reset(); - $split->append_child($frame); - } - - $page_breaks = array("always", "left", "right"); - $frame_style = $frame->get_style(); - if( $force_pagebreak || - in_array($frame_style->page_break_before, $page_breaks) || - in_array($frame_style->page_break_after, $page_breaks) ) { - - $this->get_parent()->split($split, true); - } - } - -} diff --git a/application/helpers/dompdf/include/inline_frame_reflower.cls.php b/application/helpers/dompdf/include/inline_frame_reflower.cls.php deleted file mode 100755 index 049b8e586..000000000 --- a/application/helpers/dompdf/include/inline_frame_reflower.cls.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Reflows inline frames - * - * @access private - * @package dompdf - */ -class Inline_Frame_Reflower extends Frame_Reflower { - - function __construct(Frame $frame) { parent::__construct($frame); } - - //........................................................................ - - function reflow(Block_Frame_Decorator $block = null) { - $frame = $this->_frame; - - // Check if a page break is forced - $page = $frame->get_root(); - $page->check_forced_page_break($frame); - - if ( $page->is_full() ) - return; - - $style = $frame->get_style(); - - // Generated content - $this->_set_content(); - - $frame->position(); - - $cb = $frame->get_containing_block(); - - // Add our margin, padding & border to the first and last children - if ( ($f = $frame->get_first_child()) && $f instanceof Text_Frame_Decorator ) { - $f_style = $f->get_style(); - $f_style->margin_left = $style->margin_left; - $f_style->padding_left = $style->padding_left; - $f_style->border_left = $style->border_left; - } - - if ( ($l = $frame->get_last_child()) && $l instanceof Text_Frame_Decorator ) { - $l_style = $l->get_style(); - $l_style->margin_right = $style->margin_right; - $l_style->padding_right = $style->padding_right; - $l_style->border_right = $style->border_right; - } - - if ( $block ) { - $block->add_frame_to_line($this->_frame); - } - - // Set the containing blocks and reflow each child. The containing - // block is not changed by line boxes. - foreach ( $frame->get_children() as $child ) { - $child->set_containing_block($cb); - $child->reflow($block); - } - } -} diff --git a/application/helpers/dompdf/include/inline_positioner.cls.php b/application/helpers/dompdf/include/inline_positioner.cls.php deleted file mode 100755 index 1694ce8e2..000000000 --- a/application/helpers/dompdf/include/inline_positioner.cls.php +++ /dev/null @@ -1,70 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Positions inline frames - * - * @access private - * @package dompdf - */ -class Inline_Positioner extends Positioner { - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - //........................................................................ - - function position() { - /** - * Find our nearest block level parent and access its lines property. - * @var Block_Frame_Decorator - */ - $p = $this->_frame->find_block_parent(); - - // Debugging code: - -// pre_r("\nPositioning:"); -// pre_r("Me: " . $this->_frame->get_node()->nodeName . " (" . spl_object_hash($this->_frame->get_node()) . ")"); -// pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")"); - - // End debugging - - if ( !$p ) - throw new DOMPDF_Exception("No block-level parent found. Not good."); - - $f = $this->_frame; - - $cb = $f->get_containing_block(); - $line = $p->get_current_line_box(); - - // Skip the page break if in a fixed position element - $is_fixed = false; - while($f = $f->get_parent()) { - if($f->get_style()->position === "fixed") { - $is_fixed = true; - break; - } - } - - $f = $this->_frame; - - if ( !$is_fixed && $f->get_parent() && - $f->get_parent() instanceof Inline_Frame_Decorator && - $f->is_text_node() ) { - - $min_max = $f->get_reflower()->get_min_max_width(); - - // If the frame doesn't fit in the current line, a line break occurs - if ( $min_max["min"] > ($cb["w"] - $line->left - $line->w - $line->right) ) { - $p->add_line(); - } - } - - $f->set_position($cb["x"] + $line->w, $line->y); - - } -} diff --git a/application/helpers/dompdf/include/inline_renderer.cls.php b/application/helpers/dompdf/include/inline_renderer.cls.php deleted file mode 100755 index 7a8ff51c3..000000000 --- a/application/helpers/dompdf/include/inline_renderer.cls.php +++ /dev/null @@ -1,190 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Renders inline frames - * - * @access private - * @package dompdf - */ -class Inline_Renderer extends Abstract_Renderer { - - //........................................................................ - - function render(Frame $frame) { - $style = $frame->get_style(); - - if ( !$frame->get_first_child() ) - return; // No children, no service - - // Draw the left border if applicable - $bp = $style->get_border_properties(); - $widths = array($style->length_in_pt($bp["top"]["width"]), - $style->length_in_pt($bp["right"]["width"]), - $style->length_in_pt($bp["bottom"]["width"]), - $style->length_in_pt($bp["left"]["width"])); - - // Draw the background & border behind each child. To do this we need - // to figure out just how much space each child takes: - list($x, $y) = $frame->get_first_child()->get_position(); - $w = null; - $h = 0; -// $x += $widths[3]; -// $y += $widths[0]; - - $this->_set_opacity( $frame->get_opacity( $style->opacity ) ); - - $first_row = true; - - foreach ($frame->get_children() as $child) { - list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box(); - - if ( !is_null($w) && $child_x < $x + $w ) { - //This branch seems to be supposed to being called on the first part - //of an inline html element, and the part after the if clause for the - //parts after a line break. - //But because $w initially mostly is 0, and gets updated only on the next - //round, this seem to be never executed and the common close always. - - // The next child is on another line. Draw the background & - // borders on this line. - - // Background: - 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 this is the first row, draw the left border - if ( $first_row ) { - - if ( $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $bp["left"]["width"] > 0 ) { - $method = "_border_" . $bp["left"]["style"]; - $this->$method($x, $y, $h + $widths[0] + $widths[2], $bp["left"]["color"], $widths, "left"); - } - $first_row = false; - } - - // Draw the top & bottom borders - if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $bp["top"]["width"] > 0 ) { - $method = "_border_" . $bp["top"]["style"]; - $this->$method($x, $y, $w + $widths[1] + $widths[3], $bp["top"]["color"], $widths, "top"); - } - - if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $bp["bottom"]["width"] > 0 ) { - $method = "_border_" . $bp["bottom"]["style"]; - $this->$method($x, $y + $h + $widths[0] + $widths[2], $w + $widths[1] + $widths[3], $bp["bottom"]["color"], $widths, "bottom"); - } - - // Handle anchors & links - $link_node = null; - if ( $frame->get_node()->nodeName === "a" ) { - $link_node = $frame->get_node(); - } - else if ( $frame->get_parent()->get_node()->nodeName === "a" ){ - $link_node = $frame->get_parent()->get_node(); - } - - if ( $link_node && $href = $link_node->getAttribute("href") ) { - $this->_canvas->add_link($href, $x, $y, $w, $h); - } - - $x = $child_x; - $y = $child_y; - $w = $child_w; - $h = $child_h; - continue; - } - - if ( is_null($w) ) - $w = $child_w; - else - $w += $child_w; - - $h = max($h, $child_h); - - if (DEBUG_LAYOUT && DEBUG_LAYOUT_INLINE) { - $this->_debug_layout($child->get_border_box(), "blue"); - if (DEBUG_LAYOUT_PADDINGBOX) { - $this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5)); - } - } - } - - - // Handle the last child - if ( ($bg = $style->background_color) !== "transparent" ) - $this->_canvas->filled_rectangle( $x + $widths[3], $y + $widths[0], $w, $h, $bg); - - //On continuation lines (after line break) of inline elements, the style got copied. - //But a non repeatable background image should not be repeated on the next line. - //But removing the background image above has never an effect, and removing it below - //removes it always, even on the initial line. - //Need to handle it elsewhere, e.g. on certain ...clone()... usages. - // Repeat not given: default is Style::__construct - // ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ... - //different position? $this->_background_image($url, $x, $y, $w, $h, $style); - if ( ($url = $style->background_image) && $url !== "none" ) - $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style); - - // Add the border widths - $w += $widths[1] + $widths[3]; - $h += $widths[0] + $widths[2]; - - // make sure the border and background start inside the left margin - $left_margin = $style->length_in_pt($style->margin_left); - $x += $left_margin; - - // If this is the first row, draw the left border too - if ( $first_row && $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0 ) { - $method = "_border_" . $bp["left"]["style"]; - $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left"); - } - - // Draw the top & bottom borders - if ( $bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0 ) { - $method = "_border_" . $bp["top"]["style"]; - $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top"); - } - - if ( $bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0 ) { - $method = "_border_" . $bp["bottom"]["style"]; - $this->$method($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom"); - } - - // pre_var_dump(get_class($frame->get_next_sibling())); - // $last_row = get_class($frame->get_next_sibling()) !== 'Inline_Frame_Decorator'; - // Draw the right border if this is the last row - if ( $bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0 ) { - $method = "_border_" . $bp["right"]["style"]; - $this->$method($x + $w, $y, $h, $bp["right"]["color"], $widths, "right"); - } - - // Only two levels of links frames - $link_node = null; - if ( $frame->get_node()->nodeName === "a" ) { - $link_node = $frame->get_node(); - - if ( ($name = $link_node->getAttribute("name")) || ($name = $link_node->getAttribute("id")) ) { - $this->_canvas->add_named_dest($name); - } - } - - if ( $frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a" ){ - $link_node = $frame->get_parent()->get_node(); - } - - // Handle anchors & links - if ( $link_node ) { - if ( $href = $link_node->getAttribute("href") ) - $this->_canvas->add_link($href, $x, $y, $w, $h); - } - } -} diff --git a/application/helpers/dompdf/include/javascript_embedder.cls.php b/application/helpers/dompdf/include/javascript_embedder.cls.php deleted file mode 100755 index 92c244b2d..000000000 --- a/application/helpers/dompdf/include/javascript_embedder.cls.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Embeds Javascript into the PDF document - * - * @access private - * @package dompdf - */ -class Javascript_Embedder { - - /** - * @var DOMPDF - */ - protected $_dompdf; - - function __construct(DOMPDF $dompdf) { - $this->_dompdf = $dompdf; - } - - function insert($script) { - $this->_dompdf->get_canvas()->javascript($script); - } - - function render(Frame $frame) { - if ( !$this->_dompdf->get_option("enable_javascript") ) { - return; - } - - $this->insert($frame->get_node()->nodeValue); - } -} diff --git a/application/helpers/dompdf/include/line_box.cls.php b/application/helpers/dompdf/include/line_box.cls.php deleted file mode 100755 index 352359729..000000000 --- a/application/helpers/dompdf/include/line_box.cls.php +++ /dev/null @@ -1,252 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * The line box class - * - * This class represents a line box - * http://www.w3.org/TR/CSS2/visuren.html#line-box - * - * @access protected - * @package dompdf - */ -class Line_Box { - - /** - * @var Block_Frame_Decorator - */ - protected $_block_frame; - - /** - * @var Frame[] - */ - protected $_frames = array(); - - /** - * @var integer - */ - public $wc = 0; - - /** - * @var float - */ - public $y = null; - - /** - * @var float - */ - public $w = 0.0; - - /** - * @var float - */ - public $h = 0.0; - - /** - * @var float - */ - public $left = 0.0; - - /** - * @var float - */ - public $right = 0.0; - - /** - * @var Frame - */ - public $tallest_frame = null; - - /** - * @var bool[] - */ - public $floating_blocks = array(); - - /** - * @var bool - */ - public $br = false; - - /** - * Class constructor - * - * @param Block_Frame_Decorator $frame the Block_Frame_Decorator containing this line - */ - function __construct(Block_Frame_Decorator $frame, $y = 0) { - $this->_block_frame = $frame; - $this->_frames = array(); - $this->y = $y; - - $this->get_float_offsets(); - } - - /** - * Returns the floating elements inside the first floating parent - * - * @param Page_Frame_Decorator $root - * - * @return Frame[] - */ - function get_floats_inside(Page_Frame_Decorator $root) { - $floating_frames = $root->get_floating_frames(); - - if ( count($floating_frames) == 0 ) { - return $floating_frames; - } - - // Find nearest floating element - $p = $this->_block_frame; - while( $p->get_style()->float === "none" ) { - $parent = $p->get_parent(); - - if ( !$parent ) { - break; - } - - $p = $parent; - } - - if ( $p == $root ) { - return $floating_frames; - } - - $parent = $p; - - $childs = array(); - - foreach ($floating_frames as $_floating) { - $p = $_floating->get_parent(); - - while (($p = $p->get_parent()) && $p !== $parent); - - if ( $p ) { - $childs[] = $p; - } - } - - return $childs; - } - - function get_float_offsets() { - $enable_css_float = $this->_block_frame->get_dompdf()->get_option("enable_css_float"); - if ( !$enable_css_float ) { - return; - } - - static $anti_infinite_loop = 500; // FIXME smelly hack - - $reflower = $this->_block_frame->get_reflower(); - - if ( !$reflower ) { - return; - } - - $cb_w = null; - - $block = $this->_block_frame; - $root = $block->get_root(); - - if ( !$root ) { - return; - } - - $floating_frames = $this->get_floats_inside($root); - - foreach ( $floating_frames as $child_key => $floating_frame ) { - $id = $floating_frame->get_id(); - - if ( isset($this->floating_blocks[$id]) ) { - continue; - } - - $floating_style = $floating_frame->get_style(); - $float = $floating_style->float; - - $floating_width = $floating_frame->get_margin_width(); - - if (!$cb_w) { - $cb_w = $floating_frame->get_containing_block("w"); - } - - $line_w = $this->get_width(); - - if ( !$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w) ) { - $floating_frame->_float_next_line = true; - continue; - } - - // If the child is still shifted by the floating element - if ( $anti_infinite_loop-- > 0 && - $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y && - $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x") - ) { - if ( $float === "left" ) - $this->left += $floating_width; - else - $this->right += $floating_width; - - $this->floating_blocks[$id] = true; - } - - // else, the floating element won't shift anymore - else { - $root->remove_floating_frame($child_key); - } - } - } - - /** - * @return float - */ - function get_width(){ - return $this->left + $this->w + $this->right; - } - - /** - * @return Block_Frame_Decorator - */ - function get_block_frame() { - return $this->_block_frame; - } - - /** - * @return Frame[] - */ - function &get_frames() { - return $this->_frames; - } - - /** - * @param Frame $frame - */ - function add_frame(Frame $frame) { - $this->_frames[] = $frame; - } - - function __toString(){ - $props = array("wc", "y", "w", "h", "left", "right", "br"); - $s = ""; - foreach($props as $prop) { - $s .= "$prop: ".$this->$prop."\n"; - } - $s .= count($this->_frames)." frames\n"; - return $s; - } - /*function __get($prop) { - if (!isset($this->{"_$prop"})) return; - return $this->{"_$prop"}; - }*/ -} - -/* -class LineBoxList implements Iterator { - private $_p = 0; - private $_lines = array(); - -} -*/ diff --git a/application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php b/application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php deleted file mode 100755 index a661dc050..000000000 --- a/application/helpers/dompdf/include/list_bullet_frame_decorator.cls.php +++ /dev/null @@ -1,65 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for list bullet rendering - * - * @access private - * @package dompdf - */ -class List_Bullet_Frame_Decorator extends Frame_Decorator { - - const BULLET_PADDING = 1; // Distance from bullet to text in pt - // As fraction of font size (including descent). See also DECO_THICKNESS. - const BULLET_THICKNESS = 0.04; // Thickness of bullet outline. Screen: 0.08, print: better less, e.g. 0.04 - const BULLET_DESCENT = 0.3; //descent of font below baseline. Todo: Guessed for now. - const BULLET_SIZE = 0.35; // bullet diameter. For now 0.5 of font_size without descent. - - static $BULLET_TYPES = array("disc", "circle", "square"); - - //........................................................................ - - function __construct(Frame $frame, DOMPDF $dompdf) { - parent::__construct($frame, $dompdf); - } - - function get_margin_width() { - $style = $this->_frame->get_style(); - - // Small hack to prevent extra indenting of list text on list_style_position === "inside" - // and on suppressed bullet - if ( $style->list_style_position === "outside" || - $style->list_style_type === "none" ) { - return 0; - } - - return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; - } - - //hits only on "inset" lists items, to increase height of box - function get_margin_height() { - $style = $this->_frame->get_style(); - - if ( $style->list_style_type === "none" ) { - return 0; - } - - return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; - } - - function get_width() { - return $this->get_margin_height(); - } - - function get_height() { - return $this->get_margin_height(); - } - - //........................................................................ -} diff --git a/application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php b/application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php deleted file mode 100755 index 283056f00..000000000 --- a/application/helpers/dompdf/include/list_bullet_frame_reflower.cls.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Reflows list bullets - * - * @access private - * @package dompdf - */ -class List_Bullet_Frame_Reflower extends Frame_Reflower { - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - //........................................................................ - - function reflow(Block_Frame_Decorator $block = null) { - $style = $this->_frame->get_style(); - - $style->width = $this->_frame->get_width(); - $this->_frame->position(); - - if ( $style->list_style_position === "inside" ) { - $p = $this->_frame->find_block_parent(); - $p->add_frame_to_line($this->_frame); - } - - } -} diff --git a/application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php b/application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php deleted file mode 100755 index f27ca3d68..000000000 --- a/application/helpers/dompdf/include/list_bullet_image_frame_decorator.cls.php +++ /dev/null @@ -1,143 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for list bullets with custom images - * - * @access private - * @package dompdf - */ -class List_Bullet_Image_Frame_Decorator extends Frame_Decorator { - - /** - * The underlying image frame - * - * @var Image_Frame_Decorator - */ - protected $_img; - - /** - * The image's width in pixels - * - * @var int - */ - protected $_width; - - /** - * The image's height in pixels - * - * @var int - */ - protected $_height; - - /** - * Class constructor - * - * @param Frame $frame the bullet frame to decorate - * @param DOMPDF $dompdf the document's dompdf object - */ - function __construct(Frame $frame, DOMPDF $dompdf) { - $style = $frame->get_style(); - $url = $style->list_style_image; - $frame->get_node()->setAttribute("src", $url); - $this->_img = new Image_Frame_Decorator($frame, $dompdf); - parent::__construct($this->_img, $dompdf); - list($width, $height) = dompdf_getimagesize($this->_img->get_image_url()); - - // Resample the bullet image to be consistent with 'auto' sized images - // See also Image_Frame_Reflower::get_min_max_width - // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary. - $dpi = $this->_dompdf->get_option("dpi"); - $this->_width = ((float)rtrim($width, "px") * 72) / $dpi; - $this->_height = ((float)rtrim($height, "px") * 72) / $dpi; - - //If an image is taller as the containing block/box, the box should be extended. - //Neighbour elements are overwriting the overlapping image areas. - //Todo: Where can the box size be extended? - //Code below has no effect. - //See block_frame_reflower _calculate_restricted_height - //See generated_frame_reflower, Dompdf:render() "list-item", "-dompdf-list-bullet"S. - //Leave for now - //if ($style->min_height < $this->_height ) { - // $style->min_height = $this->_height; - //} - //$style->height = "auto"; - } - - /** - * Return the bullet's width - * - * @return int - */ - function get_width() { - //ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator - //for proper alignment of bullet image and text. Allow image to not fitting on left border. - //This controls the distance between bullet image and text - //return $this->_width; - return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE + - 2 * List_Bullet_Frame_Decorator::BULLET_PADDING; - } - - /** - * Return the bullet's height - * - * @return int - */ - function get_height() { - //based on image height - return $this->_height; - } - - /** - * Override get_margin_width - * - * @return int - */ - function get_margin_width() { - //ignore image width, use same width as on predefined bullet List_Bullet_Frame_Decorator - //for proper alignment of bullet image and text. Allow image to not fitting on left border. - //This controls the extra indentation of text to make room for the bullet image. - //Here use actual image size, not predefined bullet size - //return $this->_frame->get_style()->get_font_size()*List_Bullet_Frame_Decorator::BULLET_SIZE + - // 2 * List_Bullet_Frame_Decorator::BULLET_PADDING; - - // Small hack to prevent indenting of list text - // Image Might not exist, then position like on list_bullet_frame_decorator fallback to none. - if ( $this->_frame->get_style()->list_style_position === "outside" || - $this->_width == 0) - return 0; - //This aligns the "inside" image position with the text. - //The text starts to the right of the image. - //Between the image and the text there is an added margin of image width. - //Where this comes from is unknown. - //The corresponding List_Bullet_Frame_Decorator sets a smaller margin. bullet size? - return $this->_width + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING; - } - - /** - * Override get_margin_height() - * - * @return int - */ - function get_margin_height() { - //Hits only on "inset" lists items, to increase height of box - //based on image height - return $this->_height + 2 * List_Bullet_Frame_Decorator::BULLET_PADDING; - } - - /** - * Return image url - * - * @return string - */ - function get_image_url() { - return $this->_img->get_image_url(); - } - -} diff --git a/application/helpers/dompdf/include/list_bullet_positioner.cls.php b/application/helpers/dompdf/include/list_bullet_positioner.cls.php deleted file mode 100755 index 7e89ae471..000000000 --- a/application/helpers/dompdf/include/list_bullet_positioner.cls.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Positions list bullets - * - * @access private - * @package dompdf - */ -class List_Bullet_Positioner extends Positioner { - - function __construct(Frame_Decorator $frame) { parent::__construct($frame); } - - //........................................................................ - - function position() { - - // Bullets & friends are positioned an absolute distance to the left of - // the content edge of their parent element - $cb = $this->_frame->get_containing_block(); - - // Note: this differs from most frames in that we must position - // ourselves after determining our width - $x = $cb["x"] - $this->_frame->get_width(); - - $p = $this->_frame->find_block_parent(); - - $y = $p->get_current_line_box()->y; - - // This is a bit of a hack... - $n = $this->_frame->get_next_sibling(); - if ( $n ) { - $style = $n->get_style(); - $line_height = $style->length_in_pt($style->line_height, $style->get_font_size()); - $offset = $style->length_in_pt($line_height, $n->get_containing_block("h")) - $this->_frame->get_height(); - $y += $offset / 2; - } - - // Now the position is the left top of the block which should be marked with the bullet. - // We tried to find out the y of the start of the first text character within the block. - // But the top margin/padding does not fit, neither from this nor from the next sibling - // The "bit of a hack" above does not work also. - - // Instead let's position the bullet vertically centered to the block which should be marked. - // But for get_next_sibling() the get_containing_block is all zero, and for find_block_parent() - // the get_containing_block is paper width and the entire list as height. - - // if ($p) { - // //$cb = $n->get_containing_block(); - // $cb = $p->get_containing_block(); - // $y += $cb["h"]/2; - // print 'cb:'.$cb["x"].':'.$cb["y"].':'.$cb["w"].':'.$cb["h"].':'; - // } - - // Todo: - // For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing - - /*$style = $p->get_style(); - $font_size = $style->get_font_size(); - $line_height = $style->length_in_pt($style->line_height, $font_size); - $y += ($line_height - $font_size) / 2; */ - - //Position is x-end y-top of character position of the bullet. - $this->_frame->set_position($x, $y); - - } -} diff --git a/application/helpers/dompdf/include/list_bullet_renderer.cls.php b/application/helpers/dompdf/include/list_bullet_renderer.cls.php deleted file mode 100755 index 6b984764f..000000000 --- a/application/helpers/dompdf/include/list_bullet_renderer.cls.php +++ /dev/null @@ -1,236 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Renders list bullets - * - * @access private - * @package dompdf - */ -class List_Bullet_Renderer extends Abstract_Renderer { - static function get_counter_chars($type) { - static $cache = array(); - - if ( isset($cache[$type]) ) { - return $cache[$type]; - } - - $uppercase = false; - $text = ""; - - switch ($type) { - case "decimal-leading-zero": - case "decimal": - case "1": - return "0123456789"; - - case "upper-alpha": - case "upper-latin": - case "A": - $uppercase = true; - case "lower-alpha": - case "lower-latin": - case "a": - $text = "abcdefghijklmnopqrstuvwxyz"; - break; - - case "upper-roman": - case "I": - $uppercase = true; - case "lower-roman": - case "i": - $text = "ivxlcdm"; - break; - - case "lower-greek": - for($i = 0; $i < 24; $i++) { - $text .= unichr($i+944); - } - break; - } - - if ( $uppercase ) { - $text = strtoupper($text); - } - - return $cache[$type] = "$text."; - } - - /** - * @param integer $n - * @param string $type - * @param integer $pad - * - * @return string - */ - private function make_counter($n, $type, $pad = null){ - $n = intval($n); - $text = ""; - $uppercase = false; - - switch ($type) { - case "decimal-leading-zero": - case "decimal": - case "1": - if ($pad) - $text = str_pad($n, $pad, "0", STR_PAD_LEFT); - else - $text = $n; - break; - - case "upper-alpha": - case "upper-latin": - case "A": - $uppercase = true; - case "lower-alpha": - case "lower-latin": - case "a": - $text = chr( ($n % 26) + ord('a') - 1); - break; - - case "upper-roman": - case "I": - $uppercase = true; - case "lower-roman": - case "i": - $text = dec2roman($n); - break; - - case "lower-greek": - $text = unichr($n + 944); - break; - } - - if ( $uppercase ) { - $text = strtoupper($text); - } - - return "$text."; - } - - 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" && - !Image_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_Frame_Reflower::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) = dompdf_getimagesize($img); - $dpi = $this->_dompdf->get_option("dpi"); - $w = ((float)rtrim($width, "px") * 72) / $dpi; - $h = ((float)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*(List_Bullet_Frame_Decorator::BULLET_SIZE /*-List_Bullet_Frame_Decorator::BULLET_THICKNESS*/ ))/2; - $x -= $font_size*(List_Bullet_Frame_Decorator::BULLET_SIZE/2); - $y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT))/2; - $o = $font_size*List_Bullet_Frame_Decorator::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*List_Bullet_Frame_Decorator::BULLET_SIZE; - $x -= $w; - $y += ($font_size*(1-List_Bullet_Frame_Decorator::BULLET_DESCENT-List_Bullet_Frame_Decorator::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 - 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 -= Font_Metrics::get_text_width($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; - } - } - } -} diff --git a/application/helpers/dompdf/include/null_frame_decorator.cls.php b/application/helpers/dompdf/include/null_frame_decorator.cls.php deleted file mode 100755 index 15f806d0d..000000000 --- a/application/helpers/dompdf/include/null_frame_decorator.cls.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Dummy decorator - * - * @access private - * @package dompdf - */ -class Null_Frame_Decorator extends Frame_Decorator { - - function __construct(Frame $frame, DOMPDF $dompdf) { - parent::__construct($frame, $dompdf); - $style = $this->_frame->get_style(); - $style->width = 0; - $style->height = 0; - $style->margin = 0; - $style->padding = 0; - } - -} diff --git a/application/helpers/dompdf/include/null_frame_reflower.cls.php b/application/helpers/dompdf/include/null_frame_reflower.cls.php deleted file mode 100755 index 389f1479d..000000000 --- a/application/helpers/dompdf/include/null_frame_reflower.cls.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Dummy reflower - * - * @access private - * @package dompdf - */ -class Null_Frame_Reflower extends Frame_Reflower { - - function __construct(Frame $frame) { parent::__construct($frame); } - - function reflow(Block_Frame_Decorator $block = null) { return; } - -} diff --git a/application/helpers/dompdf/include/null_positioner.cls.php b/application/helpers/dompdf/include/null_positioner.cls.php deleted file mode 100755 index 97d4986dc..000000000 --- a/application/helpers/dompdf/include/null_positioner.cls.php +++ /dev/null @@ -1,23 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Dummy positioner - * - * @access private - * @package dompdf - */ -class Null_Positioner extends Positioner { - - function __construct(Frame_Decorator $frame) { - parent::__construct($frame); - } - - function position() { return; } - -} diff --git a/application/helpers/dompdf/include/page_cache.cls.php b/application/helpers/dompdf/include/page_cache.cls.php deleted file mode 100755 index 652da160a..000000000 --- a/application/helpers/dompdf/include/page_cache.cls.php +++ /dev/null @@ -1,126 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Caches individual rendered PDF pages - * - * Not totally implemented yet. Use at your own risk ;) - * - * @access private - * @package dompdf - * @static - */ -class Page_Cache { - - const DB_USER = "dompdf_page_cache"; - const DB_PASS = "some meaningful password"; - const DB_NAME = "dompdf_page_cache"; - - static private $__connection = null; - - static function init() { - if ( is_null(self::$__connection) ) { - $con_str = "host=" . DB_HOST . - " dbname=" . self::DB_NAME . - " user=" . self::DB_USER . - " password=" . self::DB_PASS; - - if ( !self::$__connection = pg_connect($con_str) ) - throw new Exception("Database connection failed."); - } - } - - function __construct() { throw new Exception("Can not create instance of Page_Class. Class is static."); } - - private static function __query($sql) { - if ( !($res = pg_query(self::$__connection, $sql)) ) - throw new Exception(pg_last_error(self::$__connection)); - return $res; - } - - static function store_page($id, $page_num, $data) { - $where = "WHERE id='" . pg_escape_string($id) . "' AND ". - "page_num=". pg_escape_string($page_num); - - $res = self::__query("SELECT timestamp FROM page_cache ". $where); - - $row = pg_fetch_assoc($res); - - if ( $row ) - self::__query("UPDATE page_cache SET data='" . pg_escape_string($data) . "' " . $where); - else - self::__query("INSERT INTO page_cache (id, page_num, data) VALUES ('" . pg_escape_string($id) . "', ". - pg_escape_string($page_num) . ", ". - "'". pg_escape_string($data) . "')"); - - } - - static function store_fonts($id, $fonts) { - self::__query("BEGIN"); - // Update the font information - self::__query("DELETE FROM page_fonts WHERE id='" . pg_escape_string($id) . "'"); - - foreach (array_keys($fonts) as $font) - self::__query("INSERT INTO page_fonts (id, font_name) VALUES ('" . - pg_escape_string($id) . "', '" . pg_escape_string($font) . "')"); - self::__query("COMMIT"); - } - -// static function retrieve_page($id, $page_num) { - -// $res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ". -// "page_num=". pg_escape_string($page_num)); - -// $row = pg_fetch_assoc($res); - -// return pg_unescape_bytea($row["data"]); - -// } - - static function get_page_timestamp($id, $page_num) { - $res = self::__query("SELECT timestamp FROM page_cache WHERE id='" . pg_escape_string($id) . "' AND ". - "page_num=". pg_escape_string($page_num)); - - $row = pg_fetch_assoc($res); - - return $row["timestamp"]; - - } - - // Adds the cached document referenced by $id to the provided pdf - static function insert_cached_document(CPDF_Adapter $pdf, $id, $new_page = true) { - $res = self::__query("SELECT font_name FROM page_fonts WHERE id='" . pg_escape_string($id) . "'"); - - // Ensure that the fonts needed by the cached document are loaded into - // the pdf - while ($row = pg_fetch_assoc($res)) - $pdf->get_cpdf()->selectFont($row["font_name"]); - - $res = self::__query("SELECT data FROM page_cache WHERE id='" . pg_escape_string($id) . "'"); - - if ( $new_page ) - $pdf->new_page(); - - $first = true; - while ($row = pg_fetch_assoc($res)) { - - if ( !$first ) - $pdf->new_page(); - else - $first = false; - - $page = $pdf->reopen_serialized_object($row["data"]); - //$pdf->close_object(); - $pdf->add_object($page, "add"); - - } - - } -} - -Page_Cache::init(); diff --git a/application/helpers/dompdf/include/page_frame_decorator.cls.php b/application/helpers/dompdf/include/page_frame_decorator.cls.php deleted file mode 100755 index f089d0075..000000000 --- a/application/helpers/dompdf/include/page_frame_decorator.cls.php +++ /dev/null @@ -1,592 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Decorates frames for page layout - * - * @access private - * @package dompdf - */ -class Page_Frame_Decorator extends Frame_Decorator { - - /** - * y value of bottom page margin - * - * @var float - */ - protected $_bottom_page_margin; - - /** - * Flag indicating page is full. - * - * @var bool - */ - protected $_page_full; - - /** - * Number of tables currently being reflowed - * - * @var int - */ - protected $_in_table; - - /** - * The pdf renderer - * - * @var Renderer - */ - protected $_renderer; - - /** - * This page's floating frames - * - * @var array - */ - protected $_floating_frames = array(); - - //........................................................................ - - /** - * Class constructor - * - * @param Frame $frame the frame to decorate - * @param DOMPDF $dompdf - */ - function __construct(Frame $frame, DOMPDF $dompdf) { - parent::__construct($frame, $dompdf); - $this->_page_full = false; - $this->_in_table = 0; - $this->_bottom_page_margin = null; - } - - /** - * Set the renderer used for this pdf - * - * @param Renderer $renderer the renderer to use - */ - function set_renderer($renderer) { - $this->_renderer = $renderer; - } - - /** - * Return the renderer used for this pdf - * - * @return Renderer - */ - function get_renderer() { - return $this->_renderer; - } - - /** - * Set the frame's containing block. Overridden to set $this->_bottom_page_margin. - * - * @param float $x - * @param float $y - * @param float $w - * @param float $h - */ - function set_containing_block($x = null, $y = null, $w = null, $h = null) { - parent::set_containing_block($x,$y,$w,$h); - //$w = $this->get_containing_block("w"); - if ( isset($h) ) - $this->_bottom_page_margin = $h; // - $this->_frame->get_style()->length_in_pt($this->_frame->get_style()->margin_bottom, $w); - } - - /** - * Returns true if the page is full and is no longer accepting frames. - * - * @return bool - */ - function is_full() { - return $this->_page_full; - } - - /** - * Start a new page by resetting the full flag. - */ - function next_page() { - $this->_floating_frames = array(); - $this->_renderer->new_page(); - $this->_page_full = false; - } - - /** - * Indicate to the page that a table is currently being reflowed. - */ - function table_reflow_start() { - $this->_in_table++; - } - - /** - * Indicate to the page that table reflow is finished. - */ - function table_reflow_end() { - $this->_in_table--; - } - - /** - * Return whether we are currently in a nested table or not - * - * @return bool - */ - function in_nested_table() { - return $this->_in_table > 1; - } - - /** - * Check if a forced page break is required before $frame. This uses the - * frame's page_break_before property as well as the preceeding frame's - * page_break_after property. - * - * @link http://www.w3.org/TR/CSS21/page.html#forced - * - * @param Frame $frame the frame to check - * @return bool true if a page break occured - */ - function check_forced_page_break(Frame $frame) { - - // Skip check if page is already split - if ( $this->_page_full ) - return null; - - $block_types = array("block", "list-item", "table", "inline"); - $page_breaks = array("always", "left", "right"); - - $style = $frame->get_style(); - - if ( !in_array($style->display, $block_types) ) - return false; - - // Find the previous block-level sibling - $prev = $frame->get_prev_sibling(); - - while ( $prev && !in_array($prev->get_style()->display, $block_types) ) - $prev = $prev->get_prev_sibling(); - - - if ( in_array($style->page_break_before, $page_breaks) ) { - - // Prevent cascading splits - $frame->split(null, true); - // We have to grab the style again here because split() resets - // $frame->style to the frame's orignal style. - $frame->get_style()->page_break_before = "auto"; - $this->_page_full = true; - - return true; - } - - if ( $prev && in_array($prev->get_style()->page_break_after, $page_breaks) ) { - // Prevent cascading splits - $frame->split(null, true); - $prev->get_style()->page_break_after = "auto"; - $this->_page_full = true; - return true; - } - - if( $prev && $prev->get_last_child() && $frame->get_node()->nodeName != "body" ) { - $prev_last_child = $prev->get_last_child(); - if ( in_array($prev_last_child->get_style()->page_break_after, $page_breaks) ) { - $frame->split(null, true); - $prev_last_child->get_style()->page_break_after = "auto"; - $this->_page_full = true; - return true; - } - } - - - return false; - } - - /** - * Determine if a page break is allowed before $frame - * http://www.w3.org/TR/CSS21/page.html#allowed-page-breaks - * - * In the normal flow, page breaks can occur at the following places: - * - * 1. In the vertical margin between block boxes. When a page - * break occurs here, the used values of the relevant - * 'margin-top' and 'margin-bottom' properties are set to '0'. - * 2. Between line boxes inside a block box. - * - * These breaks are subject to the following rules: - * - * * Rule A: Breaking at (1) is allowed only if the - * 'page-break-after' and 'page-break-before' properties of - * all the elements generating boxes that meet at this margin - * allow it, which is when at least one of them has the value - * 'always', 'left', or 'right', or when all of them are - * 'auto'. - * - * * Rule B: However, if all of them are 'auto' and the - * nearest common ancestor of all the elements has a - * 'page-break-inside' value of 'avoid', then breaking here is - * not allowed. - * - * * Rule C: Breaking at (2) is allowed only if the number of - * line boxes between the break and the start of the enclosing - * block box is the value of 'orphans' or more, and the number - * of line boxes between the break and the end of the box is - * the value of 'widows' or more. - * - * * Rule D: In addition, breaking at (2) is allowed only if - * the 'page-break-inside' property is 'auto'. - * - * If the above doesn't provide enough break points to keep - * content from overflowing the page boxes, then rules B and D are - * dropped in order to find additional breakpoints. - * - * If that still does not lead to sufficient break points, rules A - * and C are dropped as well, to find still more break points. - * - * We will also allow breaks between table rows. However, when - * splitting a table, the table headers should carry over to the - * next page (but they don't yet). - * - * @param Frame $frame the frame to check - * @return bool true if a break is allowed, false otherwise - */ - protected function _page_break_allowed(Frame $frame) { - - $block_types = array("block", "list-item", "table", "-dompdf-image"); - dompdf_debug("page-break", "_page_break_allowed(" . $frame->get_node()->nodeName. ")"); - $display = $frame->get_style()->display; - - // Block Frames (1): - if ( in_array($display, $block_types) ) { - - // Avoid breaks within table-cells - if ( $this->_in_table ) { - dompdf_debug("page-break", "In table: " . $this->_in_table); - return false; - } - - // Rules A & B - - if ( $frame->get_style()->page_break_before === "avoid" ) { - dompdf_debug("page-break", "before: avoid"); - return false; - } - - // Find the preceeding block-level sibling - $prev = $frame->get_prev_sibling(); - while ( $prev && !in_array($prev->get_style()->display, $block_types) ) - $prev = $prev->get_prev_sibling(); - - // Does the previous element allow a page break after? - if ( $prev && $prev->get_style()->page_break_after === "avoid" ) { - dompdf_debug("page-break", "after: avoid"); - return false; - } - - // If both $prev & $frame have the same parent, check the parent's - // page_break_inside property. - $parent = $frame->get_parent(); - if ( $prev && $parent && $parent->get_style()->page_break_inside === "avoid" ) { - dompdf_debug("page-break", "parent inside: avoid"); - return false; - } - - // To prevent cascading page breaks when a top-level element has - // page-break-inside: avoid, ensure that at least one frame is - // on the page before splitting. - if ( $parent->get_node()->nodeName === "body" && !$prev ) { - // We are the body's first child - dompdf_debug("page-break", "Body's first child."); - return false; - } - - // If the frame is the first block-level frame, use the value from - // $frame's parent instead. - if ( !$prev && $parent ) - return $this->_page_break_allowed( $parent ); - - dompdf_debug("page-break", "block: break allowed"); - return true; - - } - - // Inline frames (2): - else if ( in_array($display, Style::$INLINE_TYPES) ) { - - // Avoid breaks within table-cells - if ( $this->_in_table ) { - dompdf_debug("page-break", "In table: " . $this->_in_table); - return false; - } - - // Rule C - $block_parent = $frame->find_block_parent(); - if ( count($block_parent->get_line_boxes() ) < $frame->get_style()->orphans ) { - dompdf_debug("page-break", "orphans"); - return false; - } - - // FIXME: Checking widows is tricky without having laid out the - // remaining line boxes. Just ignore it for now... - - // Rule D - $p = $block_parent; - while ($p) { - if ( $p->get_style()->page_break_inside === "avoid" ) { - dompdf_debug("page-break", "parent->inside: avoid"); - return false; - } - $p = $p->find_block_parent(); - } - - // To prevent cascading page breaks when a top-level element has - // page-break-inside: avoid, ensure that at least one frame with - // some content is on the page before splitting. - $prev = $frame->get_prev_sibling(); - while ( $prev && ($prev->is_text_node() && trim($prev->get_node()->nodeValue) == "") ) - $prev = $prev->get_prev_sibling(); - - if ( $block_parent->get_node()->nodeName === "body" && !$prev ) { - // We are the body's first child - dompdf_debug("page-break", "Body's first child."); - return false; - } - - // Skip breaks on empty text nodes - if ( $frame->is_text_node() && - $frame->get_node()->nodeValue == "" ) - return false; - - dompdf_debug("page-break", "inline: break allowed"); - return true; - - // Table-rows - } else if ( $display === "table-row" ) { - - // Simply check if the parent table's page_break_inside property is - // not 'avoid' - $p = Table_Frame_Decorator::find_parent_table($frame); - - while ($p) { - if ( $p->get_style()->page_break_inside === "avoid" ) { - dompdf_debug("page-break", "parent->inside: avoid"); - return false; - } - $p = $p->find_block_parent(); - } - - // Avoid breaking after the first row of a table - if ( $p && $p->get_first_child() === $frame) { - dompdf_debug("page-break", "table: first-row"); - return false; - } - - // If this is a nested table, prevent the page from breaking - if ( $this->_in_table > 1 ) { - dompdf_debug("page-break", "table: nested table"); - return false; - } - - dompdf_debug("page-break","table-row/row-groups: break allowed"); - return true; - - } else if ( in_array($display, Table_Frame_Decorator::$ROW_GROUPS) ) { - - // Disallow breaks at row-groups: only split at row boundaries - return false; - - } else { - - dompdf_debug("page-break", "? " . $frame->get_style()->display . ""); - return false; - } - - } - - /** - * Check if $frame will fit on the page. If the frame does not fit, - * the frame tree is modified so that a page break occurs in the - * correct location. - * - * @param Frame $frame the frame to check - * @return Frame the frame following the page break - */ - function check_page_break(Frame $frame) { - // Do not split if we have already or if the frame was already - // pushed to the next page (prevents infinite loops) - if ( $this->_page_full || $frame->_already_pushed ) { - return false; - } - - // If the frame is absolute of fixed it shouldn't break - $p = $frame; - do { - if ( $p->is_absolute() ) - return false; - } while ( $p = $p->get_parent() ); - - $margin_height = $frame->get_margin_height(); - - // FIXME If the row is taller than the page and - // if it the first of the page, we don't break - if ( $frame->get_style()->display === "table-row" && - !$frame->get_prev_sibling() && - $margin_height > $this->get_margin_height() ) - return false; - - // Determine the frame's maximum y value - $max_y = $frame->get_position("y") + $margin_height; - - // If a split is to occur here, then the bottom margins & paddings of all - // parents of $frame must fit on the page as well: - $p = $frame->get_parent(); - while ( $p ) { - $style = $p->get_style(); - $max_y += $style->length_in_pt(array($style->margin_bottom, - $style->padding_bottom, - $style->border_bottom_width)); - $p = $p->get_parent(); - } - - - // Check if $frame flows off the page - if ( $max_y <= $this->_bottom_page_margin ) - // no: do nothing - return false; - - dompdf_debug("page-break", "check_page_break"); - dompdf_debug("page-break", "in_table: " . $this->_in_table); - - // yes: determine page break location - $iter = $frame; - $flg = false; - - $in_table = $this->_in_table; - - dompdf_debug("page-break","Starting search"); - while ( $iter ) { - // echo "\nbacktrack: " .$iter->get_node()->nodeName ." ".spl_object_hash($iter->get_node()). ""; - if ( $iter === $this ) { - dompdf_debug("page-break", "reached root."); - // We've reached the root in our search. Just split at $frame. - break; - } - - if ( $this->_page_break_allowed($iter) ) { - dompdf_debug("page-break","break allowed, splitting."); - $iter->split(null, true); - $this->_page_full = true; - $this->_in_table = $in_table; - $frame->_already_pushed = true; - return true; - } - - if ( !$flg && $next = $iter->get_last_child() ) { - dompdf_debug("page-break", "following last child."); - - if ( $next->is_table() ) - $this->_in_table++; - - $iter = $next; - continue; - } - - if ( $next = $iter->get_prev_sibling() ) { - dompdf_debug("page-break", "following prev sibling."); - - if ( $next->is_table() && !$iter->is_table() ) - $this->_in_table++; - - else if ( !$next->is_table() && $iter->is_table() ) - $this->_in_table--; - - $iter = $next; - $flg = false; - continue; - } - - if ( $next = $iter->get_parent() ) { - dompdf_debug("page-break", "following parent."); - - if ( $iter->is_table() ) - $this->_in_table--; - - $iter = $next; - $flg = true; - continue; - } - - break; - } - - $this->_in_table = $in_table; - - // No valid page break found. Just break at $frame. - dompdf_debug("page-break", "no valid break found, just splitting."); - - // If we are in a table, backtrack to the nearest top-level table row - if ( $this->_in_table ) { - $iter = $frame; - while ($iter && $iter->get_style()->display !== "table-row") - $iter = $iter->get_parent(); - - $iter->split(null, true); - } else { - $frame->split(null, true); - } - - $this->_page_full = true; - $frame->_already_pushed = true; - return true; - } - - //........................................................................ - - function split(Frame $frame = null, $force_pagebreak = false) { - // Do nothing - } - - /** - * Add a floating frame - * - * @param Frame $frame - * - * @return void - */ - function add_floating_frame(Frame $frame) { - array_unshift($this->_floating_frames, $frame); - } - - /** - * @return Frame[] - */ - function get_floating_frames() { - return $this->_floating_frames; - } - - public function remove_floating_frame($key) { - unset($this->_floating_frames[$key]); - } - - public function get_lowest_float_offset(Frame $child) { - $style = $child->get_style(); - $side = $style->clear; - $float = $style->float; - - $y = 0; - - foreach($this->_floating_frames as $key => $frame) { - if ( $side === "both" || $frame->get_style()->float === $side ) { - $y = max($y, $frame->get_position("y") + $frame->get_margin_height()); - - if ( $float !== "none" ) { - $this->remove_floating_frame($key); - } - } - } - - return $y; - } - -} diff --git a/application/helpers/dompdf/include/page_frame_reflower.cls.php b/application/helpers/dompdf/include/page_frame_reflower.cls.php deleted file mode 100755 index 4223f4e85..000000000 --- a/application/helpers/dompdf/include/page_frame_reflower.cls.php +++ /dev/null @@ -1,186 +0,0 @@ - - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Reflows pages - * - * @access private - * @package dompdf - */ -class Page_Frame_Reflower extends Frame_Reflower { - - /** - * Cache of the callbacks array - * - * @var array - */ - private $_callbacks; - - /** - * Cache of the canvas - * - * @var Canvas - */ - private $_canvas; - - function __construct(Page_Frame_Decorator $frame) { parent::__construct($frame); } - - function apply_page_style(Frame $frame, $page_number){ - $style = $frame->get_style(); - $page_styles = $style->get_stylesheet()->get_page_styles(); - - // http://www.w3.org/TR/CSS21/page.html#page-selectors - if ( count($page_styles) > 1 ) { - $odd = $page_number % 2 == 1; - $first = $page_number == 1; - - $style = clone $page_styles["base"]; - - // FIXME RTL - if ( $odd && isset($page_styles[":right"]) ) { - $style->merge($page_styles[":right"]); - } - - if ( $odd && isset($page_styles[":odd"]) ) { - $style->merge($page_styles[":odd"]); - } - - // FIXME RTL - if ( !$odd && isset($page_styles[":left"]) ) { - $style->merge($page_styles[":left"]); - } - - if ( !$odd && isset($page_styles[":even"]) ) { - $style->merge($page_styles[":even"]); - } - - if ( $first && isset($page_styles[":first"]) ) { - $style->merge($page_styles[":first"]); - } - - $frame->set_style($style); - } - } - - //........................................................................ - - /** - * Paged layout: - * http://www.w3.org/TR/CSS21/page.html - */ - function reflow(Block_Frame_Decorator $block = null) { - $fixed_children = array(); - $prev_child = null; - $child = $this->_frame->get_first_child(); - $current_page = 0; - - while ($child) { - $this->apply_page_style($this->_frame, $current_page + 1); - - $style = $this->_frame->get_style(); - - // Pages are only concerned with margins - $cb = $this->_frame->get_containing_block(); - $left = $style->length_in_pt($style->margin_left, $cb["w"]); - $right = $style->length_in_pt($style->margin_right, $cb["w"]); - $top = $style->length_in_pt($style->margin_top, $cb["h"]); - $bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); - - $content_x = $cb["x"] + $left; - $content_y = $cb["y"] + $top; - $content_width = $cb["w"] - $left - $right; - $content_height = $cb["h"] - $top - $bottom; - - // Only if it's the first page, we save the nodes with a fixed position - if ($current_page == 0) { - $children = $child->get_children(); - foreach ($children as $onechild) { - if ($onechild->get_style()->position === "fixed") { - $fixed_children[] = $onechild->deep_copy(); - } - } - $fixed_children = array_reverse($fixed_children); - } - - $child->set_containing_block($content_x, $content_y, $content_width, $content_height); - - // Check for begin reflow callback - $this->_check_callbacks("begin_page_reflow", $child); - - //Insert a copy of each node which have a fixed position - if ($current_page >= 1) { - foreach ($fixed_children as $fixed_child) { - $child->insert_child_before($fixed_child->deep_copy(), $child->get_first_child()); - } - } - - $child->reflow(); - $next_child = $child->get_next_sibling(); - - // Check for begin render callback - $this->_check_callbacks("begin_page_render", $child); - - // Render the page - $this->_frame->get_renderer()->render($child); - - // Check for end render callback - $this->_check_callbacks("end_page_render", $child); - - if ( $next_child ) { - $this->_frame->next_page(); - } - - // Wait to dispose of all frames on the previous page - // so callback will have access to them - if ( $prev_child ) { - $prev_child->dispose(true); - } - $prev_child = $child; - $child = $next_child; - $current_page++; - } - - // Dispose of previous page if it still exists - if ( $prev_child ) { - $prev_child->dispose(true); - } - } - - //........................................................................ - - /** - * Check for callbacks that need to be performed when a given event - * gets triggered on a page - * - * @param string $event the type of event - * @param Frame $frame the frame that event is triggered on - */ - protected function _check_callbacks($event, $frame) { - if (!isset($this->_callbacks)) { - $dompdf = $this->_frame->get_dompdf(); - $this->_callbacks = $dompdf->get_callbacks(); - $this->_canvas = $dompdf->get_canvas(); - } - - if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) { - $info = array(0 => $this->_canvas, "canvas" => $this->_canvas, - 1 => $frame, "frame" => $frame); - $fs = $this->_callbacks[$event]; - foreach ($fs as $f) { - if (is_callable($f)) { - if (is_array($f)) { - $f[0]->$f[1]($info); - } else { - $f($info); - } - } - } - } - } -} diff --git a/application/helpers/dompdf/include/pdflib_adapter.cls.php b/application/helpers/dompdf/include/pdflib_adapter.cls.php deleted file mode 100755 index 4bfe1913e..000000000 --- a/application/helpers/dompdf/include/pdflib_adapter.cls.php +++ /dev/null @@ -1,1085 +0,0 @@ - - * @author Helmut Tischer - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * PDF rendering interface - * - * PDFLib_Adapter provides a simple, stateless interface to the one - * provided by PDFLib. - * - * Unless otherwise mentioned, all dimensions are in points (1/72 in). - * The coordinate origin is in the top left corner and y values - * increase downwards. - * - * See {@link http://www.pdflib.com/} for more complete documentation - * on the underlying PDFlib functions. - * - * @package dompdf - */ -class PDFLib_Adapter implements Canvas { - - /** - * Dimensions of paper sizes in points - * - * @var array; - */ - static public $PAPER_SIZES = array(); // Set to CPDF_Adapter::$PAPER_SIZES below. - - /** - * Whether to create PDFs in memory or on disk - * - * @var bool - */ - static $IN_MEMORY = true; - - /** - * @var DOMPDF - */ - private $_dompdf; - - /** - * Instance of PDFLib class - * - * @var PDFlib - */ - private $_pdf; - - /** - * Name of temporary file used for PDFs created on disk - * - * @var string - */ - private $_file; - - /** - * PDF width, in points - * - * @var float - */ - private $_width; - - /** - * PDF height, in points - * - * @var float - */ - private $_height; - - /** - * Last fill color used - * - * @var array - */ - private $_last_fill_color; - - /** - * Last stroke color used - * - * @var array - */ - private $_last_stroke_color; - - /** - * Cache of image handles - * - * @var array - */ - private $_imgs; - - /** - * Cache of font handles - * - * @var array - */ - private $_fonts; - - /** - * List of objects (templates) to add to multiple pages - * - * @var array - */ - private $_objs; - - /** - * Current page number - * - * @var int - */ - private $_page_number; - - /** - * Total number of pages - * - * @var int - */ - private $_page_count; - - /** - * Text to display on every page - * - * @var array - */ - private $_page_text; - - /** - * Array of pages for accesing after rendering is initially complete - * - * @var array - */ - private $_pages; - - /** - * Class constructor - * - * @param mixed $paper The size of paper to use either a string (see {@link CPDF_Adapter::$PAPER_SIZES}) or - * an array(xmin,ymin,xmax,ymax) - * @param string $orientation The orientation of the document (either 'landscape' or 'portrait') - * @param DOMPDF $dompdf - */ - function __construct($paper = "letter", $orientation = "portrait", DOMPDF $dompdf) { - if ( is_array($paper) ) { - $size = $paper; - } - else if ( isset(self::$PAPER_SIZES[mb_strtolower($paper)]) ) { - $size = self::$PAPER_SIZES[mb_strtolower($paper)]; - } - else { - $size = self::$PAPER_SIZES["letter"]; - } - - if ( mb_strtolower($orientation) === "landscape" ) { - list($size[2], $size[3]) = array($size[3], $size[2]); - } - - $this->_width = $size[2] - $size[0]; - $this->_height= $size[3] - $size[1]; - - $this->_dompdf = $dompdf; - - $this->_pdf = new PDFLib(); - - if ( defined("DOMPDF_PDFLIB_LICENSE") ) - $this->_pdf->set_parameter( "license", DOMPDF_PDFLIB_LICENSE); - - $this->_pdf->set_parameter("textformat", "utf8"); - $this->_pdf->set_parameter("fontwarning", "false"); - - $this->_pdf->set_info("Creator", "DOMPDF"); - - // Silence pedantic warnings about missing TZ settings - $tz = @date_default_timezone_get(); - date_default_timezone_set("UTC"); - $this->_pdf->set_info("Date", date("Y-m-d")); - date_default_timezone_set($tz); - - if ( self::$IN_MEMORY ) - $this->_pdf->begin_document("",""); - else { - $tmp_dir = $this->_dompdf->get_options("temp_dir"); - $tmp_name = tempnam($tmp_dir, "libdompdf_pdf_"); - @unlink($tmp_name); - $this->_file = "$tmp_name.pdf"; - $this->_pdf->begin_document($this->_file,""); - } - - $this->_pdf->begin_page_ext($this->_width, $this->_height, ""); - - $this->_page_number = $this->_page_count = 1; - $this->_page_text = array(); - - $this->_imgs = array(); - $this->_fonts = array(); - $this->_objs = array(); - - // Set up font paths - $families = Font_Metrics::get_font_families(); - foreach ($families as $files) { - foreach ($files as $file) { - $face = basename($file); - $afm = null; - - // Prefer ttfs to afms - if ( file_exists("$file.ttf") ) { - $outline = "$file.ttf"; - - } else if ( file_exists("$file.TTF") ) { - $outline = "$file.TTF"; - - } else if ( file_exists("$file.pfb") ) { - $outline = "$file.pfb"; - - if ( file_exists("$file.afm") ) { - $afm = "$file.afm"; - } - - } else if ( file_exists("$file.PFB") ) { - $outline = "$file.PFB"; - if ( file_exists("$file.AFM") ) { - $afm = "$file.AFM"; - } - } else { - continue; - } - - $this->_pdf->set_parameter("FontOutline", "\{$face\}=\{$outline\}"); - - if ( !is_null($afm) ) { - $this->_pdf->set_parameter("FontAFM", "\{$face\}=\{$afm\}"); - } - } - } - } - - function get_dompdf(){ - return $this->_dompdf; - } - - /** - * Close the pdf - */ - protected function _close() { - $this->_place_objects(); - - // Close all pages - $this->_pdf->suspend_page(""); - for ($p = 1; $p <= $this->_page_count; $p++) { - $this->_pdf->resume_page("pagenumber=$p"); - $this->_pdf->end_page_ext(""); - } - - $this->_pdf->end_document(""); - } - - - /** - * Returns the PDFLib instance - * - * @return PDFLib - */ - function get_pdflib() { - return $this->_pdf; - } - - /** - * Add meta information to the PDF - * - * @param string $label label of the value (Creator, Producter, etc.) - * @param string $value the text to set - */ - function add_info($label, $value) { - $this->_pdf->set_info($label, $value); - } - - /** - * Opens a new 'object' (template in PDFLib-speak) - * - * While an object is open, all drawing actions are recorded to the - * object instead of being drawn on the current page. Objects can - * be added later to a specific page or to several pages. - * - * The return value is an integer ID for the new object. - * - * @see PDFLib_Adapter::close_object() - * @see PDFLib_Adapter::add_object() - * - * @return int - */ - function open_object() { - $this->_pdf->suspend_page(""); - $ret = $this->_pdf->begin_template($this->_width, $this->_height); - $this->_pdf->save(); - $this->_objs[$ret] = array("start_page" => $this->_page_number); - return $ret; - } - - /** - * Reopen an existing object (NOT IMPLEMENTED) - * PDFLib does not seem to support reopening templates. - * - * @param int $object the ID of a previously opened object - * - * @throws DOMPDF_Exception - * @return void - */ - function reopen_object($object) { - throw new DOMPDF_Exception("PDFLib does not support reopening objects."); - } - - /** - * Close the current template - * - * @see PDFLib_Adapter::open_object() - */ - function close_object() { - $this->_pdf->restore(); - $this->_pdf->end_template(); - $this->_pdf->resume_page("pagenumber=".$this->_page_number); - } - - /** - * Adds the specified object to the document - * - * $where can be one of: - * - 'add' add to current page only - * - 'all' add to every page from the current one onwards - * - 'odd' add to all odd numbered pages from now on - * - 'even' add to all even numbered pages from now on - * - 'next' add the object to the next page only - * - 'nextodd' add to all odd numbered pages from the next one - * - 'nexteven' add to all even numbered pages from the next one - * - * @param int $object the object handle returned by open_object() - * @param string $where - */ - function add_object($object, $where = 'all') { - - if ( mb_strpos($where, "next") !== false ) { - $this->_objs[$object]["start_page"]++; - $where = str_replace("next", "", $where); - if ( $where == "" ) - $where = "add"; - } - - $this->_objs[$object]["where"] = $where; - } - - /** - * Stops the specified template from appearing in the document. - * - * The object will stop being displayed on the page following the - * current one. - * - * @param int $object - */ - function stop_object($object) { - - if ( !isset($this->_objs[$object]) ) - return; - - $start = $this->_objs[$object]["start_page"]; - $where = $this->_objs[$object]["where"]; - - // Place the object on this page if required - if ( $this->_page_number >= $start && - (($this->_page_number % 2 == 0 && $where === "even") || - ($this->_page_number % 2 == 1 && $where === "odd") || - ($where === "all")) ) { - $this->_pdf->fit_image($object, 0, 0, ""); - } - - $this->_objs[$object] = null; - unset($this->_objs[$object]); - } - - /** - * Add all active objects to the current page - */ - protected function _place_objects() { - - foreach ( $this->_objs as $obj => $props ) { - $start = $props["start_page"]; - $where = $props["where"]; - - // Place the object on this page if required - if ( $this->_page_number >= $start && - (($this->_page_number % 2 == 0 && $where === "even") || - ($this->_page_number % 2 == 1 && $where === "odd") || - ($where === "all")) ) { - $this->_pdf->fit_image($obj,0,0,""); - } - } - - } - - function get_width() { return $this->_width; } - - function get_height() { return $this->_height; } - - function get_page_number() { return $this->_page_number; } - - function get_page_count() { return $this->_page_count; } - - function set_page_number($num) { $this->_page_number = (int)$num; } - - function set_page_count($count) { $this->_page_count = (int)$count; } - - - /** - * Sets the line style - * - * @param float $width - * @param $cap - * @param string $join - * @param array $dash - * - * @return void - */ - protected function _set_line_style($width, $cap, $join, $dash) { - - if ( count($dash) == 1 ) - $dash[] = $dash[0]; - - if ( count($dash) > 1 ) - $this->_pdf->setdashpattern("dasharray={" . implode(" ", $dash) . "}"); - else - $this->_pdf->setdash(0,0); - - switch ( $join ) { - case "miter": - $this->_pdf->setlinejoin(0); - break; - - case "round": - $this->_pdf->setlinejoin(1); - break; - - case "bevel": - $this->_pdf->setlinejoin(2); - break; - - default: - break; - } - - switch ( $cap ) { - case "butt": - $this->_pdf->setlinecap(0); - break; - - case "round": - $this->_pdf->setlinecap(1); - break; - - case "square": - $this->_pdf->setlinecap(2); - break; - - default: - break; - } - - $this->_pdf->setlinewidth($width); - - } - - /** - * Sets the line color - * - * @param array $color array(r,g,b) - */ - protected function _set_stroke_color($color) { - if($this->_last_stroke_color == $color) - return; - - $this->_last_stroke_color = $color; - - if (isset($color[3])) { - $type = "cmyk"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]); - } - elseif (isset($color[2])) { - $type = "rgb"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null); - } - else { - $type = "gray"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null); - } - - $this->_pdf->setcolor("stroke", $type, $c1, $c2, $c3, $c4); - } - - /** - * Sets the fill color - * - * @param array $color array(r,g,b) - */ - protected function _set_fill_color($color) { - if($this->_last_fill_color == $color) - return; - - $this->_last_fill_color = $color; - - if (isset($color[3])) { - $type = "cmyk"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], $color[3]); - } - elseif (isset($color[2])) { - $type = "rgb"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], $color[2], null); - } - else { - $type = "gray"; - list($c1, $c2, $c3, $c4) = array($color[0], $color[1], null, null); - } - - $this->_pdf->setcolor("fill", $type, $c1, $c2, $c3, $c4); - } - - /** - * Sets the opacity - * - * @param $opacity - * @param $mode - */ - function set_opacity($opacity, $mode = "Normal") { - if ( $mode === "Normal" ) { - $gstate = $this->_pdf->create_gstate("opacityfill=$opacity opacitystroke=$opacity"); - $this->_pdf->set_gstate($gstate); - } - } - - function set_default_view($view, $options = array()) { - // TODO - // http://www.pdflib.com/fileadmin/pdflib/pdf/manuals/PDFlib-8.0.2-API-reference.pdf - /** - * fitheight Fit the page height to the window, with the x coordinate left at the left edge of the window. - * fitrect Fit the rectangle specified by left, bottom, right, and top to the window. - * fitvisible Fit the visible contents of the page (the ArtBox) to the window. - * fitvisibleheight Fit the visible contents of the page to the window with the x coordinate left at the left edge of the window. - * fitvisiblewidth Fit the visible contents of the page to the window with the y coordinate top at the top edge of the window. - * fitwidth Fit the page width to the window, with the y coordinate top at the top edge of the window. - * fitwindow Fit the complete page to the window. - * fixed - */ - //$this->_pdf->set_parameter("openaction", $view); - } - - /** - * Loads a specific font and stores the corresponding descriptor. - * - * @param string $font - * @param string $encoding - * @param string $options - * - * @return int the font descriptor for the font - */ - protected function _load_font($font, $encoding = null, $options = "") { - - // Check if the font is a native PDF font - // Embed non-native fonts - $test = strtolower(basename($font)); - if ( in_array($test, DOMPDF::$native_fonts) ) { - $font = basename($font); - - } else { - // Embed non-native fonts - $options .= " embedding=true"; - } - - if ( is_null($encoding) ) { - - // Unicode encoding is only available for the commerical - // version of PDFlib and not PDFlib-Lite - if ( defined("DOMPDF_PDFLIB_LICENSE") ) - $encoding = "unicode"; - else - $encoding = "auto"; - - } - - $key = "$font:$encoding:$options"; - - if ( isset($this->_fonts[$key]) ) - return $this->_fonts[$key]; - - else { - - $this->_fonts[$key] = $this->_pdf->load_font($font, $encoding, $options); - return $this->_fonts[$key]; - - } - - } - - /** - * Remaps y coords from 4th to 1st quadrant - * - * @param float $y - * @return float - */ - protected function y($y) { return $this->_height - $y; } - - //........................................................................ - - /** - * @param float $x1 - * @param float $y1 - * @param float $x2 - * @param float $y2 - * @param array $color - * @param float $width - * @param array $style - */ - function line($x1, $y1, $x2, $y2, $color, $width, $style = null) { - $this->_set_line_style($width, "butt", "", $style); - $this->_set_stroke_color($color); - - $y1 = $this->y($y1); - $y2 = $this->y($y2); - - $this->_pdf->moveto($x1, $y1); - $this->_pdf->lineto($x2, $y2); - $this->_pdf->stroke(); - } - - function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array()) { - $this->_set_line_style($width, "butt", "", $style); - $this->_set_stroke_color($color); - - $y1 = $this->y($y1); - - $this->_pdf->arc($x1, $y1, $r1, $astart, $aend); - $this->_pdf->stroke(); - } - - //........................................................................ - - function rectangle($x1, $y1, $w, $h, $color, $width, $style = null) { - $this->_set_stroke_color($color); - $this->_set_line_style($width, "butt", "", $style); - - $y1 = $this->y($y1) - $h; - - $this->_pdf->rect($x1, $y1, $w, $h); - $this->_pdf->stroke(); - } - - //........................................................................ - - function filled_rectangle($x1, $y1, $w, $h, $color) { - $this->_set_fill_color($color); - - $y1 = $this->y($y1) - $h; - - $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h)); - $this->_pdf->fill(); - } - - function clipping_rectangle($x1, $y1, $w, $h) { - $this->_pdf->save(); - - $y1 = $this->y($y1) - $h; - - $this->_pdf->rect(floatval($x1), floatval($y1), floatval($w), floatval($h)); - $this->_pdf->clip(); - } - - function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL) { - // @todo - $this->clipping_rectangle($x1, $y1, $w, $h); - } - - function clipping_end() { - $this->_pdf->restore(); - } - - function save() { - $this->_pdf->save(); - } - - function restore() { - $this->_pdf->restore(); - } - - function rotate($angle, $x, $y) { - $pdf = $this->_pdf; - $pdf->translate($x, $this->_height-$y); - $pdf->rotate(-$angle); - $pdf->translate(-$x, -$this->_height+$y); - } - - function skew($angle_x, $angle_y, $x, $y) { - $pdf = $this->_pdf; - $pdf->translate($x, $this->_height-$y); - $pdf->skew($angle_y, $angle_x); // Needs to be inverted - $pdf->translate(-$x, -$this->_height+$y); - } - - function scale($s_x, $s_y, $x, $y) { - $pdf = $this->_pdf; - $pdf->translate($x, $this->_height-$y); - $pdf->scale($s_x, $s_y); - $pdf->translate(-$x, -$this->_height+$y); - } - - function translate($t_x, $t_y) { - $this->_pdf->translate($t_x, -$t_y); - } - - function transform($a, $b, $c, $d, $e, $f) { - $this->_pdf->concat($a, $b, $c, $d, $e, $f); - } - - //........................................................................ - - function polygon($points, $color, $width = null, $style = null, $fill = false) { - - $this->_set_fill_color($color); - $this->_set_stroke_color($color); - - if ( !$fill && isset($width) ) - $this->_set_line_style($width, "square", "miter", $style); - - $y = $this->y(array_pop($points)); - $x = array_pop($points); - $this->_pdf->moveto($x,$y); - - while (count($points) > 1) { - $y = $this->y(array_pop($points)); - $x = array_pop($points); - $this->_pdf->lineto($x,$y); - } - - if ( $fill ) - $this->_pdf->fill(); - else - $this->_pdf->closepath_stroke(); - } - - //........................................................................ - - function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false) { - - $this->_set_fill_color($color); - $this->_set_stroke_color($color); - - if ( !$fill && isset($width) ) - $this->_set_line_style($width, "round", "round", $style); - - $y = $this->y($y); - - $this->_pdf->circle($x, $y, $r); - - if ( $fill ) - $this->_pdf->fill(); - else - $this->_pdf->stroke(); - - } - - //........................................................................ - - function image($img_url, $x, $y, $w, $h, $resolution = "normal") { - $w = (int)$w; - $h = (int)$h; - - $img_type = Image_Cache::detect_type($img_url); - $img_ext = Image_Cache::type_to_ext($img_type); - - if ( !isset($this->_imgs[$img_url]) ) { - $this->_imgs[$img_url] = $this->_pdf->load_image($img_ext, $img_url, ""); - } - - $img = $this->_imgs[$img_url]; - - $y = $this->y($y) - $h; - $this->_pdf->fit_image($img, $x, $y, 'boxsize={'."$w $h".'} fitmethod=entire'); - } - - //........................................................................ - - function text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_spacing = 0, $char_spacing = 0, $angle = 0) { - $fh = $this->_load_font($font); - - $this->_pdf->setfont($fh, $size); - $this->_set_fill_color($color); - - $y = $this->y($y) - Font_Metrics::get_font_height($font, $size); - - $word_spacing = (float)$word_spacing; - $char_spacing = (float)$char_spacing; - $angle = -(float)$angle; - - $this->_pdf->fit_textline($text, $x, $y, "rotate=$angle wordspacing=$word_spacing charspacing=$char_spacing "); - - } - - //........................................................................ - - function javascript($code) { - if ( defined("DOMPDF_PDFLIB_LICENSE") ) { - $this->_pdf->create_action("JavaScript", $code); - } - } - - //........................................................................ - - /** - * Add a named destination (similar to ... in html) - * - * @param string $anchorname The name of the named destination - */ - function add_named_dest($anchorname) { - $this->_pdf->add_nameddest($anchorname,""); - } - - //........................................................................ - - /** - * Add a link to the pdf - * - * @param string $url The url to link to - * @param float $x The x position of the link - * @param float $y The y position of the link - * @param float $width The width of the link - * @param float $height The height of the link - */ - function add_link($url, $x, $y, $width, $height) { - - $y = $this->y($y) - $height; - if ( strpos($url, '#') === 0 ) { - // Local link - $name = substr($url,1); - if ( $name ) - $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} destname=". substr($url,1) . " linewidth=0"); - } else { - - list($proto, $host, $path, $file) = explode_url($url); - - if ( $proto == "" || $proto === "file://" ) - return; // Local links are not allowed - $url = build_url($proto, $host, $path, $file); - $url = '{' . rawurldecode($url) . '}'; - - $action = $this->_pdf->create_action("URI", "url=" . $url); - $this->_pdf->create_annotation($x, $y, $x + $width, $y + $height, 'Link', "contents={$url} action={activate=$action} linewidth=0"); - } - } - - //........................................................................ - - function get_text_width($text, $font, $size, $word_spacing = 0, $letter_spacing = 0) { - $fh = $this->_load_font($font); - - // Determine the additional width due to extra spacing - $num_spaces = mb_substr_count($text," "); - $delta = $word_spacing * $num_spaces; - - if ( $letter_spacing ) { - $num_chars = mb_strlen($text); - $delta += ($num_chars - $num_spaces) * $letter_spacing; - } - - return $this->_pdf->stringwidth($text, $fh, $size) + $delta; - } - - //........................................................................ - - function get_font_height($font, $size) { - - $fh = $this->_load_font($font); - - $this->_pdf->setfont($fh, $size); - - $asc = $this->_pdf->get_value("ascender", $fh); - $desc = $this->_pdf->get_value("descender", $fh); - - // $desc is usually < 0, - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $size * ($asc - $desc) * $ratio; - } - - function get_font_baseline($font, $size) { - $ratio = $this->_dompdf->get_option("font_height_ratio"); - return $this->get_font_height($font, $size) / $ratio * 1.1; - } - - //........................................................................ - - /** - * Writes text at the specified x and y coordinates on every page - * - * The strings '{PAGE_NUM}' and '{PAGE_COUNT}' are automatically replaced - * with their current values. - * - * See {@link Style::munge_color()} for the format of the color array. - * - * @param float $x - * @param float $y - * @param string $text the text to write - * @param string $font the font file to use - * @param float $size the font size, in points - * @param array $color - * @param float $word_space word spacing adjustment - * @param float $char_space char spacing adjustment - * @param float $angle angle to write the text at, measured CW starting from the x-axis - */ - function page_text($x, $y, $text, $font, $size, $color = array(0,0,0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0) { - $_t = "text"; - $this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle"); - } - - //........................................................................ - - /** - * Processes a script on every page - * - * The variables $pdf, $PAGE_NUM, and $PAGE_COUNT are available. - * - * This function can be used to add page numbers to all pages - * after the first one, for example. - * - * @param string $code the script code - * @param string $type the language type for script - */ - function page_script($code, $type = "text/php") { - $_t = "script"; - $this->_page_text[] = compact("_t", "code", "type"); - } - - //........................................................................ - - function new_page() { - - // Add objects to the current page - $this->_place_objects(); - - $this->_pdf->suspend_page(""); - $this->_pdf->begin_page_ext($this->_width, $this->_height, ""); - $this->_page_number = ++$this->_page_count; - - } - - //........................................................................ - - /** - * Add text to each page after rendering is complete - */ - protected function _add_page_text() { - - if ( !count($this->_page_text) ) - return; - - $this->_pdf->suspend_page(""); - - for ($p = 1; $p <= $this->_page_count; $p++) { - $this->_pdf->resume_page("pagenumber=$p"); - - foreach ($this->_page_text as $pt) { - extract($pt); - - switch ($_t) { - - case "text": - $text = str_replace(array("{PAGE_NUM}","{PAGE_COUNT}"), - array($p, $this->_page_count), $text); - $this->text($x, $y, $text, $font, $size, $color, $word_space, $char_space, $angle); - break; - - case "script": - if (!$eval) { - $eval = new PHP_Evaluator($this); - } - $eval->evaluate($code, array('PAGE_NUM' => $p, 'PAGE_COUNT' => $this->_page_count)); - break; - } - } - - $this->_pdf->suspend_page(""); - } - - $this->_pdf->resume_page("pagenumber=".$this->_page_number); - } - - //........................................................................ - - function stream($filename, $options = null) { - - // Add page text - $this->_add_page_text(); - - if ( isset($options["compress"]) && $options["compress"] != 1 ) - $this->_pdf->set_value("compress", 0); - else - $this->_pdf->set_value("compress", 6); - - $this->_close(); - - $data = ""; - - if ( self::$IN_MEMORY ) { - $data = $this->_pdf->get_buffer(); - //$size = strlen($data); - } else { - //$size = filesize($this->_file); - } - - - $filename = str_replace(array("\n","'"),"", $filename); - $attach = (isset($options["Attachment"]) && $options["Attachment"]) ? "attachment" : "inline"; - - header("Cache-Control: private"); - header("Content-type: application/pdf"); - header("Content-Disposition: $attach; filename=\"$filename\""); - - //header("Content-length: " . $size); - - if ( self::$IN_MEMORY ) - echo $data; - - else { - - // Chunked readfile() - $chunk = (1 << 21); // 2 MB - $fh = fopen($this->_file, "rb"); - if ( !$fh ) - throw new DOMPDF_Exception("Unable to load temporary PDF file: " . $this->_file); - - while ( !feof($fh) ) - echo fread($fh,$chunk); - fclose($fh); - - //debugpng - if (DEBUGPNG) print '[pdflib stream unlink '.$this->_file.']'; - if (!DEBUGKEEPTEMP) - - unlink($this->_file); - $this->_file = null; - unset($this->_file); - } - - flush(); - } - - //........................................................................ - - function output($options = null) { - - // Add page text - $this->_add_page_text(); - - if ( isset($options["compress"]) && $options["compress"] != 1 ) - $this->_pdf->set_value("compress", 0); - else - $this->_pdf->set_value("compress", 6); - - $this->_close(); - - if ( self::$IN_MEMORY ) - $data = $this->_pdf->get_buffer(); - - else { - $data = file_get_contents($this->_file); - - //debugpng - if (DEBUGPNG) print '[pdflib output unlink '.$this->_file.']'; - if (!DEBUGKEEPTEMP) - - unlink($this->_file); - $this->_file = null; - unset($this->_file); - } - - return $data; - } -} - -// Workaround for idiotic limitation on statics... -PDFLib_Adapter::$PAPER_SIZES = CPDF_Adapter::$PAPER_SIZES; diff --git a/application/helpers/dompdf/include/php_evaluator.cls.php b/application/helpers/dompdf/include/php_evaluator.cls.php deleted file mode 100755 index 38896675d..000000000 --- a/application/helpers/dompdf/include/php_evaluator.cls.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Executes inline PHP code during the rendering process - * - * @access private - * @package dompdf - */ -class PHP_Evaluator { - - /** - * @var Canvas - */ - protected $_canvas; - - function __construct(Canvas $canvas) { - $this->_canvas = $canvas; - } - - function evaluate($code, $vars = array()) { - if ( !$this->_canvas->get_dompdf()->get_option("enable_php") ) { - return; - } - - // Set up some variables for the inline code - $pdf = $this->_canvas; - $PAGE_NUM = $pdf->get_page_number(); - $PAGE_COUNT = $pdf->get_page_count(); - - // Override those variables if passed in - foreach ($vars as $k => $v) { - $$k = $v; - } - - //$code = html_entity_decode($code); // @todo uncomment this when tested - eval($code); - } - - function render(Frame $frame) { - $this->evaluate($frame->get_node()->nodeValue); - } -} diff --git a/application/helpers/dompdf/include/positioner.cls.php b/application/helpers/dompdf/include/positioner.cls.php deleted file mode 100755 index 6a8b9edc1..000000000 --- a/application/helpers/dompdf/include/positioner.cls.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Base Positioner class - * - * Defines postioner interface - * - * @access private - * @package dompdf - */ -abstract class Positioner { - - /** - * @var Frame_Decorator - */ - protected $_frame; - - //........................................................................ - - function __construct(Frame_Decorator $frame) { - $this->_frame = $frame; - } - - /** - * Class destructor - */ - function __destruct() { - clear_object($this); - } - //........................................................................ - - abstract function position(); - - function move($offset_x, $offset_y, $ignore_self = false) { - list($x, $y) = $this->_frame->get_position(); - - if ( !$ignore_self ) { - $this->_frame->set_position($x + $offset_x, $y + $offset_y); - } - - foreach($this->_frame->get_children() as $child) { - $child->move($offset_x, $offset_y); - } - } -} diff --git a/application/helpers/dompdf/include/renderer.cls.php b/application/helpers/dompdf/include/renderer.cls.php deleted file mode 100755 index ceff4775c..000000000 --- a/application/helpers/dompdf/include/renderer.cls.php +++ /dev/null @@ -1,290 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Concrete renderer - * - * Instantiates several specific renderers in order to render any given - * frame. - * - * @access private - * @package dompdf - */ -class Renderer extends Abstract_Renderer { - - /** - * Array of renderers for specific frame types - * - * @var Abstract_Renderer[] - */ - protected $_renderers; - - /** - * Cache of the callbacks array - * - * @var array - */ - private $_callbacks; - - /** - * Class destructor - */ - function __destruct() { - clear_object($this); - } - - /** - * Advance the canvas to the next page - */ - function new_page() { - $this->_canvas->new_page(); - } - - /** - * Render frames recursively - * - * @param Frame $frame the frame to render - */ - function render(Frame $frame) { - global $_dompdf_debug; - - if ( $_dompdf_debug ) { - echo $frame; - flush(); - } - - $style = $frame->get_style(); - - if ( in_array($style->visibility, array("hidden", "collapse")) ) { - return; - } - - $display = $style->display; - - // Starts the CSS transformation - if ( $style->transform && is_array($style->transform) ) { - $this->_canvas->save(); - list($x, $y) = $frame->get_padding_box(); - $origin = $style->transform_origin; - - foreach($style->transform as $transform) { - list($function, $values) = $transform; - if ( $function === "matrix" ) { - $function = "transform"; - } - - $values = array_map("floatval", $values); - $values[] = $x + $style->length_in_pt($origin[0], $style->width); - $values[] = $y + $style->length_in_pt($origin[1], $style->height); - - call_user_func_array(array($this->_canvas, $function), $values); - } - } - - switch ($display) { - - case "block": - case "list-item": - case "inline-block": - case "table": - case "inline-table": - $this->_render_frame("block", $frame); - break; - - case "inline": - if ( $frame->is_text_node() ) - $this->_render_frame("text", $frame); - else - $this->_render_frame("inline", $frame); - break; - - case "table-cell": - $this->_render_frame("table-cell", $frame); - break; - - case "table-row-group": - case "table-header-group": - case "table-footer-group": - $this->_render_frame("table-row-group", $frame); - break; - - case "-dompdf-list-bullet": - $this->_render_frame("list-bullet", $frame); - break; - - case "-dompdf-image": - $this->_render_frame("image", $frame); - break; - - case "none": - $node = $frame->get_node(); - - if ( $node->nodeName === "script" ) { - if ( $node->getAttribute("type") === "text/php" || - $node->getAttribute("language") === "php" ) { - // Evaluate embedded php scripts - $this->_render_frame("php", $frame); - } - - elseif ( $node->getAttribute("type") === "text/javascript" || - $node->getAttribute("language") === "javascript" ) { - // Insert JavaScript - $this->_render_frame("javascript", $frame); - } - } - - // Don't render children, so skip to next iter - return; - - default: - break; - - } - - // Starts the overflow: hidden box - if ( $style->overflow === "hidden" ) { - list($x, $y, $w, $h) = $frame->get_padding_box(); - - // get border radii - $style = $frame->get_style(); - 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); - } - else { - $this->_canvas->clipping_rectangle($x, $y, $w, $h); - } - } - - $stack = array(); - - foreach ($frame->get_children() as $child) { - // < 0 : nagative z-index - // = 0 : no z-index, no stacking context - // = 1 : stacking context without z-index - // > 1 : z-index - $child_style = $child->get_style(); - $child_z_index = $child_style->z_index; - $z_index = 0; - - if ( $child_z_index !== "auto" ) { - $z_index = intval($child_z_index) + 1; - } - elseif ( $child_style->float !== "none" || $child->is_positionned()) { - $z_index = 1; - } - - $stack[$z_index][] = $child; - } - - ksort($stack); - - foreach ($stack as $by_index) { - foreach($by_index as $child) { - $this->render($child); - } - } - - // Ends the overflow: hidden box - if ( $style->overflow === "hidden" ) { - $this->_canvas->clipping_end(); - } - - if ( $style->transform && is_array($style->transform) ) { - $this->_canvas->restore(); - } - - // Check for end frame callback - $this->_check_callbacks("end_frame", $frame); - } - - /** - * Check for callbacks that need to be performed when a given event - * gets triggered on a frame - * - * @param string $event the type of event - * @param Frame $frame the frame that event is triggered on - */ - protected function _check_callbacks($event, $frame) { - if (!isset($this->_callbacks)) { - $this->_callbacks = $this->_dompdf->get_callbacks(); - } - - if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) { - $info = array(0 => $this->_canvas, "canvas" => $this->_canvas, - 1 => $frame, "frame" => $frame); - $fs = $this->_callbacks[$event]; - foreach ($fs as $f) { - if (is_callable($f)) { - if (is_array($f)) { - $f[0]->$f[1]($info); - } else { - $f($info); - } - } - } - } - } - - /** - * Render a single frame - * - * Creates Renderer objects on demand - * - * @param string $type type of renderer to use - * @param Frame $frame the frame to render - */ - protected function _render_frame($type, $frame) { - - if ( !isset($this->_renderers[$type]) ) { - - switch ($type) { - case "block": - $this->_renderers[$type] = new Block_Renderer($this->_dompdf); - break; - - case "inline": - $this->_renderers[$type] = new Inline_Renderer($this->_dompdf); - break; - - case "text": - $this->_renderers[$type] = new Text_Renderer($this->_dompdf); - break; - - case "image": - $this->_renderers[$type] = new Image_Renderer($this->_dompdf); - break; - - case "table-cell": - $this->_renderers[$type] = new Table_Cell_Renderer($this->_dompdf); - break; - - case "table-row-group": - $this->_renderers[$type] = new Table_Row_Group_Renderer($this->_dompdf); - break; - - case "list-bullet": - $this->_renderers[$type] = new List_Bullet_Renderer($this->_dompdf); - break; - - case "php": - $this->_renderers[$type] = new PHP_Evaluator($this->_canvas); - break; - - case "javascript": - $this->_renderers[$type] = new Javascript_Embedder($this->_dompdf); - break; - - } - } - - $this->_renderers[$type]->render($frame); - - } -} diff --git a/application/helpers/dompdf/include/style.cls.php b/application/helpers/dompdf/include/style.cls.php deleted file mode 100755 index d08fb4baa..000000000 --- a/application/helpers/dompdf/include/style.cls.php +++ /dev/null @@ -1,2435 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * Represents CSS properties. - * - * The Style class is responsible for handling and storing CSS properties. - * It includes methods to resolve colors and lengths, as well as getters & - * setters for many CSS properites. - * - * Actual CSS parsing is performed in the {@link Stylesheet} class. - * - * @package dompdf - */ -class Style { - - const CSS_IDENTIFIER = "-?[_a-zA-Z]+[_a-zA-Z0-9-]*"; - const CSS_INTEGER = "-?\d+"; - - /** - * Default font size, in points. - * - * @var float - */ - static $default_font_size = 12; - - /** - * Default line height, as a fraction of the font size. - * - * @var float - */ - static $default_line_height = 1.2; - - /** - * Default "absolute" font sizes relative to the default font-size - * http://www.w3.org/TR/css3-fonts/#font-size-the-font-size-property - * @var array - */ - static $font_size_keywords = array( - "xx-small" => 0.6, // 3/5 - "x-small" => 0.75, // 3/4 - "small" => 0.889, // 8/9 - "medium" => 1, // 1 - "large" => 1.2, // 6/5 - "x-large" => 1.5, // 3/2 - "xx-large" => 2.0, // 2/1 - ); - - /** - * List of all inline types. Should really be a constant. - * - * @var array - */ - static $INLINE_TYPES = array("inline"); - - /** - * List of all block types. Should really be a constant. - * - * @var array - */ - static $BLOCK_TYPES = array("block", "inline-block", "table-cell", "list-item"); - - /** - * List of all positionned types. Should really be a constant. - * - * @var array - */ - static $POSITIONNED_TYPES = array("relative", "absolute", "fixed"); - - /** - * List of all table types. Should really be a constant. - * - * @var array; - */ - static $TABLE_TYPES = array("table", "inline-table"); - - /** - * List of valid border styles. Should also really be a constant. - * - * @var array - */ - static $BORDER_STYLES = array("none", "hidden", "dotted", "dashed", "solid", - "double", "groove", "ridge", "inset", "outset"); - - /** - * Default style values. - * - * @link http://www.w3.org/TR/CSS21/propidx.html - * - * @var array - */ - static protected $_defaults = null; - - /** - * List of inherited properties - * - * @link http://www.w3.org/TR/CSS21/propidx.html - * - * @var array - */ - static protected $_inherited = null; - - /** - * Caches method_exists result - * - * @var array - */ - static protected $_methods_cache = array(); - - /** - * The stylesheet this style belongs to - * - * @see Stylesheet - * @var Stylesheet - */ - protected $_stylesheet; // stylesheet this style is attached to - - /** - * Main array of all CSS properties & values - * - * @var array - */ - protected $_props; - - /* var instead of protected would allow access outside of class */ - protected $_important_props; - - /** - * Cached property values - * - * @var array - */ - protected $_prop_cache; - - /** - * Font size of parent element in document tree. Used for relative font - * size resolution. - * - * @var float - */ - protected $_parent_font_size; // Font size of parent element - - protected $_font_family; - - /** - * @var Frame - */ - protected $_frame; - - /** - * The origin of the style - * - * @var int - */ - protected $_origin = Stylesheet::ORIG_AUTHOR; - - // private members - /** - * True once the font size is resolved absolutely - * - * @var bool - */ - private $__font_size_calculated; // Cache flag - - /** - * The computed border radius - */ - private $_computed_border_radius = null; - - /** - * @var bool - */ - public $_has_border_radius = false; - - /** - * Class constructor - * - * @param Stylesheet $stylesheet the stylesheet this Style is associated with. - * @param int $origin - */ - function __construct(Stylesheet $stylesheet, $origin = Stylesheet::ORIG_AUTHOR) { - $this->_props = array(); - $this->_important_props = array(); - $this->_stylesheet = $stylesheet; - $this->_origin = $origin; - $this->_parent_font_size = null; - $this->__font_size_calculated = false; - - if ( !isset(self::$_defaults) ) { - - // Shorthand - $d =& self::$_defaults; - - // All CSS 2.1 properties, and their default values - $d["azimuth"] = "center"; - $d["background_attachment"] = "scroll"; - $d["background_color"] = "transparent"; - $d["background_image"] = "none"; - $d["background_image_resolution"] = "normal"; - $d["_dompdf_background_image_resolution"] = $d["background_image_resolution"]; - $d["background_position"] = "0% 0%"; - $d["background_repeat"] = "repeat"; - $d["background"] = ""; - $d["border_collapse"] = "separate"; - $d["border_color"] = ""; - $d["border_spacing"] = "0"; - $d["border_style"] = ""; - $d["border_top"] = ""; - $d["border_right"] = ""; - $d["border_bottom"] = ""; - $d["border_left"] = ""; - $d["border_top_color"] = ""; - $d["border_right_color"] = ""; - $d["border_bottom_color"] = ""; - $d["border_left_color"] = ""; - $d["border_top_style"] = "none"; - $d["border_right_style"] = "none"; - $d["border_bottom_style"] = "none"; - $d["border_left_style"] = "none"; - $d["border_top_width"] = "medium"; - $d["border_right_width"] = "medium"; - $d["border_bottom_width"] = "medium"; - $d["border_left_width"] = "medium"; - $d["border_width"] = "medium"; - $d["border_bottom_left_radius"] = ""; - $d["border_bottom_right_radius"] = ""; - $d["border_top_left_radius"] = ""; - $d["border_top_right_radius"] = ""; - $d["border_radius"] = ""; - $d["border"] = ""; - $d["bottom"] = "auto"; - $d["caption_side"] = "top"; - $d["clear"] = "none"; - $d["clip"] = "auto"; - $d["color"] = "#000000"; - $d["content"] = "normal"; - $d["counter_increment"] = "none"; - $d["counter_reset"] = "none"; - $d["cue_after"] = "none"; - $d["cue_before"] = "none"; - $d["cue"] = ""; - $d["cursor"] = "auto"; - $d["direction"] = "ltr"; - $d["display"] = "inline"; - $d["elevation"] = "level"; - $d["empty_cells"] = "show"; - $d["float"] = "none"; - $d["font_family"] = $stylesheet->get_dompdf()->get_option("default_font"); - $d["font_size"] = "medium"; - $d["font_style"] = "normal"; - $d["font_variant"] = "normal"; - $d["font_weight"] = "normal"; - $d["font"] = ""; - $d["height"] = "auto"; - $d["image_resolution"] = "normal"; - $d["_dompdf_image_resolution"] = $d["image_resolution"]; - $d["_dompdf_keep"] = ""; - $d["left"] = "auto"; - $d["letter_spacing"] = "normal"; - $d["line_height"] = "normal"; - $d["list_style_image"] = "none"; - $d["list_style_position"] = "outside"; - $d["list_style_type"] = "disc"; - $d["list_style"] = ""; - $d["margin_right"] = "0"; - $d["margin_left"] = "0"; - $d["margin_top"] = "0"; - $d["margin_bottom"] = "0"; - $d["margin"] = ""; - $d["max_height"] = "none"; - $d["max_width"] = "none"; - $d["min_height"] = "0"; - $d["min_width"] = "0"; - $d["opacity"] = "1.0"; // CSS3 - $d["orphans"] = "2"; - $d["outline_color"] = ""; // "invert" special color is not supported - $d["outline_style"] = "none"; - $d["outline_width"] = "medium"; - $d["outline"] = ""; - $d["overflow"] = "visible"; - $d["padding_top"] = "0"; - $d["padding_right"] = "0"; - $d["padding_bottom"] = "0"; - $d["padding_left"] = "0"; - $d["padding"] = ""; - $d["page_break_after"] = "auto"; - $d["page_break_before"] = "auto"; - $d["page_break_inside"] = "auto"; - $d["pause_after"] = "0"; - $d["pause_before"] = "0"; - $d["pause"] = ""; - $d["pitch_range"] = "50"; - $d["pitch"] = "medium"; - $d["play_during"] = "auto"; - $d["position"] = "static"; - $d["quotes"] = ""; - $d["richness"] = "50"; - $d["right"] = "auto"; - $d["size"] = "auto"; // @page - $d["speak_header"] = "once"; - $d["speak_numeral"] = "continuous"; - $d["speak_punctuation"] = "none"; - $d["speak"] = "normal"; - $d["speech_rate"] = "medium"; - $d["stress"] = "50"; - $d["table_layout"] = "auto"; - $d["text_align"] = "left"; - $d["text_decoration"] = "none"; - $d["text_indent"] = "0"; - $d["text_transform"] = "none"; - $d["top"] = "auto"; - $d["transform"] = "none"; // CSS3 - $d["transform_origin"] = "50% 50%"; // CSS3 - $d["_webkit_transform"] = $d["transform"]; // CSS3 - $d["_webkit_transform_origin"] = $d["transform_origin"]; // CSS3 - $d["unicode_bidi"] = "normal"; - $d["vertical_align"] = "baseline"; - $d["visibility"] = "visible"; - $d["voice_family"] = ""; - $d["volume"] = "medium"; - $d["white_space"] = "normal"; - $d["word_wrap"] = "normal"; - $d["widows"] = "2"; - $d["width"] = "auto"; - $d["word_spacing"] = "normal"; - $d["z_index"] = "auto"; - - // for @font-face - $d["src"] = ""; - $d["unicode_range"] = ""; - - // Properties that inherit by default - self::$_inherited = array( - "azimuth", - "background_image_resolution", - "border_collapse", - "border_spacing", - "caption_side", - "color", - "cursor", - "direction", - "elevation", - "empty_cells", - "font_family", - "font_size", - "font_style", - "font_variant", - "font_weight", - "font", - "image_resolution", - "letter_spacing", - "line_height", - "list_style_image", - "list_style_position", - "list_style_type", - "list_style", - "orphans", - "page_break_inside", - "pitch_range", - "pitch", - "quotes", - "richness", - "speak_header", - "speak_numeral", - "speak_punctuation", - "speak", - "speech_rate", - "stress", - "text_align", - "text_indent", - "text_transform", - "visibility", - "voice_family", - "volume", - "white_space", - "word_wrap", - "widows", - "word_spacing", - ); - } - } - - /** - * "Destructor": forcibly free all references held by this object - */ - function dispose() { - clear_object($this); - } - - function set_frame(Frame $frame) { - $this->_frame = $frame; - } - - function get_frame() { - return $this->_frame; - } - - function set_origin($origin) { - $this->_origin = $origin; - } - - function get_origin() { - return $this->_origin; - } - - /** - * returns the {@link Stylesheet} this Style is associated with. - * - * @return Stylesheet - */ - function get_stylesheet() { return $this->_stylesheet; } - - /** - * Converts any CSS length value into an absolute length in points. - * - * length_in_pt() takes a single length (e.g. '1em') or an array of - * lengths and returns an absolute length. If an array is passed, then - * the return value is the sum of all elements. - * - * If a reference size is not provided, the default font size is used - * ({@link Style::$default_font_size}). - * - * @param float|array $length the length or array of lengths to resolve - * @param float $ref_size an absolute reference size to resolve percentage lengths - * @return float - */ - function length_in_pt($length, $ref_size = null) { - static $cache = array(); - - if ( !is_array($length) ) { - $length = array($length); - } - - if ( !isset($ref_size) ) { - $ref_size = self::$default_font_size; - } - - $key = implode("@", $length)."/$ref_size"; - - if ( isset($cache[$key]) ) { - return $cache[$key]; - } - - $ret = 0; - foreach ($length as $l) { - - if ( $l === "auto" ) { - return "auto"; - } - - if ( $l === "none" ) { - return "none"; - } - - // Assume numeric values are already in points - if ( is_numeric($l) ) { - $ret += $l; - continue; - } - - if ( $l === "normal" ) { - $ret += $ref_size; - continue; - } - - // Border lengths - if ( $l === "thin" ) { - $ret += 0.5; - continue; - } - - if ( $l === "medium" ) { - $ret += 1.5; - continue; - } - - if ( $l === "thick" ) { - $ret += 2.5; - continue; - } - - if ( ($i = mb_strpos($l, "px")) !== false ) { - $dpi = $this->_stylesheet->get_dompdf()->get_option("dpi"); - $ret += ( mb_substr($l, 0, $i) * 72 ) / $dpi; - continue; - } - - if ( ($i = mb_strpos($l, "pt")) !== false ) { - $ret += (float)mb_substr($l, 0, $i); - continue; - } - - if ( ($i = mb_strpos($l, "%")) !== false ) { - $ret += (float)mb_substr($l, 0, $i)/100 * $ref_size; - continue; - } - - if ( ($i = mb_strpos($l, "rem")) !== false ) { - $ret += (float)mb_substr($l, 0, $i) * $this->_stylesheet->get_dompdf()->get_tree()->get_root()->get_style()->font_size; - continue; - } - - if ( ($i = mb_strpos($l, "em")) !== false ) { - $ret += (float)mb_substr($l, 0, $i) * $this->__get("font_size"); - continue; - } - - if ( ($i = mb_strpos($l, "cm")) !== false ) { - $ret += mb_substr($l, 0, $i) * 72 / 2.54; - continue; - } - - if ( ($i = mb_strpos($l, "mm")) !== false ) { - $ret += mb_substr($l, 0, $i) * 72 / 25.4; - continue; - } - - // FIXME: em:ex ratio? - if ( ($i = mb_strpos($l, "ex")) !== false ) { - $ret += mb_substr($l, 0, $i) * $this->__get("font_size") / 2; - continue; - } - - if ( ($i = mb_strpos($l, "in")) !== false ) { - $ret += (float)mb_substr($l, 0, $i) * 72; - continue; - } - - if ( ($i = mb_strpos($l, "pc")) !== false ) { - $ret += (float)mb_substr($l, 0, $i) * 12; - continue; - } - - // Bogus value - $ret += $ref_size; - } - - return $cache[$key] = $ret; - } - - - /** - * Set inherited properties in this style using values in $parent - * - * @param Style $parent - * - * @return Style - */ - function inherit(Style $parent) { - - // Set parent font size - $this->_parent_font_size = $parent->get_font_size(); - - foreach (self::$_inherited as $prop) { - //inherit the !important property also. - //if local property is also !important, don't inherit. - if ( isset($parent->_props[$prop]) && - ( !isset($this->_props[$prop]) || - ( isset($parent->_important_props[$prop]) && !isset($this->_important_props[$prop]) ) - ) - ) { - if ( isset($parent->_important_props[$prop]) ) { - $this->_important_props[$prop] = true; - } - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$prop] = null; - $this->_props[$prop] = $parent->_props[$prop]; - } - } - - foreach ($this->_props as $prop => $value) { - if ( $value === "inherit" ) { - if ( isset($parent->_important_props[$prop]) ) { - $this->_important_props[$prop] = true; - } - //do not assign direct, but - //implicite assignment through __set, redirect to specialized, get value with __get - //This is for computing defaults if the parent setting is also missing. - //Therefore do not directly assign the value without __set - //set _important_props before that to be able to propagate. - //see __set and __get, on all assignments clear cache! - //$this->_prop_cache[$prop] = null; - //$this->_props[$prop] = $parent->_props[$prop]; - //props_set for more obvious explicite assignment not implemented, because - //too many implicite uses. - // $this->props_set($prop, $parent->$prop); - $this->__set($prop, $parent->__get($prop)); - } - } - - return $this; - } - - /** - * Override properties in this style with those in $style - * - * @param Style $style - */ - function merge(Style $style) { - //treat the !important attribute - //if old rule has !important attribute, override with new rule only if - //the new rule is also !important - foreach($style->_props as $prop => $val ) { - if (isset($style->_important_props[$prop])) { - $this->_important_props[$prop] = true; - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$prop] = null; - $this->_props[$prop] = $val; - } - else if ( !isset($this->_important_props[$prop]) ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$prop] = null; - $this->_props[$prop] = $val; - } - } - - if ( isset($style->_props["font_size"]) ) { - $this->__font_size_calculated = false; - } - } - - /** - * Returns an array(r, g, b, "r"=> r, "g"=>g, "b"=>b, "hex"=>"#rrggbb") - * based on the provided CSS color value. - * - * @param string $color - * @return array - */ - function munge_color($color) { - return CSS_Color::parse($color); - } - - /* direct access to _important_props array from outside would work only when declared as - * 'var $_important_props;' instead of 'protected $_important_props;' - * Don't call _set/__get on missing attribute. Therefore need a special access. - * Assume that __set will be also called when this is called, so do not check validity again. - * Only created, if !important exists -> always set true. - */ - function important_set($prop) { - $prop = str_replace("-", "_", $prop); - $this->_important_props[$prop] = true; - } - - function important_get($prop) { - return isset($this->_important_props[$prop]); - } - - /** - * PHP5 overloaded setter - * - * This function along with {@link Style::__get()} permit a user of the - * Style class to access any (CSS) property using the following syntax: - * - * Style->margin_top = "1em"; - * echo (Style->margin_top); - * - * - * __set() automatically calls the provided set function, if one exists, - * otherwise it sets the property directly. Typically, __set() is not - * called directly from outside of this class. - * - * On each modification clear cache to return accurate setting. - * Also affects direct settings not using __set - * For easier finding all assignments, attempted to allowing only explicite assignment: - * Very many uses, e.g. frame_reflower.cls.php -> for now leave as it is - * function __set($prop, $val) { - * throw new DOMPDF_Exception("Implicite replacement of assignment by __set. Not good."); - * } - * function props_set($prop, $val) { ... } - * - * @param string $prop the property to set - * @param mixed $val the value of the property - * - */ - function __set($prop, $val) { - $prop = str_replace("-", "_", $prop); - $this->_prop_cache[$prop] = null; - - if ( !isset(self::$_defaults[$prop]) ) { - global $_dompdf_warnings; - $_dompdf_warnings[] = "'$prop' is not a valid CSS2 property."; - return; - } - - if ( $prop !== "content" && is_string($val) && strlen($val) > 5 && mb_strpos($val, "url") === false ) { - $val = mb_strtolower(trim(str_replace(array("\n", "\t"), array(" "), $val))); - $val = preg_replace("/([0-9]+) (pt|px|pc|em|ex|in|cm|mm|%)/S", "\\1\\2", $val); - } - - $method = "set_$prop"; - - if ( !isset(self::$_methods_cache[$method]) ) { - self::$_methods_cache[$method] = method_exists($this, $method); - } - - if ( self::$_methods_cache[$method] ) { - $this->$method($val); - } - else { - $this->_props[$prop] = $val; - } - } - - /** - * PHP5 overloaded getter - * Along with {@link Style::__set()} __get() provides access to all CSS - * properties directly. Typically __get() is not called directly outside - * of this class. - * On each modification clear cache to return accurate setting. - * Also affects direct settings not using __set - * - * @param string $prop - * - * @throws DOMPDF_Exception - * @return mixed - */ - function __get($prop) { - if ( !isset(self::$_defaults[$prop]) ) { - throw new DOMPDF_Exception("'$prop' is not a valid CSS2 property."); - } - - if ( isset($this->_prop_cache[$prop]) && $this->_prop_cache[$prop] != null ) { - return $this->_prop_cache[$prop]; - } - - $method = "get_$prop"; - - // Fall back on defaults if property is not set - if ( !isset($this->_props[$prop]) ) { - $this->_props[$prop] = self::$_defaults[$prop]; - } - - if ( !isset(self::$_methods_cache[$method]) ) { - self::$_methods_cache[$method] = method_exists($this, $method); - } - - if ( self::$_methods_cache[$method] ) { - return $this->_prop_cache[$prop] = $this->$method(); - } - - return $this->_prop_cache[$prop] = $this->_props[$prop]; - } - - function get_font_family_raw(){ - return trim($this->_props["font_family"], " \t\n\r\x0B\"'"); - } - - /** - * Getter for the 'font-family' CSS property. - * Uses the {@link Font_Metrics} class to resolve the font family into an - * actual font file. - * - * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-family - * @throws DOMPDF_Exception - * - * @return string - */ - function get_font_family() { - if ( isset($this->_font_family) ) { - return $this->_font_family; - } - - $DEBUGCSS=DEBUGCSS; //=DEBUGCSS; Allow override of global setting for ad hoc debug - - // Select the appropriate font. First determine the subtype, then check - // the specified font-families for a candidate. - - // Resolve font-weight - $weight = $this->__get("font_weight"); - - if ( is_numeric($weight) ) { - if ( $weight < 600 ) { - $weight = "normal"; - } - else { - $weight = "bold"; - } - } - else if ( $weight === "bold" || $weight === "bolder" ) { - $weight = "bold"; - } - else { - $weight = "normal"; - } - - // Resolve font-style - $font_style = $this->__get("font_style"); - - if ( $weight === "bold" && ($font_style === "italic" || $font_style === "oblique") ) { - $subtype = "bold_italic"; - } - else if ( $weight === "bold" && $font_style !== "italic" && $font_style !== "oblique" ) { - $subtype = "bold"; - } - else if ( $weight !== "bold" && ($font_style === "italic" || $font_style === "oblique") ) { - $subtype = "italic"; - } - else { - $subtype = "normal"; - } - - // Resolve the font family - if ( $DEBUGCSS ) { - print "
[get_font_family:";
-      print '('.$this->_props["font_family"].'.'.$font_style.'.'.$this->__get("font_weight").'.'.$weight.'.'.$subtype.')';
-    }
-    
-    $families = preg_split("/\s*,\s*/", $this->_props["font_family"]);
-
-    $font = null;
-    foreach($families as $family) {
-      //remove leading and trailing string delimiters, e.g. on font names with spaces;
-      //remove leading and trailing whitespace
-      $family = trim($family, " \t\n\r\x0B\"'");
-      if ( $DEBUGCSS ) {
-        print '('.$family.')';
-      }
-      $font = Font_Metrics::get_font($family, $subtype);
-
-      if ( $font ) {
-        if ($DEBUGCSS) print '('.$font.")get_font_family]\n
"; - return $this->_font_family = $font; - } - } - - $family = null; - if ( $DEBUGCSS ) { - print '(default)'; - } - $font = Font_Metrics::get_font($family, $subtype); - - if ( $font ) { - if ( $DEBUGCSS ) print '('.$font.")get_font_family]\n"; - return$this->_font_family = $font; - } - - throw new DOMPDF_Exception("Unable to find a suitable font replacement for: '" . $this->_props["font_family"] ."'"); - - } - - /** - * Returns the resolved font size, in points - * - * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size - * @return float - */ - function get_font_size() { - - if ( $this->__font_size_calculated ) { - return $this->_props["font_size"]; - } - - if ( !isset($this->_props["font_size"]) ) { - $fs = self::$_defaults["font_size"]; - } - else { - $fs = $this->_props["font_size"]; - } - - if ( !isset($this->_parent_font_size) ) { - $this->_parent_font_size = self::$default_font_size; - } - - switch ((string)$fs) { - case "xx-small": - case "x-small": - case "small": - case "medium": - case "large": - case "x-large": - case "xx-large": - $fs = self::$default_font_size * self::$font_size_keywords[$fs]; - break; - - case "smaller": - $fs = 8/9 * $this->_parent_font_size; - break; - - case "larger": - $fs = 6/5 * $this->_parent_font_size; - break; - - default: - break; - } - - // Ensure relative sizes resolve to something - if ( ($i = mb_strpos($fs, "em")) !== false ) { - $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size; - } - else if ( ($i = mb_strpos($fs, "ex")) !== false ) { - $fs = mb_substr($fs, 0, $i) * $this->_parent_font_size; - } - else { - $fs = $this->length_in_pt($fs); - } - - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["font_size"] = null; - $this->_props["font_size"] = $fs; - $this->__font_size_calculated = true; - return $this->_props["font_size"]; - - } - - /** - * @link http://www.w3.org/TR/CSS21/text.html#propdef-word-spacing - * @return float - */ - function get_word_spacing() { - if ( $this->_props["word_spacing"] === "normal" ) { - return 0; - } - - return $this->_props["word_spacing"]; - } - - /** - * @link http://www.w3.org/TR/CSS21/text.html#propdef-letter-spacing - * @return float - */ - function get_letter_spacing() { - if ( $this->_props["letter_spacing"] === "normal" ) { - return 0; - } - - return $this->_props["letter_spacing"]; - } - - /** - * @link http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height - * @return float - */ - function get_line_height() { - $line_height = $this->_props["line_height"]; - - if ( $line_height === "normal" ) { - return self::$default_line_height * $this->get_font_size(); - } - - if ( is_numeric($line_height) ) { - return $this->length_in_pt( $line_height . "em", $this->get_font_size()); - } - - return $this->length_in_pt( $line_height, $this->_parent_font_size ); - } - - /** - * Returns the color as an array - * - * The array has the following format: - * array(r,g,b, "r" => r, "g" => g, "b" => b, "hex" => "#rrggbb") - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color - * @return array - */ - function get_color() { - return $this->munge_color( $this->_props["color"] ); - } - - /** - * Returns the background color as an array - * - * The returned array has the same format as {@link Style::get_color()} - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color - * @return array - */ - function get_background_color() { - return $this->munge_color( $this->_props["background_color"] ); - } - - /** - * Returns the background position as an array - * - * The returned array has the following format: - * array(x,y, "x" => x, "y" => y) - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position - * @return array - */ - function get_background_position() { - $tmp = explode(" ", $this->_props["background_position"]); - - switch ($tmp[0]) { - case "left": - $x = "0%"; - break; - - case "right": - $x = "100%"; - break; - - case "top": - $y = "0%"; - break; - - case "bottom": - $y = "100%"; - break; - - case "center": - $x = "50%"; - $y = "50%"; - break; - - default: - $x = $tmp[0]; - break; - } - - if ( isset($tmp[1]) ) { - - switch ($tmp[1]) { - case "left": - $x = "0%"; - break; - - case "right": - $x = "100%"; - break; - - case "top": - $y = "0%"; - break; - - case "bottom": - $y = "100%"; - break; - - case "center": - if ( $tmp[0] === "left" || $tmp[0] === "right" || $tmp[0] === "center" ) { - $y = "50%"; - } - else { - $x = "50%"; - } - break; - - default: - $y = $tmp[1]; - break; - } - - } - else { - $y = "50%"; - } - - if ( !isset($x) ) { - $x = "0%"; - } - - if ( !isset($y) ) { - $y = "0%"; - } - - return array( - 0 => $x, "x" => $x, - 1 => $y, "y" => $y, - ); - } - - - /** - * Returns the background as it is currently stored - * - * (currently anyway only for completeness. - * not used for further processing) - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment - * @return string - */ - function get_background_attachment() { - return $this->_props["background_attachment"]; - } - - - /** - * Returns the background_repeat as it is currently stored - * - * (currently anyway only for completeness. - * not used for further processing) - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat - * @return string - */ - function get_background_repeat() { - return $this->_props["background_repeat"]; - } - - - /** - * Returns the background as it is currently stored - * - * (currently anyway only for completeness. - * not used for further processing, but the individual get_background_xxx) - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background - * @return string - */ - function get_background() { - return $this->_props["background"]; - } - - - /**#@+ - * Returns the border color as an array - * - * See {@link Style::get_color()} - * - * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties - * @return array - */ - function get_border_top_color() { - if ( $this->_props["border_top_color"] === "" ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["border_top_color"] = null; - $this->_props["border_top_color"] = $this->__get("color"); - } - - return $this->munge_color($this->_props["border_top_color"]); - } - - function get_border_right_color() { - if ( $this->_props["border_right_color"] === "" ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["border_right_color"] = null; - $this->_props["border_right_color"] = $this->__get("color"); - } - - return $this->munge_color($this->_props["border_right_color"]); - } - - function get_border_bottom_color() { - if ( $this->_props["border_bottom_color"] === "" ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["border_bottom_color"] = null; - $this->_props["border_bottom_color"] = $this->__get("color"); - } - - return $this->munge_color($this->_props["border_bottom_color"]); - } - - function get_border_left_color() { - if ( $this->_props["border_left_color"] === "" ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["border_left_color"] = null; - $this->_props["border_left_color"] = $this->__get("color"); - } - - return $this->munge_color($this->_props["border_left_color"]); - } - - /**#@-*/ - - /**#@+ - * Returns the border width, as it is currently stored - * - * @link http://www.w3.org/TR/CSS21/box.html#border-width-properties - * @return float|string - */ - function get_border_top_width() { - $style = $this->__get("border_top_style"); - return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_top_width"]) : 0; - } - - function get_border_right_width() { - $style = $this->__get("border_right_style"); - return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_right_width"]) : 0; - } - - function get_border_bottom_width() { - $style = $this->__get("border_bottom_style"); - return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_bottom_width"]) : 0; - } - - function get_border_left_width() { - $style = $this->__get("border_left_style"); - return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["border_left_width"]) : 0; - } - /**#@-*/ - - /** - * Return an array of all border properties. - * - * The returned array has the following structure: - * - * array("top" => array("width" => [border-width], - * "style" => [border-style], - * "color" => [border-color (array)]), - * "bottom" ... ) - * - * - * @return array - */ - function get_border_properties() { - return array( - "top" => array( - "width" => $this->__get("border_top_width"), - "style" => $this->__get("border_top_style"), - "color" => $this->__get("border_top_color"), - ), - "bottom" => array( - "width" => $this->__get("border_bottom_width"), - "style" => $this->__get("border_bottom_style"), - "color" => $this->__get("border_bottom_color"), - ), - "right" => array( - "width" => $this->__get("border_right_width"), - "style" => $this->__get("border_right_style"), - "color" => $this->__get("border_right_color"), - ), - "left" => array( - "width" => $this->__get("border_left_width"), - "style" => $this->__get("border_left_style"), - "color" => $this->__get("border_left_color"), - ), - ); - } - - /** - * Return a single border property - * - * @param string $side - * - * @return mixed - */ - protected function _get_border($side) { - $color = $this->__get("border_" . $side . "_color"); - - return $this->__get("border_" . $side . "_width") . " " . - $this->__get("border_" . $side . "_style") . " " . $color["hex"]; - } - - /**#@+ - * Return full border properties as a string - * - * Border properties are returned just as specified in CSS: - *
[width] [style] [color]
- * e.g. "1px solid blue" - * - * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties - * @return string - */ - function get_border_top() { - return $this->_get_border("top"); - } - - function get_border_right() { - return $this->_get_border("right"); - } - - function get_border_bottom() { - return $this->_get_border("bottom"); - } - - function get_border_left() { - return $this->_get_border("left"); - } - /**#@-*/ - - function get_computed_border_radius($w, $h) { - if ( !empty($this->_computed_border_radius) ) { - return $this->_computed_border_radius; - } - - $rTL = $this->__get("border_top_left_radius"); - $rTR = $this->__get("border_top_right_radius"); - $rBL = $this->__get("border_bottom_left_radius"); - $rBR = $this->__get("border_bottom_right_radius"); - - if ( $rTL + $rTR + $rBL + $rBR == 0 ) { - return $this->_computed_border_radius = array( - 0, 0, 0, 0, - "top-left" => 0, - "top-right" => 0, - "bottom-right" => 0, - "bottom-left" => 0, - ); - } - - $t = $this->__get("border_top_width"); - $r = $this->__get("border_right_width"); - $b = $this->__get("border_bottom_width"); - $l = $this->__get("border_left_width"); - - $rTL = min($rTL, $h - $rBL - $t/2 - $b/2, $w - $rTR - $l/2 - $r/2); - $rTR = min($rTR, $h - $rBR - $t/2 - $b/2, $w - $rTL - $l/2 - $r/2); - $rBL = min($rBL, $h - $rTL - $t/2 - $b/2, $w - $rBR - $l/2 - $r/2); - $rBR = min($rBR, $h - $rTR - $t/2 - $b/2, $w - $rBL - $l/2 - $r/2); - - return $this->_computed_border_radius = array( - $rTL, $rTR, $rBR, $rBL, - "top-left" => $rTL, - "top-right" => $rTR, - "bottom-right" => $rBR, - "bottom-left" => $rBL, - ); - } - /**#@-*/ - - - /** - * Returns the outline color as an array - * - * See {@link Style::get_color()} - * - * @link http://www.w3.org/TR/CSS21/box.html#border-color-properties - * @return array - */ - function get_outline_color() { - if ( $this->_props["outline_color"] === "" ) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["outline_color"] = null; - $this->_props["outline_color"] = $this->__get("color"); - } - - return $this->munge_color($this->_props["outline_color"]); - } - - /**#@+ - * Returns the outline width, as it is currently stored - * @return float|string - */ - function get_outline_width() { - $style = $this->__get("outline_style"); - return $style !== "none" && $style !== "hidden" ? $this->length_in_pt($this->_props["outline_width"]) : 0; - } - - /**#@+ - * Return full outline properties as a string - * - * Outline properties are returned just as specified in CSS: - *
[width] [style] [color]
- * e.g. "1px solid blue" - * - * @link http://www.w3.org/TR/CSS21/box.html#border-shorthand-properties - * @return string - */ - function get_outline() { - $color = $this->__get("outline_color"); - return - $this->__get("outline_width") . " " . - $this->__get("outline_style") . " " . - $color["hex"]; - } - /**#@-*/ - - /** - * Returns border spacing as an array - * - * The array has the format (h_space,v_space) - * - * @link http://www.w3.org/TR/CSS21/tables.html#propdef-border-spacing - * @return array - */ - function get_border_spacing() { - $arr = explode(" ", $this->_props["border_spacing"]); - if ( count($arr) == 1 ) { - $arr[1] = $arr[0]; - } - return $arr; - } - -/*==============================*/ - - /* - !important attribute - For basic functionality of the !important attribute with overloading - of several styles of an element, changes in inherit(), merge() and _parse_properties() - are sufficient [helpers var $_important_props, __construct(), important_set(), important_get()] - - Only for combined attributes extra treatment needed. See below. - - div { border: 1px red; } - div { border: solid; } // Not combined! Only one occurence of same style per context - // - div { border: 1px red; } - div a { border: solid; } // Adding to border style ok by inheritance - // - div { border-style: solid; } // Adding to border style ok because of different styles - div { border: 1px red; } - // - div { border-style: solid; !important} // border: overrides, even though not !important - div { border: 1px dashed red; } - // - div { border: 1px red; !important } - div a { border-style: solid; } // Need to override because not set - - Special treatment: - At individual property like border-top-width need to check whether overriding value is also !important. - Also store the !important condition for later overrides. - Since not known who is initiating the override, need to get passed !important as parameter. - !important Paramter taken as in the original style in the css file. - When property border !important given, do not mark subsets like border_style as important. Only - individual properties. - - Note: - Setting individual property directly from css with e.g. set_border_top_style() is not needed, because - missing set funcions handled by a generic handler __set(), including the !important. - Setting individual property of as sub-property is handled below. - - Implementation see at _set_style_side_type() - Callers _set_style_sides_type(), _set_style_type, _set_style_type_important() - - Related functionality for background, padding, margin, font, list_style - */ - - /* Generalized set function for individual attribute of combined style. - * With check for !important - * Applicable for background, border, padding, margin, font, list_style - * Note: $type has a leading underscore (or is empty), the others not. - */ - protected function _set_style_side_type($style, $side, $type, $val, $important) { - $prop = $style.'_'.$side.$type; - - if ( !isset($this->_important_props[$prop]) || $important) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$prop] = null; - if ( $important ) { - $this->_important_props[$prop] = true; - } - $this->_props[$prop] = $val; - } - } - - protected function _set_style_sides_type($style,$top,$right,$bottom,$left,$type,$important) { - $this->_set_style_side_type($style,'top',$type,$top,$important); - $this->_set_style_side_type($style,'right',$type,$right,$important); - $this->_set_style_side_type($style,'bottom',$type,$bottom,$important); - $this->_set_style_side_type($style,'left',$type,$left,$important); - } - - protected function _set_style_type($style,$type,$val,$important) { - $val = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces - $arr = explode(" ", $val); - - switch (count($arr)) { - case 1: $this->_set_style_sides_type($style,$arr[0],$arr[0],$arr[0],$arr[0],$type,$important); break; - case 2: $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[0],$arr[1],$type,$important); break; - case 3: $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[2],$arr[1],$type,$important); break; - case 4: $this->_set_style_sides_type($style,$arr[0],$arr[1],$arr[2],$arr[3],$type,$important); break; - } - - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$style.$type] = null; - $this->_props[$style.$type] = $val; - } - - protected function _set_style_type_important($style,$type,$val) { - $this->_set_style_type($style,$type,$val,isset($this->_important_props[$style.$type])); - } - - /* Anyway only called if _important matches and is assigned - * E.g. _set_style_side_type($style,$side,'',str_replace("none", "0px", $val),isset($this->_important_props[$style.'_'.$side])); - */ - protected function _set_style_side_width_important($style,$side,$val) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$style.'_'.$side] = null; - $this->_props[$style.'_'.$side] = str_replace("none", "0px", $val); - } - - protected function _set_style($style,$val,$important) { - if ( !isset($this->_important_props[$style]) || $important) { - if ( $important ) { - $this->_important_props[$style] = true; - } - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$style] = null; - $this->_props[$style] = $val; - } - } - - protected function _image($val) { - $DEBUGCSS=DEBUGCSS; - $parsed_url = "none"; - - if ( mb_strpos($val, "url") === false ) { - $path = "none"; //Don't resolve no image -> otherwise would prefix path and no longer recognize as none - } - else { - $val = preg_replace("/url\(['\"]?([^'\")]+)['\"]?\)/","\\1", trim($val)); - - // Resolve the url now in the context of the current stylesheet - $parsed_url = explode_url($val); - if ( $parsed_url["protocol"] == "" && $this->_stylesheet->get_protocol() == "" ) { - if ($parsed_url["path"][0] === '/' || $parsed_url["path"][0] === '\\' ) { - $path = $_SERVER["DOCUMENT_ROOT"].'/'; - } - else { - $path = $this->_stylesheet->get_base_path(); - } - - $path .= $parsed_url["path"] . $parsed_url["file"]; - $path = realpath($path); - // If realpath returns FALSE then specifically state that there is no background image - if ( !$path ) { - $path = 'none'; - } - } - else { - $path = build_url($this->_stylesheet->get_protocol(), - $this->_stylesheet->get_host(), - $this->_stylesheet->get_base_path(), - $val); - } - } - if ($DEBUGCSS) { - print "
[_image\n";
-      print_r($parsed_url);
-      print $this->_stylesheet->get_protocol()."\n".$this->_stylesheet->get_base_path()."\n".$path."\n";
-      print "_image]
";; - } - return $path; - } - -/*======================*/ - - /** - * Sets color - * - * The color parameter can be any valid CSS color value - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-color - * @param string $color - */ - function set_color($color) { - $col = $this->munge_color($color); - - if ( is_null($col) || !isset($col["hex"]) ) { - $color = "inherit"; - } - else { - $color = $col["hex"]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["color"] = null; - $this->_props["color"] = $color; - } - - /** - * Sets the background color - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-color - * @param string $color - */ - function set_background_color($color) { - $col = $this->munge_color($color); - - if ( is_null($col) ) { - return; - //$col = self::$_defaults["background_color"]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background_color"] = null; - $this->_props["background_color"] = is_array($col) ? $col["hex"] : $col; - } - - /** - * Set the background image url - * @link http://www.w3.org/TR/CSS21/colors.html#background-properties - * - * @param string $val - */ - function set_background_image($val) { - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background_image"] = null; - $this->_props["background_image"] = $this->_image($val); - } - - /** - * Sets the background repeat - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-repeat - * @param string $val - */ - function set_background_repeat($val) { - if ( is_null($val) ) { - $val = self::$_defaults["background_repeat"]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background_repeat"] = null; - $this->_props["background_repeat"] = $val; - } - - /** - * Sets the background attachment - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-attachment - * @param string $val - */ - function set_background_attachment($val) { - if ( is_null($val) ) { - $val = self::$_defaults["background_attachment"]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background_attachment"] = null; - $this->_props["background_attachment"] = $val; - } - - /** - * Sets the background position - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background-position - * @param string $val - */ - function set_background_position($val) { - if ( is_null($val) ) { - $val = self::$_defaults["background_position"]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background_position"] = null; - $this->_props["background_position"] = $val; - } - - /** - * Sets the background - combined options - * - * @link http://www.w3.org/TR/CSS21/colors.html#propdef-background - * @param string $val - */ - function set_background($val) { - $val = trim($val); - $important = isset($this->_important_props["background"]); - - if ( $val === "none" ) { - $this->_set_style("background_image", "none", $important); - $this->_set_style("background_color", "transparent", $important); - } - else { - $pos = array(); - $tmp = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces - $tmp = preg_split("/\s+/", $tmp); - - foreach($tmp as $attr) { - if ( mb_substr($attr, 0, 3) === "url" || $attr === "none" ) { - $this->_set_style("background_image", $this->_image($attr), $important); - } - elseif ( $attr === "fixed" || $attr === "scroll" ) { - $this->_set_style("background_attachment", $attr, $important); - } - elseif ( $attr === "repeat" || $attr === "repeat-x" || $attr === "repeat-y" || $attr === "no-repeat" ) { - $this->_set_style("background_repeat", $attr, $important); - } - elseif ( ($col = $this->munge_color($attr)) != null ) { - $this->_set_style("background_color", is_array($col) ? $col["hex"] : $col, $important); - } - else { - $pos[] = $attr; - } - } - - if (count($pos)) { - $this->_set_style("background_position", implode(" ", $pos), $important); - } - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["background"] = null; - $this->_props["background"] = $val; - } - - /** - * Sets the font size - * - * $size can be any acceptable CSS size - * - * @link http://www.w3.org/TR/CSS21/fonts.html#propdef-font-size - * @param string|float $size - */ - function set_font_size($size) { - $this->__font_size_calculated = false; - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["font_size"] = null; - $this->_props["font_size"] = $size; - } - - /** - * Sets the font style - * - * combined attributes - * set individual attributes also, respecting !important mark - * exactly this order, separate by space. Multiple fonts separated by comma: - * font-style, font-variant, font-weight, font-size, line-height, font-family - * - * Other than with border and list, existing partial attributes should - * reset when starting here, even when not mentioned. - * If individual attribute is !important and explicite or implicite replacement is not, - * keep individual attribute - * - * require whitespace as delimiters for single value attributes - * On delimiter "/" treat first as font height, second as line height - * treat all remaining at the end of line as font - * font-style, font-variant, font-weight, font-size, line-height, font-family - * - * missing font-size and font-family might be not allowed, but accept it here and - * use default (medium size, enpty font name) - * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style - * @param $val - */ - function set_font($val) { - $this->__font_size_calculated = false; - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["font"] = null; - $this->_props["font"] = $val; - - $important = isset($this->_important_props["font"]); - - if ( preg_match("/^(italic|oblique|normal)\s*(.*)$/i",$val,$match) ) { - $this->_set_style("font_style", $match[1], $important); - $val = $match[2]; - } - else { - $this->_set_style("font_style", self::$_defaults["font_style"], $important); - } - - if ( preg_match("/^(small-caps|normal)\s*(.*)$/i",$val,$match) ) { - $this->_set_style("font_variant", $match[1], $important); - $val = $match[2]; - } - else { - $this->_set_style("font_variant", self::$_defaults["font_variant"], $important); - } - - //matching numeric value followed by unit -> this is indeed a subsequent font size. Skip! - if ( preg_match("/^(bold|bolder|lighter|100|200|300|400|500|600|700|800|900|normal)\s*(.*)$/i", $val, $match) && - !preg_match("/^(?:pt|px|pc|em|ex|in|cm|mm|%)/",$match[2]) - ) { - $this->_set_style("font_weight", $match[1], $important); - $val = $match[2]; - } - else { - $this->_set_style("font_weight", self::$_defaults["font_weight"], $important); - } - - if ( preg_match("/^(xx-small|x-small|small|medium|large|x-large|xx-large|smaller|larger|\d+\s*(?:pt|px|pc|em|ex|in|cm|mm|%))\s*(.*)$/i",$val,$match) ) { - $this->_set_style("font_size", $match[1], $important); - $val = $match[2]; - if ( preg_match("/^\/\s*(\d+\s*(?:pt|px|pc|em|ex|in|cm|mm|%))\s*(.*)$/i", $val, $match ) ) { - $this->_set_style("line_height", $match[1], $important); - $val = $match[2]; - } - else { - $this->_set_style("line_height", self::$_defaults["line_height"], $important); - } - } - else { - $this->_set_style("font_size", self::$_defaults["font_size"], $important); - $this->_set_style("line_height", self::$_defaults["line_height"], $important); - } - - if( strlen($val) != 0 ) { - $this->_set_style("font_family", $val, $important); - } - else { - $this->_set_style("font_family", self::$_defaults["font_family"], $important); - } - } - - /**#@+ - * Sets page break properties - * - * @link http://www.w3.org/TR/CSS21/page.html#page-breaks - * @param string $break - */ - function set_page_break_before($break) { - if ( $break === "left" || $break === "right" ) { - $break = "always"; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["page_break_before"] = null; - $this->_props["page_break_before"] = $break; - } - - function set_page_break_after($break) { - if ( $break === "left" || $break === "right" ) { - $break = "always"; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["page_break_after"] = null; - $this->_props["page_break_after"] = $break; - } - /**#@-*/ - - //........................................................................ - - /**#@+ - * Sets the margin size - * - * @link http://www.w3.org/TR/CSS21/box.html#margin-properties - * @param $val - */ - function set_margin_top($val) { - $this->_set_style_side_width_important('margin','top',$val); - } - - function set_margin_right($val) { - $this->_set_style_side_width_important('margin','right',$val); - } - - function set_margin_bottom($val) { - $this->_set_style_side_width_important('margin','bottom',$val); - } - - function set_margin_left($val) { - $this->_set_style_side_width_important('margin','left',$val); - } - - function set_margin($val) { - $val = str_replace("none", "0px", $val); - $this->_set_style_type_important('margin','',$val); - } - /**#@-*/ - - /**#@+ - * Sets the padding size - * - * @link http://www.w3.org/TR/CSS21/box.html#padding-properties - * @param $val - */ - function set_padding_top($val) { - $this->_set_style_side_width_important('padding','top',$val); - } - - function set_padding_right($val) { - $this->_set_style_side_width_important('padding','right',$val); - } - - function set_padding_bottom($val) { - $this->_set_style_side_width_important('padding','bottom',$val); - } - - function set_padding_left($val) { - $this->_set_style_side_width_important('padding','left',$val); - } - - function set_padding($val) { - $val = str_replace("none", "0px", $val); - $this->_set_style_type_important('padding','',$val); - } - /**#@-*/ - - /** - * Sets a single border - * - * @param string $side - * @param string $border_spec ([width] [style] [color]) - * @param boolean $important - */ - protected function _set_border($side, $border_spec, $important) { - $border_spec = preg_replace("/\s*\,\s*/", ",", $border_spec); - //$border_spec = str_replace(",", " ", $border_spec); // Why did we have this ?? rbg(10, 102, 10) > rgb(10 102 10) - $arr = explode(" ", $border_spec); - - // FIXME: handle partial values - - //For consistency of individal and combined properties, and with ie8 and firefox3 - //reset all attributes, even if only partially given - $this->_set_style_side_type('border',$side,'_style',self::$_defaults['border_'.$side.'_style'],$important); - $this->_set_style_side_type('border',$side,'_width',self::$_defaults['border_'.$side.'_width'],$important); - $this->_set_style_side_type('border',$side,'_color',self::$_defaults['border_'.$side.'_color'],$important); - - foreach ($arr as $value) { - $value = trim($value); - if ( in_array($value, self::$BORDER_STYLES) ) { - $this->_set_style_side_type('border',$side,'_style',$value,$important); - } - else if ( preg_match("/[.0-9]+(?:px|pt|pc|em|ex|%|in|mm|cm)|(?:thin|medium|thick)/", $value ) ) { - $this->_set_style_side_type('border',$side,'_width',$value,$important); - } - else { - // must be color - $this->_set_style_side_type('border',$side,'_color',$value,$important); - } - } - - //see __set and __get, on all assignments clear cache! - $this->_prop_cache['border_'.$side] = null; - $this->_props['border_'.$side] = $border_spec; - } - - /** - * Sets the border styles - * - * @link http://www.w3.org/TR/CSS21/box.html#border-properties - * @param string $val - */ - function set_border_top($val) { - $this->_set_border("top", $val, isset($this->_important_props['border_top'])); - } - - function set_border_right($val) { - $this->_set_border("right", $val, isset($this->_important_props['border_right'])); - } - - function set_border_bottom($val) { - $this->_set_border("bottom", $val, isset($this->_important_props['border_bottom'])); - } - - function set_border_left($val) { - $this->_set_border("left", $val, isset($this->_important_props['border_left'])); - } - - function set_border($val) { - $important = isset($this->_important_props["border"]); - $this->_set_border("top", $val, $important); - $this->_set_border("right", $val, $important); - $this->_set_border("bottom", $val, $important); - $this->_set_border("left", $val, $important); - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["border"] = null; - $this->_props["border"] = $val; - } - - function set_border_width($val) { - $this->_set_style_type_important('border','_width',$val); - } - - function set_border_color($val) { - $this->_set_style_type_important('border','_color',$val); - } - - function set_border_style($val) { - $this->_set_style_type_important('border','_style',$val); - } - - /** - * Sets the border radius size - * - * http://www.w3.org/TR/css3-background/#corners - */ - function set_border_top_left_radius($val) { - $this->_set_border_radius_corner($val, "top_left"); - } - - function set_border_top_right_radius($val) { - $this->_set_border_radius_corner($val, "top_right"); - } - - function set_border_bottom_left_radius($val) { - $this->_set_border_radius_corner($val, "bottom_left"); - } - - function set_border_bottom_right_radius($val) { - $this->_set_border_radius_corner($val, "bottom_right"); - } - - function set_border_radius($val) { - $val = preg_replace("/\s*\,\s*/", ",", $val); // when border-radius has spaces - $arr = explode(" ", $val); - - switch (count($arr)) { - case 1: $this->_set_border_radii($arr[0],$arr[0],$arr[0],$arr[0]); break; - case 2: $this->_set_border_radii($arr[0],$arr[1],$arr[0],$arr[1]); break; - case 3: $this->_set_border_radii($arr[0],$arr[1],$arr[2],$arr[1]); break; - case 4: $this->_set_border_radii($arr[0],$arr[1],$arr[2],$arr[3]); break; - } - } - - protected function _set_border_radii($val1, $val2, $val3, $val4) { - $this->_set_border_radius_corner($val1, "top_left"); - $this->_set_border_radius_corner($val2, "top_right"); - $this->_set_border_radius_corner($val3, "bottom_right"); - $this->_set_border_radius_corner($val4, "bottom_left"); - } - - protected function _set_border_radius_corner($val, $corner) { - $this->_has_border_radius = true; - - //see __set and __get, on all assignments clear cache! - $this->_prop_cache["border_" . $corner . "_radius"] = null; - - $this->_props["border_" . $corner . "_radius"] = $this->length_in_pt($val); - } - - /** - * Sets the outline styles - * - * @link http://www.w3.org/TR/CSS21/ui.html#dynamic-outlines - * @param string $val - */ - function set_outline($val) { - $important = isset($this->_important_props["outline"]); - - $props = array( - "outline_style", - "outline_width", - "outline_color", - ); - - foreach($props as $prop) { - $_val = self::$_defaults[$prop]; - - if ( !isset($this->_important_props[$prop]) || $important) { - //see __set and __get, on all assignments clear cache! - $this->_prop_cache[$prop] = null; - if ( $important ) { - $this->_important_props[$prop] = true; - } - $this->_props[$prop] = $_val; - } - } - - $val = preg_replace("/\s*\,\s*/", ",", $val); // when rgb() has spaces - $arr = explode(" ", $val); - foreach ($arr as $value) { - $value = trim($value); - - if ( in_array($value, self::$BORDER_STYLES) ) { - $this->set_outline_style($value); - } - else if ( preg_match("/[.0-9]+(?:px|pt|pc|em|ex|%|in|mm|cm)|(?:thin|medium|thick)/", $value ) ) { - $this->set_outline_width($value); - } - else { - // must be color - $this->set_outline_color($value); - } - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["outline"] = null; - $this->_props["outline"] = $val; - } - - function set_outline_width($val) { - $this->_set_style_type_important('outline','_width',$val); - } - - function set_outline_color($val) { - $this->_set_style_type_important('outline','_color',$val); - } - - function set_outline_style($val) { - $this->_set_style_type_important('outline','_style',$val); - } - - /** - * Sets the border spacing - * - * @link http://www.w3.org/TR/CSS21/box.html#border-properties - * @param float $val - */ - function set_border_spacing($val) { - $arr = explode(" ", $val); - - if ( count($arr) == 1 ) { - $arr[1] = $arr[0]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["border_spacing"] = null; - $this->_props["border_spacing"] = "$arr[0] $arr[1]"; - } - - /** - * Sets the list style image - * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-image - * @param $val - */ - function set_list_style_image($val) { - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["list_style_image"] = null; - $this->_props["list_style_image"] = $this->_image($val); - } - - /** - * Sets the list style - * - * @link http://www.w3.org/TR/CSS21/generate.html#propdef-list-style - * @param $val - */ - function set_list_style($val) { - $important = isset($this->_important_props["list_style"]); - $arr = explode(" ", str_replace(",", " ", $val)); - - static $types = array( - "disc", "circle", "square", - "decimal-leading-zero", "decimal", "1", - "lower-roman", "upper-roman", "a", "A", - "lower-greek", - "lower-latin", "upper-latin", - "lower-alpha", "upper-alpha", - "armenian", "georgian", "hebrew", - "cjk-ideographic", "hiragana", "katakana", - "hiragana-iroha", "katakana-iroha", "none" - ); - - static $positions = array("inside", "outside"); - - foreach ($arr as $value) { - /* http://www.w3.org/TR/CSS21/generate.html#list-style - * A value of 'none' for the 'list-style' property sets both 'list-style-type' and 'list-style-image' to 'none' - */ - if ( $value === "none" ) { - $this->_set_style("list_style_type", $value, $important); - $this->_set_style("list_style_image", $value, $important); - continue; - } - - //On setting or merging or inheriting list_style_image as well as list_style_type, - //and url exists, then url has precedence, otherwise fall back to list_style_type - //Firefox is wrong here (list_style_image gets overwritten on explicite list_style_type) - //Internet Explorer 7/8 and dompdf is right. - - if ( mb_substr($value, 0, 3) === "url" ) { - $this->_set_style("list_style_image", $this->_image($value), $important); - continue; - } - - if ( in_array($value, $types) ) { - $this->_set_style("list_style_type", $value, $important); - } - else if ( in_array($value, $positions) ) { - $this->_set_style("list_style_position", $value, $important); - } - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["list_style"] = null; - $this->_props["list_style"] = $val; - } - - function set_size($val) { - $length_re = "/(\d+\s*(?:pt|px|pc|em|ex|in|cm|mm|%))/"; - - $val = mb_strtolower($val); - - if ( $val === "auto" ) { - return; - } - - $parts = preg_split("/\s+/", $val); - - $computed = array(); - if ( preg_match($length_re, $parts[0]) ) { - $computed[] = $this->length_in_pt($parts[0]); - - if ( isset($parts[1]) && preg_match($length_re, $parts[1]) ) { - $computed[] = $this->length_in_pt($parts[1]); - } - else { - $computed[] = $computed[0]; - } - } - elseif ( isset(CPDF_Adapter::$PAPER_SIZES[$parts[0]]) ) { - $computed = array_slice(CPDF_Adapter::$PAPER_SIZES[$parts[0]], 2, 2); - - if ( isset($parts[1]) && $parts[1] === "landscape" ) { - $computed = array_reverse($computed); - } - } - else { - return; - } - - $this->_props["size"] = $computed; - } - - /** - * Sets the CSS3 transform property - * - * @link http://www.w3.org/TR/css3-2d-transforms/#transform-property - * @param string $val - */ - function set_transform($val) { - $number = "\s*([^,\s]+)\s*"; - $tr_value = "\s*([^,\s]+)\s*"; - $angle = "\s*([^,\s]+(?:deg|rad)?)\s*"; - - if ( !preg_match_all("/[a-z]+\([^\)]+\)/i", $val, $parts, PREG_SET_ORDER) ) { - return; - } - - $functions = array( - //"matrix" => "\($number,$number,$number,$number,$number,$number\)", - - "translate" => "\($tr_value(?:,$tr_value)?\)", - "translateX" => "\($tr_value\)", - "translateY" => "\($tr_value\)", - - "scale" => "\($number(?:,$number)?\)", - "scaleX" => "\($number\)", - "scaleY" => "\($number\)", - - "rotate" => "\($angle\)", - - "skew" => "\($angle(?:,$angle)?\)", - "skewX" => "\($angle\)", - "skewY" => "\($angle\)", - ); - - $transforms = array(); - - foreach($parts as $part) { - $t = $part[0]; - - foreach($functions as $name => $pattern) { - if ( preg_match("/$name\s*$pattern/i", $t, $matches) ) { - $values = array_slice($matches, 1); - - switch($name) { - // units - case "rotate": - case "skew": - case "skewX": - case "skewY": - - foreach($values as $i => $value) { - if ( strpos($value, "rad") ) { - $values[$i] = rad2deg(floatval($value)); - } - else { - $values[$i] = floatval($value); - } - } - - switch($name) { - case "skew": - if ( !isset($values[1]) ) { - $values[1] = 0; - } - break; - case "skewX": - $name = "skew"; - $values = array($values[0], 0); - break; - case "skewY": - $name = "skew"; - $values = array(0, $values[0]); - break; - } - break; - - // units - case "translate": - $values[0] = $this->length_in_pt($values[0], $this->width); - - if ( isset($values[1]) ) { - $values[1] = $this->length_in_pt($values[1], $this->height); - } - else { - $values[1] = 0; - } - break; - - case "translateX": - $name = "translate"; - $values = array($this->length_in_pt($values[0], $this->width), 0); - break; - - case "translateY": - $name = "translate"; - $values = array(0, $this->length_in_pt($values[0], $this->height)); - break; - - // units - case "scale": - if ( !isset($values[1]) ) { - $values[1] = $values[0]; - } - break; - - case "scaleX": - $name = "scale"; - $values = array($values[0], 1.0); - break; - - case "scaleY": - $name = "scale"; - $values = array(1.0, $values[0]); - break; - } - - $transforms[] = array( - $name, - $values, - ); - } - } - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["transform"] = null; - $this->_props["transform"] = $transforms; - } - - function set__webkit_transform($val) { - $this->set_transform($val); - } - - function set__webkit_transform_origin($val) { - $this->set_transform_origin($val); - } - - /** - * Sets the CSS3 transform-origin property - * - * @link http://www.w3.org/TR/css3-2d-transforms/#transform-origin - * @param string $val - */ - function set_transform_origin($val) { - $values = preg_split("/\s+/", $val); - - if ( count($values) === 0) { - return; - } - - foreach($values as &$value) { - if ( in_array($value, array("top", "left")) ) { - $value = 0; - } - - if ( in_array($value, array("bottom", "right")) ) { - $value = "100%"; - } - } - - if ( !isset($values[1]) ) { - $values[1] = $values[0]; - } - - //see __set and __get, on all assignments clear cache, not needed on direct set through __set - $this->_prop_cache["transform_origin"] = null; - $this->_props["transform_origin"] = $values; - } - - protected function parse_image_resolution($val) { - // If exif data could be get: - // $re = '/^\s*(\d+|normal|auto)(?:\s*,\s*(\d+|normal))?\s*$/'; - - $re = '/^\s*(\d+|normal|auto)\s*$/'; - - if ( !preg_match($re, $val, $matches) ) { - return null; - } - - return $matches[1]; - } - - // auto | normal | dpi - function set_background_image_resolution($val) { - $parsed = $this->parse_image_resolution($val); - - $this->_prop_cache["background_image_resolution"] = null; - $this->_props["background_image_resolution"] = $parsed; - } - - // auto | normal | dpi - function set_image_resolution($val) { - $parsed = $this->parse_image_resolution($val); - - $this->_prop_cache["image_resolution"] = null; - $this->_props["image_resolution"] = $parsed; - } - - function set__dompdf_background_image_resolution($val) { - $this->set_background_image_resolution($val); - } - - function set__dompdf_image_resolution($val) { - $this->set_image_resolution($val); - } - - function set_z_index($val) { - if ( round($val) != $val && $val !== "auto" ) { - return; - } - - $this->_prop_cache["z_index"] = null; - $this->_props["z_index"] = $val; - } - - function set_counter_increment($val) { - $val = trim($val); - $value = null; - - if ( in_array($val, array("none", "inherit")) ) { - $value = $val; - } - else { - if ( preg_match_all("/(".self::CSS_IDENTIFIER.")(?:\s+(".self::CSS_INTEGER."))?/", $val, $matches, PREG_SET_ORDER) ){ - $value = array(); - foreach($matches as $match) { - $value[$match[1]] = isset($match[2]) ? $match[2] : 1; - } - } - } - - $this->_prop_cache["counter_increment"] = null; - $this->_props["counter_increment"] = $value; - } - - /** - * Generate a string representation of the Style - * - * This dumps the entire property array into a string via print_r. Useful - * for debugging. - * - * @return string - */ - /*DEBUGCSS print: see below additional debugging util*/ - function __toString() { - return print_r(array_merge(array("parent_font_size" => $this->_parent_font_size), - $this->_props), true); - } - -/*DEBUGCSS*/ function debug_print() { -/*DEBUGCSS*/ print "parent_font_size:".$this->_parent_font_size . ";\n"; -/*DEBUGCSS*/ foreach($this->_props as $prop => $val ) { -/*DEBUGCSS*/ print $prop.':'.$val; -/*DEBUGCSS*/ if (isset($this->_important_props[$prop])) { -/*DEBUGCSS*/ print '!important'; -/*DEBUGCSS*/ } -/*DEBUGCSS*/ print ";\n"; -/*DEBUGCSS*/ } -/*DEBUGCSS*/ } -} diff --git a/application/helpers/dompdf/include/stylesheet.cls.php b/application/helpers/dompdf/include/stylesheet.cls.php deleted file mode 100755 index 3b2ba3180..000000000 --- a/application/helpers/dompdf/include/stylesheet.cls.php +++ /dev/null @@ -1,1418 +0,0 @@ - - * @author Helmut Tischer - * @author Fabien Ménager - * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License - */ - -/** - * The location of the default built-in CSS file. - * {@link Stylesheet::DEFAULT_STYLESHEET} - */ -define('__DEFAULT_STYLESHEET', DOMPDF_LIB_DIR . DIRECTORY_SEPARATOR . "res" . DIRECTORY_SEPARATOR . "html.css"); - -/** - * The master stylesheet class - * - * The Stylesheet class is responsible for parsing stylesheets and style - * tags/attributes. It also acts as a registry of the individual Style - * objects generated by the current set of loaded CSS files and style - * elements. - * - * @see Style - * @package dompdf - */ -class Stylesheet { - - /** - * The location of the default built-in CSS file. - */ - const DEFAULT_STYLESHEET = __DEFAULT_STYLESHEET; - - /** - * User agent stylesheet origin - * - * @var int - */ - const ORIG_UA = 1; - - /** - * User normal stylesheet origin - * - * @var int - */ - const ORIG_USER = 2; - - /** - * Author normal stylesheet origin - * - * @var int - */ - const ORIG_AUTHOR = 3; - - private static $_stylesheet_origins = array( - self::ORIG_UA => -0x0FFFFFFF, // user agent style sheets - self::ORIG_USER => -0x0000FFFF, // user normal style sheets - self::ORIG_AUTHOR => 0x00000000, // author normal style sheets - ); - - /** - * Current dompdf instance - * - * @var DOMPDF - */ - private $_dompdf; - - /** - * Array of currently defined styles - * - * @var Style[] - */ - private $_styles; - - /** - * Base protocol of the document being parsed - * Used to handle relative urls. - * - * @var string - */ - private $_protocol; - - /** - * Base hostname of the document being parsed - * Used to handle relative urls. - * - * @var string - */ - private $_base_host; - - /** - * Base path of the document being parsed - * Used to handle relative urls. - * - * @var string - */ - private $_base_path; - - /** - * The styles defined by @page rules - * - * @var array + $child = $child->nextSibling; + } + } else { + $css = $tag->nodeValue; + } + + $this->css->load_css($css); + break; + } + } + } + + /** + * @param string $cacheId + * @deprecated + */ + public function enable_caching($cacheId) + { + $this->enableCaching($cacheId); + } + + /** + * Enable experimental caching capability + * + * @param string $cacheId + */ + public function enableCaching($cacheId) + { + $this->cacheId = $cacheId; + } + + /** + * @param string $value + * @return bool + * @deprecated + */ + public function parse_default_view($value) + { + return $this->parseDefaultView($value); + } + + /** + * @param string $value + * @return bool + */ + public function parseDefaultView($value) + { + $valid = array("XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV"); + + $options = preg_split("/\s*,\s*/", trim($value)); + $defaultView = array_shift($options); + + if (!in_array($defaultView, $valid)) { + return false; + } + + $this->setDefaultView($defaultView, $options); + return true; + } + + /** + * Renders the HTML to PDF + */ + public function render() + { + $this->saveLocale(); + + $logOutputFile = $this->options->getLogOutputFile(); + if ($logOutputFile) { + if (!file_exists($logOutputFile) && is_writable(dirname($logOutputFile))) { + touch($logOutputFile); + } + + $this->startTime = microtime(true); + ob_start(); + } + + $this->processHtml(); + + $this->css->apply_styles($this->tree); + + // @page style rules : size, margins + $pageStyles = $this->css->get_page_styles(); + + $basePageStyle = $pageStyles["base"]; + unset($pageStyles["base"]); + + foreach ($pageStyles as $pageStyle) { + $pageStyle->inherit($basePageStyle); + } + + if (is_array($basePageStyle->size)) { + $this->setPaper(array(0, 0, $basePageStyle->size[0], $basePageStyle->size[1])); + } + + //TODO: We really shouldn't be doing this; properties were already set in the constructor. We should add Canvas methods to set the page size and orientation after instantiaion (see #1059). + $this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation)); + $this->setFontMetrics(new FontMetrics($this->pdf, $this->getOptions())); + + if ($this->options->isFontSubsettingEnabled() && $this->pdf instanceof CPDF) { + foreach ($this->tree->get_frames() as $frame) { + $style = $frame->get_style(); + $node = $frame->get_node(); + + // Handle text nodes + if ($node->nodeName === "#text") { + $this->getCanvas()->register_string_subset($style->font_family, $node->nodeValue); + continue; + } + + // Handle generated content (list items) + if ($style->display === "list-item") { + $chars = ListBullet::get_counter_chars($style->list_style_type); + $this->getCanvas()->register_string_subset($style->font_family, $chars); + continue; + } + + // Handle other generated content (pseudo elements) + // FIXME: This only captures the text of the stylesheet declaration, + // not the actual generated content, and forces all possible counter + // values. See notes in issue #750. + if ($frame->get_node()->nodeName == "dompdf_generated") { + // all possible counter values + $chars = ListBullet::get_counter_chars('decimal'); + $this->getCanvas()->register_string_subset($style->font_family, $chars); + $chars = ListBullet::get_counter_chars('upper-alpha'); + $this->getCanvas()->register_string_subset($style->font_family, $chars); + $chars = ListBullet::get_counter_chars('lower-alpha'); + $this->getCanvas()->register_string_subset($style->font_family, $chars); + $chars = ListBullet::get_counter_chars('lower-greek'); + $this->getCanvas()->register_string_subset($style->font_family, $chars); + // the text of the stylesheet declaration + $this->getCanvas()->register_string_subset($style->font_family, $style->content); + continue; + } + } + } + + $root = null; + + foreach ($this->tree->get_frames() as $frame) { + // Set up the root frame + if (is_null($root)) { + $root = Factory::decorate_root($this->tree->get_root(), $this); + continue; + } + + // Create the appropriate decorators, reflowers & positioners. + Factory::decorate_frame($frame, $this, $root); + } + + // Add meta information + $title = $this->dom->getElementsByTagName("title"); + if ($title->length) { + $this->getCanvas()->add_info("Title", trim($title->item(0)->nodeValue)); + } + + $metas = $this->dom->getElementsByTagName("meta"); + $labels = array( + "author" => "Author", + "keywords" => "Keywords", + "description" => "Subject", + ); + foreach ($metas as $meta) { + $name = mb_strtolower($meta->getAttribute("name")); + $value = trim($meta->getAttribute("content")); + + if (isset($labels[$name])) { + $this->pdf->add_info($labels[$name], $value); + continue; + } + + if ($name === "dompdf.view" && $this->parseDefaultView($value)) { + $this->getCanvas()->set_default_view($this->defaultView, $this->defaultViewOptions); + } + } + + $root->set_containing_block(0, 0, $this->getCanvas()->get_width(), $this->getCanvas()->get_height()); + $root->set_renderer(new Renderer($this)); + + // This is where the magic happens: + $root->reflow(); + + // Clean up cached images + Cache::clear(); + + global $_dompdf_warnings, $_dompdf_show_warnings; + if ($_dompdf_show_warnings && isset($_dompdf_warnings)) { + echo 'Dompdf Warnings
';
+            foreach ($_dompdf_warnings as $msg) {
+                echo $msg . "\n";
+            }
+            echo $this->getCanvas()->get_cpdf()->messages;
+            echo '
'; + flush(); + } + + $this->restoreLocale(); + } + + /** + * Add meta information to the PDF after rendering + */ + public function add_info($label, $value) + { + if (!is_null($this->pdf)) { + $this->pdf->add_info($label, $value); + } + } + + /** + * Writes the output buffer in the log file + * + * @return void + */ + private function write_log() + { + $log_output_file = $this->get_option("log_output_file"); + if (!$log_output_file || !is_writable($log_output_file)) { + return; + } + + $frames = Frame::$ID_COUNTER; + $memory = memory_get_peak_usage(true) / 1024; + $time = (microtime(true) - $this->startTime) * 1000; + + $out = sprintf( + "%6d" . + "%10.2f KB" . + "%10.2f ms" . + " " . + ($this->quirksmode ? " ON" : "OFF") . + "
", $frames, $memory, $time); + + $out .= ob_get_clean(); + + $log_output_file = $this->get_option("log_output_file"); + file_put_contents($log_output_file, $out); + } + + /** + * Streams the PDF to the client + * + * The file will open a download dialog by default. The options + * parameter controls the output. Accepted options (array keys) are: + * + * 'Accept-Ranges' => 1 or 0 (=default): Send an 'Accept-Ranges:' + * HTTP header, see https://tools.ietf.org/html/rfc2616#section-14.5 + * This header seems to have caused some problems, despite the fact + * that it is supposed to solve them, so I am leaving it off by default. + * + * 'compress' = > 1 (=default) or 0: + * Apply content stream compression + * + * 'Attachment' => 1 (=default) or 0: + * Set the 'Content-Disposition:' HTTP header to 'attachment' + * (thereby causing the browser to open a download dialog) + * + * @param string $filename the name of the streamed file + * @param array $options header options (see above) + */ + public function stream($filename = 'document.pdf', $options = null) + { + $this->saveLocale(); + + $this->write_log(); + + if (!is_null($this->pdf)) { + $this->pdf->stream($filename, $options); + } + + $this->restoreLocale(); + } + + /** + * Returns the PDF as a string + * + * The file will open a download dialog by default. The options + * parameter controls the output. Accepted options are: + * + * + * 'compress' = > 1 or 0 - apply content stream compression, this is + * on (1) by default + * + * + * @param array $options options (see above) + * + * @return string + */ + public function output($options = null) + { + $this->saveLocale(); + + $this->write_log(); + + if (is_null($this->pdf)) { + return null; + } + + $output = $this->pdf->output($options); + + $this->restoreLocale(); + + return $output; + } + + /** + * @return string + * @deprecated + */ + public function output_html() + { + return $this->outputHtml(); + } + + /** + * Returns the underlying HTML document as a string + * + * @return string + */ + public function outputHtml() + { + return $this->dom->saveHTML(); + } + + /** + * Get the dompdf option value + * + * @param string $key + * @return mixed + * @deprecated + */ + public function get_option($key) + { + return $this->options->get($key); + } + + /** + * @param string $key + * @param mixed $value + * @return $this + * @deprecated + */ + public function set_option($key, $value) + { + $this->options->set($key, $value); + return $this; + } + + /** + * @param array $options + * @return $this + * @deprecated + */ + public function set_options(array $options) + { + $this->options->set($options); + return $this; + } + + /** + * @param string $size + * @param string $orientation + * @deprecated + */ + public function set_paper($size, $orientation = "portrait") + { + $this->setPaper($size, $orientation); + } + + /** + * Sets the paper size & orientation + * + * @param string $size 'letter', 'legal', 'A4', etc. {@link Dompdf\Adapter\CPDF::$PAPER_SIZES} + * @param string $orientation 'portrait' or 'landscape' + * @return $this + */ + public function setPaper($size, $orientation = "portrait") + { + $this->paperSize = $size; + $this->paperOrientation = $orientation; + return $this; + } + + /** + * @param FrameTree $tree + * @return $this + */ + public function setTree(FrameTree $tree) + { + $this->tree = $tree; + return $this; + } + + /** + * @return FrameTree + * @deprecated + */ + public function get_tree() + { + return $this->getTree(); + } + + /** + * Returns the underlying {@link FrameTree} object + * + * @return FrameTree + */ + public function getTree() + { + return $this->tree; + } + + /** + * @param string $protocol + * @return $this + * @deprecated + */ + public function set_protocol($protocol) + { + return $this->setProtocol($protocol); + } + + /** + * Sets the protocol to use + * FIXME validate these + * + * @param string $protocol + * @return $this + */ + public function setProtocol($protocol) + { + $this->protocol = $protocol; + return $this; + } + + /** + * @return string + * @deprecated + */ + public function get_protocol() + { + return $this->getProtocol(); + } + + /** + * Returns the protocol in use + * + * @return string + */ + public function getProtocol() + { + return $this->protocol; + } + + /** + * @param string $host + * @deprecated + */ + public function set_host($host) + { + $this->setBaseHost($host); + } + + /** + * Sets the base hostname + * + * @param string $baseHost + * @return $this + */ + public function setBaseHost($baseHost) + { + $this->baseHost = $baseHost; + return $this; + } + + /** + * @return string + * @deprecated + */ + public function get_host() + { + return $this->getBaseHost(); + } + + /** + * Returns the base hostname + * + * @return string + */ + public function getBaseHost() + { + return $this->baseHost; + } + + /** + * Sets the base path + * + * @param string $path + * @deprecated + */ + public function set_base_path($path) + { + $this->setBasePath($path); + } + + /** + * Sets the base path + * + * @param string $basePath + * @return $this + */ + public function setBasePath($basePath) + { + $this->basePath = $basePath; + return $this; + } + + /** + * @return string + * @deprecated + */ + public function get_base_path() + { + return $this->getBasePath(); + } + + /** + * Returns the base path + * + * @return string + */ + public function getBasePath() + { + return $this->basePath; + } + + /** + * @param string $default_view The default document view + * @param array $options The view's options + * @return $this + * @deprecated + */ + public function set_default_view($default_view, $options) + { + return $this->setDefaultView($default_view, $options); + } + + /** + * Sets the default view + * + * @param string $defaultView The default document view + * @param array $options The view's options + * @return $this + */ + public function setDefaultView($defaultView, $options) + { + $this->defaultView = $defaultView; + $this->defaultViewOptions = $options; + return $this; + } + + /** + * @param resource $http_context + * @return $this + * @deprecated + */ + public function set_http_context($http_context) + { + return $this->setHttpContext($http_context); + } + + /** + * Sets the HTTP context + * + * @param resource $httpContext + * @return $this + */ + public function setHttpContext($httpContext) + { + $this->httpContext = $httpContext; + return $this; + } + + /** + * @return resource + * @deprecated + */ + public function get_http_context() + { + return $this->getHttpContext(); + } + + /** + * Returns the HTTP context + * + * @return resource + */ + public function getHttpContext() + { + return $this->httpContext; + } + + /** + * @param Canvas $canvas + * @return $this + */ + public function setCanvas(Canvas $canvas) + { + $this->pdf = $canvas; + $this->canvas = $canvas; + return $this; + } + + /** + * @return Canvas + * @deprecated + */ + public function get_canvas() + { + return $this->getCanvas(); + } + + /** + * Return the underlying Canvas instance (e.g. Dompdf\Adapter\CPDF, Dompdf\Adapter\GD) + * + * @return Canvas + */ + public function getCanvas() + { + if (null === $this->canvas && null !== $this->pdf) { + return $this->pdf; + } + return $this->canvas; + } + + /** + * @param Stylesheet $css + * @return $this + */ + public function setCss(Stylesheet $css) + { + $this->css = $css; + return $this; + } + + /** + * @return Stylesheet + * @deprecated + */ + public function get_css() + { + return $this->getCss(); + } + + /** + * Returns the stylesheet + * + * @return Stylesheet + */ + public function getCss() + { + return $this->css; + } + + /** + * @param DOMDocument $dom + * @return $this + */ + public function setDom(DOMDocument $dom) + { + $this->dom = $dom; + return $this; + } + + /** + * @return DOMDocument + * @deprecated + */ + public function get_dom() + { + return $this->getDom(); + } + + /** + * @return DOMDocument + */ + public function getDom() + { + return $this->dom; + } + + /** + * @param Options $options + * @return $this + */ + public function setOptions(Options $options) + { + $this->options = $options; + $fontMetrics = $this->getFontMetrics(); + if (isset($fontMetrics)) { + $fontMetrics->setOptions($options); + } + return $this; + } + + /** + * @return Options + */ + public function getOptions() + { + return $this->options; + } + + /** + * @return array + * @deprecated + */ + public function get_callbacks() + { + return $this->getCallbacks(); + } + + /** + * Returns the callbacks array + * + * @return array + */ + public function getCallbacks() + { + return $this->callbacks; + } + + /** + * @param array $callbacks the set of callbacks to set + * @deprecated + */ + public function set_callbacks($callbacks) + { + $this->setCallbacks($callbacks); + } + + /** + * Sets callbacks for events like rendering of pages and elements. + * The callbacks array contains arrays with 'event' set to 'begin_page', + * 'end_page', 'begin_frame', or 'end_frame' and 'f' set to a function or + * object plus method to be called. + * + * The function 'f' must take an array as argument, which contains info + * about the event. + * + * @param array $callbacks the set of callbacks to set + */ + public function setCallbacks($callbacks) + { + if (is_array($callbacks)) { + $this->callbacks = array(); + foreach ($callbacks as $c) { + if (is_array($c) && isset($c['event']) && isset($c['f'])) { + $event = $c['event']; + $f = $c['f']; + if (is_callable($f) && is_string($event)) { + $this->callbacks[$event][] = $f; + } + } + } + } + } + + /** + * @return boolean + * @deprecated + */ + public function get_quirksmode() + { + return $this->getQuirksmode(); + } + + /** + * Get the quirks mode + * + * @return boolean true if quirks mode is active + */ + public function getQuirksmode() + { + return $this->quirksmode; + } + + /** + * @param FontMetrics $fontMetrics + * @return $this + */ + public function setFontMetrics(FontMetrics $fontMetrics) + { + $this->fontMetrics = $fontMetrics; + return $this; + } + + /** + * @return FontMetrics + */ + public function getFontMetrics() + { + return $this->fontMetrics; + } + + /** + * PHP5 overloaded getter + * Along with {@link Dompdf::__set()} __get() provides access to all + * properties directly. Typically __get() is not called directly outside + * of this class. + * + * @param string $prop + * + * @throws Exception + * @return mixed + */ + function __get($prop) + { + switch ($prop) + { + case 'version' : + return $this->version; + default: + throw new Exception( 'Invalid property: ' . $prop ); + } + } +} diff --git a/vendor/dompdf/dompdf/src/Exception.php b/vendor/dompdf/dompdf/src/Exception.php new file mode 100644 index 000000000..9729dc704 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Exception.php @@ -0,0 +1,30 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf; + +/** + * Standard exception thrown by DOMPDF classes + * + * @package dompdf + */ +class Exception extends \Exception +{ + + /** + * Class constructor + * + * @param string $message Error message + * @param int $code Error code + */ + function __construct($message = null, $code = 0) + { + parent::__construct($message, $code); + } + +} diff --git a/vendor/dompdf/dompdf/src/Exception/ImageException.php b/vendor/dompdf/dompdf/src/Exception/ImageException.php new file mode 100644 index 000000000..62b44b1c8 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Exception/ImageException.php @@ -0,0 +1,31 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Exception; + +use Dompdf\Exception; + +/** + * Image exception thrown by DOMPDF + * + * @package dompdf + */ +class ImageException extends Exception +{ + + /** + * Class constructor + * + * @param string $message Error message + * @param int $code Error code + */ + function __construct($message = null, $code = 0) + { + parent::__construct($message, $code); + } + +} diff --git a/vendor/dompdf/dompdf/src/FontMetrics.php b/vendor/dompdf/dompdf/src/FontMetrics.php new file mode 100644 index 000000000..d6601cbb2 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FontMetrics.php @@ -0,0 +1,603 @@ + + * @author Helmut Tischer + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf; + +use FontLib\Font; + +/** + * The font metrics class + * + * This class provides information about fonts and text. It can resolve + * font names into actual installed font files, as well as determine the + * size of text in a particular font and size. + * + * @static + * @package dompdf + */ +class FontMetrics +{ + /** + * Name of the font cache file + * + * This file must be writable by the webserver process only to update it + * with save_font_families() after adding the .afm file references of a new font family + * with FontMetrics::saveFontFamilies(). + * This is typically done only from command line with load_font.php on converting + * ttf fonts to ufm with php-font-lib. + */ + const CACHE_FILE = "dompdf_font_family_cache.php"; + + /** + * @var Canvas + * @deprecated + */ + protected $pdf; + + /** + * Underlying {@link Canvas} object to perform text size calculations + * + * @var Canvas + */ + protected $canvas; + + /** + * Array of font family names to font files + * + * Usually cached by the {@link load_font.php} script + * + * @var array + */ + protected $fontLookup = array(); + + /** + * @var Options + */ + private $options; + + /** + * Class initialization + */ + public function __construct(Canvas $canvas, Options $options) + { + $this->setCanvas($canvas); + $this->setOptions($options); + $this->loadFontFamilies(); + } + + /** + * @deprecated + */ + public function save_font_families() + { + $this->saveFontFamilies(); + } + + /** + * Saves the stored font family cache + * + * The name and location of the cache file are determined by {@link + * FontMetrics::CACHE_FILE}. This file should be writable by the + * webserver process. + * + * @see Font_Metrics::load_font_families() + */ + public function saveFontFamilies() + { + // replace the path to the DOMPDF font directories with the corresponding constants (allows for more portability) + $cacheData = sprintf("fontLookup as $family => $variants) { + $cacheData .= sprintf(" '%s' => array(%s", addslashes($family), PHP_EOL); + foreach ($variants as $variant => $path) { + $path = sprintf("'%s'", $path); + $path = str_replace('\'' . $this->getOptions()->getFontDir() , '$fontDir . \'' , $path); + $path = str_replace('\'' . $this->getOptions()->getRootDir() , '$rootDir . \'' , $path); + $cacheData .= sprintf(" '%s' => %s,%s", $variant, $path, PHP_EOL); + } + $cacheData .= sprintf(" ),%s", PHP_EOL); + } + $cacheData .= ") ?>"; + file_put_contents($this->getCacheFile(), $cacheData); + } + + /** + * @deprecated + */ + public function load_font_families() + { + $this->loadFontFamilies(); + } + + /** + * Loads the stored font family cache + * + * @see save_font_families() + */ + public function loadFontFamilies() + { + $fontDir = $this->getOptions()->getFontDir(); + $rootDir = $this->getOptions()->getRootDir(); + + // FIXME: tempoarary define constants for cache files <= v0.6.2 + if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); } + if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); } + + $file = $rootDir . "/lib/fonts/dompdf_font_family_cache.dist.php"; + $distFonts = require $file; + + // FIXME: temporary step for font cache created before the font cache fix + if (is_readable($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache")) { + $oldFonts = require $fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache"; + // If the font family cache is still in the old format + if ($oldFonts === 1) { + $cacheData = file_get_contents($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache"); + file_put_contents($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache", "<" . "?php return $cacheData ?" . ">"); + $oldFonts = require $fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache"; + } + $distFonts += $oldFonts; + } + + if (!is_readable($this->getCacheFile())) { + $this->fontLookup = $distFonts; + return; + } + + $cacheData = require $this->getCacheFile(); + + // If the font family cache is still in the old format + if ($cacheData === 1) { + $cacheData = file_get_contents($this->getCacheFile()); + file_put_contents($this->getCacheFile(), "<" . "?php return $cacheData ?" . ">"); + $this->fontLookup = require $this->getCacheFile(); + } + + $this->fontLookup = array(); + foreach ($cacheData as $key => $value) { + $this->fontLookup[stripslashes($key)] = $value; + } + + // Merge provided fonts + $this->fontLookup += $distFonts; + } + + /** + * @param array $files + * @return array + * @deprecated + */ + public function install_fonts($files) + { + return $this->installFonts($files); + } + + /** + * @param array $files + * @return array + */ + public function installFonts(array $files) + { + $names = array(); + + foreach ($files as $file) { + $font = Font::load($file); + $records = $font->getData("name", "records"); + $type = $this->getType($records[2]); + $names[mb_strtolower($records[1])][$type] = $file; + $font->close(); + } + + return $names; + } + + /** + * @param array $style + * @param string $remote_file + * @param resource $context + * @return bool + * @deprecated + */ + public function register_font($style, $remote_file, $context = null) + { + return $this->registerFont($style, $remote_file); + } + + /** + * @param array $style + * @param string $remoteFile + * @param resource $context + * @return bool + */ + public function registerFont($style, $remoteFile, $context = null) + { + $fontDir = $this->getOptions()->getFontDir(); + $fontname = mb_strtolower($style["family"]); + $families = $this->getFontFamilies(); + + $entry = array(); + if (isset($families[$fontname])) { + $entry = $families[$fontname]; + } + + $localFile = $fontDir . DIRECTORY_SEPARATOR . md5($remoteFile); + $localTempFile = $this->options->get('tempDir') . "/" . md5($remoteFile); + $cacheEntry = $localFile; + $localFile .= ".ttf"; + + $styleString = $this->getType("{$style['weight']} {$style['style']}"); + + if ( !isset($entry[$styleString]) ) { + $entry[$styleString] = $cacheEntry; + + // Download the remote file + $remoteFileContent = @file_get_contents($remoteFile, null, $context); + if (false === $remoteFileContent) { + return false; + } + file_put_contents($localTempFile, $remoteFileContent); + + $font = Font::load($localTempFile); + + if (!$font) { + unlink($localTempFile); + return false; + } + + $font->parse(); + $font->saveAdobeFontMetrics("$cacheEntry.ufm"); + $font->close(); + + unlink($localTempFile); + + if ( !file_exists("$cacheEntry.ufm") ) { + return false; + } + + // Save the changes + file_put_contents($localFile, file_get_contents($remoteFile, null, $context)); + + if ( !file_exists($localFile) ) { + unlink("$cacheEntry.ufm"); + return false; + } + + $this->setFontFamily($fontname, $entry); + $this->saveFontFamilies(); + } + + return true; + } + + /** + * @param $text + * @param $font + * @param $size + * @param float $word_spacing + * @param float $char_spacing + * @return float + * @deprecated + */ + public function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0) + { + //return self::$_pdf->get_text_width($text, $font, $size, $word_spacing, $char_spacing); + return $this->getTextWidth($text, $font, $size, $word_spacing, $char_spacing); + } + + /** + * Calculates text size, in points + * + * @param string $text the text to be sized + * @param string $font the desired font + * @param float $size the desired font size + * @param float $wordSpacing + * @param float $charSpacing + * + * @internal param float $spacing word spacing, if any + * @return float + */ + public function getTextWidth($text, $font, $size, $wordSpacing = 0.0, $charSpacing = 0.0) + { + // @todo Make sure this cache is efficient before enabling it + static $cache = array(); + + if ($text === "") { + return 0; + } + + // Don't cache long strings + $useCache = !isset($text[50]); // Faster than strlen + + $key = "$font/$size/$wordSpacing/$charSpacing"; + + if ($useCache && isset($cache[$key][$text])) { + return $cache[$key]["$text"]; + } + + $width = $this->getCanvas()->get_text_width($text, $font, $size, $wordSpacing, $charSpacing); + + if ($useCache) { + $cache[$key][$text] = $width; + } + + return $width; + } + + /** + * @param $font + * @param $size + * @return float + * @deprecated + */ + public function get_font_height($font, $size) + { + return $this->getFontHeight($font, $size); + } + + /** + * Calculates font height + * + * @param string $font + * @param float $size + * + * @return float + */ + public function getFontHeight($font, $size) + { + return $this->getCanvas()->get_font_height($font, $size); + } + + /** + * @param $family_raw + * @param string $subtype_raw + * @return string + * @deprecated + */ + public function get_font($family_raw, $subtype_raw = "normal") + { + return $this->getFont($family_raw, $subtype_raw); + } + + /** + * Resolves a font family & subtype into an actual font file + * Subtype can be one of 'normal', 'bold', 'italic' or 'bold_italic'. If + * the particular font family has no suitable font file, the default font + * ({@link Options::defaultFont}) is used. The font file returned + * is the absolute pathname to the font file on the system. + * + * @param string $familyRaw + * @param string $subtypeRaw + * + * @return string + */ + public function getFont($familyRaw, $subtypeRaw = "normal") + { + static $cache = array(); + + if (isset($cache[$familyRaw][$subtypeRaw])) { + return $cache[$familyRaw][$subtypeRaw]; + } + + /* Allow calling for various fonts in search path. Therefore not immediately + * return replacement on non match. + * Only when called with NULL try replacement. + * When this is also missing there is really trouble. + * If only the subtype fails, nevertheless return failure. + * Only on checking the fallback font, check various subtypes on same font. + */ + + $subtype = strtolower($subtypeRaw); + + if ($familyRaw) { + $family = str_replace(array("'", '"'), "", strtolower($familyRaw)); + + if (isset($this->fontLookup[$family][$subtype])) { + return $cache[$familyRaw][$subtypeRaw] = $this->fontLookup[$family][$subtype]; + } + + return null; + } + + $family = "serif"; + + if (isset($this->fontLookup[$family][$subtype])) { + return $cache[$familyRaw][$subtypeRaw] = $this->fontLookup[$family][$subtype]; + } + + if (!isset($this->fontLookup[$family])) { + return null; + } + + $family = $this->fontLookup[$family]; + + foreach ($family as $sub => $font) { + if (strpos($subtype, $sub) !== false) { + return $cache[$familyRaw][$subtypeRaw] = $font; + } + } + + if ($subtype !== "normal") { + foreach ($family as $sub => $font) { + if ($sub !== "normal") { + return $cache[$familyRaw][$subtypeRaw] = $font; + } + } + } + + $subtype = "normal"; + + if (isset($family[$subtype])) { + return $cache[$familyRaw][$subtypeRaw] = $family[$subtype]; + } + + return null; + } + + /** + * @param $family + * @return null|string + * @deprecated + */ + public function get_family($family) + { + return $this->getFamily($family); + } + + /** + * @param string $family + * @return null|string + */ + public function getFamily($family) + { + $family = str_replace(array("'", '"'), "", mb_strtolower($family)); + + if (isset($this->fontLookup[$family])) { + return $this->fontLookup[$family]; + } + + return null; + } + + /** + * @param $type + * @return string + * @deprecated + */ + public function get_type($type) + { + return $this->getType($type); + } + + /** + * @param string $type + * @return string + */ + public function getType($type) + { + if (preg_match("/bold/i", $type)) { + if (preg_match("/italic|oblique/i", $type)) { + $type = "bold_italic"; + } else { + $type = "bold"; + } + } elseif (preg_match("/italic|oblique/i", $type)) { + $type = "italic"; + } else { + $type = "normal"; + } + + return $type; + } + + /** + * @return array + * @deprecated + */ + public function get_system_fonts() + { + return $this->getSystemFonts(); + } + + /** + * @return array + */ + public function getSystemFonts() + { + $files = glob("/usr/share/fonts/truetype/*.ttf") + + glob("/usr/share/fonts/truetype/*/*.ttf") + + glob("/usr/share/fonts/truetype/*/*/*.ttf") + + glob("C:\\Windows\\fonts\\*.ttf") + + glob("C:\\WinNT\\fonts\\*.ttf") + + glob("/mnt/c_drive/WINDOWS/Fonts/"); + + return $this->installFonts($files); + } + + /** + * @return array + * @deprecated + */ + public function get_font_families() + { + return $this->getFontFamilies(); + } + + /** + * Returns the current font lookup table + * + * @return array + */ + public function getFontFamilies() + { + return $this->fontLookup; + } + + /** + * @param string $fontname + * @param mixed $entry + * @deprecated + */ + public function set_font_family($fontname, $entry) + { + $this->setFontFamily($fontname, $entry); + } + + /** + * @param string $fontname + * @param mixed $entry + */ + public function setFontFamily($fontname, $entry) + { + $this->fontLookup[mb_strtolower($fontname)] = $entry; + } + + /** + * @return string + */ + public function getCacheFile() + { + return $this->getOptions()->getFontDir() . DIRECTORY_SEPARATOR . self::CACHE_FILE; + } + + /** + * @param Options $options + * @return $this + */ + public function setOptions(Options $options) + { + $this->options = $options; + return $this; + } + + /** + * @return Options + */ + public function getOptions() + { + return $this->options; + } + + /** + * @param Canvas $canvas + * @return $this + */ + public function setCanvas(Canvas $canvas) + { + $this->pdf = $canvas; + $this->canvas = $canvas; + return $this; + } + + /** + * @return Canvas + */ + public function getCanvas() + { + return $this->canvas; + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Frame.php b/vendor/dompdf/dompdf/src/Frame.php new file mode 100644 index 000000000..6c2491d04 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame.php @@ -0,0 +1,1109 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +/** + * The main Frame class + * + * This class represents a single HTML element. This class stores + * positioning information as well as containing block location and + * dimensions. Style information for the element is stored in a {@link + * Style} object. Tree structure is maintained via the parent & children + * links. + * + * @package dompdf + */ +class Frame +{ + const WS_TEXT = 1; + const WS_SPACE = 2; + + /** + * The DOMElement or DOMText object this frame represents + * + * @var \DOMElement|\DOMText + */ + protected $_node; + + /** + * Unique identifier for this frame. Used to reference this frame + * via the node. + * + * @var string + */ + protected $_id; + + /** + * Unique id counter + */ + public static $ID_COUNTER = 0; /*protected*/ + + /** + * This frame's calculated style + * + * @var Style + */ + protected $_style; + + /** + * This frame's original style. Needed for cases where frames are + * split across pages. + * + * @var Style + */ + protected $_original_style; + + /** + * This frame's parent in the document tree. + * + * @var Frame + */ + protected $_parent; + + /** + * This frame's children + * + * @var Frame[] + */ + protected $_frame_list; + + /** + * This frame's first child. All children are handled as a + * doubly-linked list. + * + * @var Frame + */ + protected $_first_child; + + /** + * This frame's last child. + * + * @var Frame + */ + protected $_last_child; + + /** + * This frame's previous sibling in the document tree. + * + * @var Frame + */ + protected $_prev_sibling; + + /** + * This frame's next sibling in the document tree. + * + * @var Frame + */ + protected $_next_sibling; + + /** + * This frame's containing block (used in layout): array(x, y, w, h) + * + * @var float[] + */ + protected $_containing_block; + + /** + * Position on the page of the top-left corner of the margin box of + * this frame: array(x,y) + * + * @var float[] + */ + protected $_position; + + /** + * Absolute opacity of this frame + * + * @var float + */ + protected $_opacity; + + /** + * This frame's decorator + * + * @var \Dompdf\FrameDecorator\AbstractFrameDecorator + */ + protected $_decorator; + + /** + * This frame's containing line box + * + * @var LineBox + */ + protected $_containing_line; + + /** + * @var array + */ + protected $_is_cache = array(); + + /** + * Tells wether the frame was already pushed to the next page + * + * @var bool + */ + public $_already_pushed = false; + + /** + * @var bool + */ + public $_float_next_line = false; + + /** + * Tells wether the frame was split + * + * @var bool + */ + public $_splitted; + + /** + * @var int + */ + public static $_ws_state = self::WS_SPACE; + + /** + * Class constructor + * + * @param \DOMNode $node the DOMNode this frame represents + */ + public function __construct(\DOMNode $node) + { + $this->_node = $node; + + $this->_parent = null; + $this->_first_child = null; + $this->_last_child = null; + $this->_prev_sibling = $this->_next_sibling = null; + + $this->_style = null; + $this->_original_style = null; + + $this->_containing_block = array( + "x" => null, + "y" => null, + "w" => null, + "h" => null, + ); + + $this->_containing_block[0] =& $this->_containing_block["x"]; + $this->_containing_block[1] =& $this->_containing_block["y"]; + $this->_containing_block[2] =& $this->_containing_block["w"]; + $this->_containing_block[3] =& $this->_containing_block["h"]; + + $this->_position = array( + "x" => null, + "y" => null, + ); + + $this->_position[0] =& $this->_position["x"]; + $this->_position[1] =& $this->_position["y"]; + + $this->_opacity = 1.0; + $this->_decorator = null; + + $this->set_id(self::$ID_COUNTER++); + } + + /** + * WIP : preprocessing to remove all the unused whitespace + */ + protected function ws_trim() + { + if ($this->ws_keep()) { + return; + } + + if (self::$_ws_state === self::WS_SPACE) { + $node = $this->_node; + + if ($node->nodeName === "#text" && !empty($node->nodeValue)) { + $node->nodeValue = preg_replace("/[ \t\r\n\f]+/u", " ", trim($node->nodeValue)); + self::$_ws_state = self::WS_TEXT; + } + } + } + + /** + * @return bool + */ + protected function ws_keep() + { + $whitespace = $this->get_style()->white_space; + + return in_array($whitespace, array("pre", "pre-wrap", "pre-line")); + } + + /** + * @return bool + */ + protected function ws_is_text() + { + $node = $this->get_node(); + + if ($node->nodeName === "img") { + return true; + } + + if (!$this->is_in_flow()) { + return false; + } + + if ($this->is_text_node()) { + return trim($node->nodeValue) !== ""; + } + + return true; + } + + /** + * "Destructor": forcibly free all references held by this frame + * + * @param bool $recursive if true, call dispose on all children + */ + public function dispose($recursive = false) + { + if ($recursive) { + while ($child = $this->_first_child) { + $child->dispose(true); + } + } + + // Remove this frame from the tree + if ($this->_prev_sibling) { + $this->_prev_sibling->_next_sibling = $this->_next_sibling; + } + + if ($this->_next_sibling) { + $this->_next_sibling->_prev_sibling = $this->_prev_sibling; + } + + if ($this->_parent && $this->_parent->_first_child === $this) { + $this->_parent->_first_child = $this->_next_sibling; + } + + if ($this->_parent && $this->_parent->_last_child === $this) { + $this->_parent->_last_child = $this->_prev_sibling; + } + + if ($this->_parent) { + $this->_parent->get_node()->removeChild($this->_node); + } + + $this->_style->dispose(); + $this->_style = null; + unset($this->_style); + + $this->_original_style->dispose(); + $this->_original_style = null; + unset($this->_original_style); + + } + + /** + * Re-initialize the frame + */ + public function reset() + { + $this->_position["x"] = null; + $this->_position["y"] = null; + + $this->_containing_block["x"] = null; + $this->_containing_block["y"] = null; + $this->_containing_block["w"] = null; + $this->_containing_block["h"] = null; + + $this->_style = null; + unset($this->_style); + $this->_style = clone $this->_original_style; + } + + /** + * @return \DOMElement|\DOMText + */ + public function get_node() + { + return $this->_node; + } + + /** + * @return string + */ + public function get_id() + { + return $this->_id; + } + + /** + * @return Style + */ + public function get_style() + { + return $this->_style; + } + + /** + * @return Style + */ + public function get_original_style() + { + return $this->_original_style; + } + + /** + * @return Frame + */ + public function get_parent() + { + return $this->_parent; + } + + /** + * @return \Dompdf\FrameDecorator\AbstractFrameDecorator + */ + public function get_decorator() + { + return $this->_decorator; + } + + /** + * @return Frame + */ + public function get_first_child() + { + return $this->_first_child; + } + + /** + * @return Frame + */ + public function get_last_child() + { + return $this->_last_child; + } + + /** + * @return Frame + */ + public function get_prev_sibling() + { + return $this->_prev_sibling; + } + + /** + * @return Frame + */ + public function get_next_sibling() + { + return $this->_next_sibling; + } + + /** + * @return FrameList|Frame[] + */ + public function get_children() + { + if (isset($this->_frame_list)) { + return $this->_frame_list; + } + + $this->_frame_list = new FrameList($this); + + return $this->_frame_list; + } + + // Layout property accessors + + /** + * Containing block dimensions + * + * @param $i string The key of the wanted containing block's dimension (x, y, x, h) + * + * @return float[]|float + */ + public function get_containing_block($i = null) + { + if (isset($i)) { + return $this->_containing_block[$i]; + } + + return $this->_containing_block; + } + + /** + * Block position + * + * @param $i string The key of the wanted position value (x, y) + * + * @return array|float + */ + public function get_position($i = null) + { + if (isset($i)) { + return $this->_position[$i]; + } + + return $this->_position; + } + + //........................................................................ + + /** + * Return the height of the margin box of the frame, in pt. Meaningless + * unless the height has been calculated properly. + * + * @return float + */ + public function get_margin_height() + { + $style = $this->_style; + + return $style->length_in_pt(array( + $style->height, + $style->margin_top, + $style->margin_bottom, + $style->border_top_width, + $style->border_bottom_width, + $style->padding_top, + $style->padding_bottom + ), $this->_containing_block["h"]); + } + + /** + * Return the width of the margin box of the frame, in pt. Meaningless + * unless the width has been calculated properly. + * + * @return float + */ + public function get_margin_width() + { + $style = $this->_style; + + return $style->length_in_pt(array( + $style->width, + $style->margin_left, + $style->margin_right, + $style->border_left_width, + $style->border_right_width, + $style->padding_left, + $style->padding_right + ), $this->_containing_block["w"]); + } + + /** + * @return float + */ + public function get_break_margins() + { + $style = $this->_style; + + return $style->length_in_pt(array( + //$style->height, + $style->margin_top, + $style->margin_bottom, + $style->border_top_width, + $style->border_bottom_width, + $style->padding_top, + $style->padding_bottom + ), $this->_containing_block["h"]); + } + + /** + * Return the padding box (x,y,w,h) of the frame + * + * @return array + */ + public function get_padding_box() + { + $style = $this->_style; + $cb = $this->_containing_block; + + $x = $this->_position["x"] + + $style->length_in_pt(array($style->margin_left, + $style->border_left_width), + $cb["w"]); + + $y = $this->_position["y"] + + $style->length_in_pt(array($style->margin_top, + $style->border_top_width), + $cb["h"]); + + $w = $style->length_in_pt(array($style->padding_left, + $style->width, + $style->padding_right), + $cb["w"]); + + $h = $style->length_in_pt(array($style->padding_top, + $style->height, + $style->padding_bottom), + $cb["h"]); + + return array(0 => $x, "x" => $x, + 1 => $y, "y" => $y, + 2 => $w, "w" => $w, + 3 => $h, "h" => $h); + } + + /** + * Return the border box of the frame + * + * @return array + */ + public function get_border_box() + { + $style = $this->_style; + $cb = $this->_containing_block; + + $x = $this->_position["x"] + $style->length_in_pt($style->margin_left, $cb["w"]); + + $y = $this->_position["y"] + $style->length_in_pt($style->margin_top, $cb["h"]); + + $w = $style->length_in_pt(array($style->border_left_width, + $style->padding_left, + $style->width, + $style->padding_right, + $style->border_right_width), + $cb["w"]); + + $h = $style->length_in_pt(array($style->border_top_width, + $style->padding_top, + $style->height, + $style->padding_bottom, + $style->border_bottom_width), + $cb["h"]); + + return array(0 => $x, "x" => $x, + 1 => $y, "y" => $y, + 2 => $w, "w" => $w, + 3 => $h, "h" => $h); + } + + /** + * @param null $opacity + * + * @return float + */ + public function get_opacity($opacity = null) + { + if ($opacity !== null) { + $this->set_opacity($opacity); + } + + return $this->_opacity; + } + + /** + * @return LineBox + */ + public function &get_containing_line() + { + return $this->_containing_line; + } + + //........................................................................ + + // Set methods + /** + * @param $id + */ + public function set_id($id) + { + $this->_id = $id; + + // We can only set attributes of DOMElement objects (nodeType == 1). + // Since these are the only objects that we can assign CSS rules to, + // this shortcoming is okay. + if ($this->_node->nodeType == XML_ELEMENT_NODE) { + $this->_node->setAttribute("frame_id", $id); + } + } + + /** + * @param Style $style + */ + public function set_style(Style $style) + { + if (is_null($this->_style)) { + $this->_original_style = clone $style; + } + + //$style->set_frame($this); + $this->_style = $style; + } + + /** + * @param \Dompdf\FrameDecorator\AbstractFrameDecorator $decorator + */ + public function set_decorator(FrameDecorator\AbstractFrameDecorator $decorator) + { + $this->_decorator = $decorator; + } + + /** + * @param null $x + * @param null $y + * @param null $w + * @param null $h + */ + public function set_containing_block($x = null, $y = null, $w = null, $h = null) + { + if (is_array($x)) { + foreach ($x as $key => $val) { + $$key = $val; + } + } + + if (is_numeric($x)) { + $this->_containing_block["x"] = $x; + } + + if (is_numeric($y)) { + $this->_containing_block["y"] = $y; + } + + if (is_numeric($w)) { + $this->_containing_block["w"] = $w; + } + + if (is_numeric($h)) { + $this->_containing_block["h"] = $h; + } + } + + /** + * @param null $x + * @param null $y + */ + public function set_position($x = null, $y = null) + { + if (is_array($x)) { + list($x, $y) = array($x["x"], $x["y"]); + } + + if (is_numeric($x)) { + $this->_position["x"] = $x; + } + + if (is_numeric($y)) { + $this->_position["y"] = $y; + } + } + + /** + * @param $opacity + */ + public function set_opacity($opacity) + { + $parent = $this->get_parent(); + $base_opacity = (($parent && $parent->_opacity !== null) ? $parent->_opacity : 1.0); + $this->_opacity = $base_opacity * $opacity; + } + + /** + * @param LineBox $line + */ + public function set_containing_line(LineBox $line) + { + $this->_containing_line = $line; + } + + /** + * Tells if the frame is a text node + * + * @return bool + */ + public function is_text_node() + { + if (isset($this->_is_cache["text_node"])) { + return $this->_is_cache["text_node"]; + } + + return $this->_is_cache["text_node"] = ($this->get_node()->nodeName === "#text"); + } + + /** + * @return bool + */ + public function is_positionned() + { + if (isset($this->_is_cache["positionned"])) { + return $this->_is_cache["positionned"]; + } + + $position = $this->get_style()->position; + + return $this->_is_cache["positionned"] = in_array($position, Style::$POSITIONNED_TYPES); + } + + /** + * @return bool + */ + public function is_absolute() + { + if (isset($this->_is_cache["absolute"])) { + return $this->_is_cache["absolute"]; + } + + $position = $this->get_style()->position; + + return $this->_is_cache["absolute"] = ($position === "absolute" || $position === "fixed"); + } + + /** + * @return bool + */ + public function is_block() + { + if (isset($this->_is_cache["block"])) { + return $this->_is_cache["block"]; + } + + return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::$BLOCK_TYPES); + } + + /** + * @return bool + */ + public function is_in_flow() + { + if (isset($this->_is_cache["in_flow"])) { + return $this->_is_cache["in_flow"]; + } + return $this->_is_cache["in_flow"] = !($this->get_style()->float !== "none" || $this->is_absolute()); + } + + /** + * @return bool + */ + public function is_pre() + { + if (isset($this->_is_cache["pre"])) { + return $this->_is_cache["pre"]; + } + + $white_space = $this->get_style()->white_space; + + return $this->_is_cache["pre"] = in_array($white_space, array("pre", "pre-wrap")); + } + + /** + * @return bool + */ + public function is_table() + { + if (isset($this->_is_cache["table"])) { + return $this->_is_cache["table"]; + } + + $display = $this->get_style()->display; + + return $this->_is_cache["table"] = in_array($display, Style::$TABLE_TYPES); + } + + + /** + * Inserts a new child at the beginning of the Frame + * + * @param $child Frame The new Frame to insert + * @param $update_node boolean Whether or not to update the DOM + */ + public function prepend_child(Frame $child, $update_node = true) + { + if ($update_node) { + $this->_node->insertBefore($child->_node, $this->_first_child ? $this->_first_child->_node : null); + } + + // Remove the child from its parent + if ($child->_parent) { + $child->_parent->remove_child($child, false); + } + + $child->_parent = $this; + $child->_prev_sibling = null; + + // Handle the first child + if (!$this->_first_child) { + $this->_first_child = $child; + $this->_last_child = $child; + $child->_next_sibling = null; + } else { + $this->_first_child->_prev_sibling = $child; + $child->_next_sibling = $this->_first_child; + $this->_first_child = $child; + } + } + + /** + * Inserts a new child at the end of the Frame + * + * @param $child Frame The new Frame to insert + * @param $update_node boolean Whether or not to update the DOM + */ + public function append_child(Frame $child, $update_node = true) + { + if ($update_node) { + $this->_node->appendChild($child->_node); + } + + // Remove the child from its parent + if ($child->_parent) { + $child->_parent->remove_child($child, false); + } + + $child->_parent = $this; + $child->_next_sibling = null; + + // Handle the first child + if (!$this->_last_child) { + $this->_first_child = $child; + $this->_last_child = $child; + $child->_prev_sibling = null; + } else { + $this->_last_child->_next_sibling = $child; + $child->_prev_sibling = $this->_last_child; + $this->_last_child = $child; + } + } + + /** + * Inserts a new child immediately before the specified frame + * + * @param $new_child Frame The new Frame to insert + * @param $ref Frame The Frame after the new Frame + * @param $update_node boolean Whether or not to update the DOM + * + * @throws Exception + */ + public function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) + { + if ($ref === $this->_first_child) { + $this->prepend_child($new_child, $update_node); + + return; + } + + if (is_null($ref)) { + $this->append_child($new_child, $update_node); + + return; + } + + if ($ref->_parent !== $this) { + throw new Exception("Reference child is not a child of this node."); + } + + // Update the node + if ($update_node) { + $this->_node->insertBefore($new_child->_node, $ref->_node); + } + + // Remove the child from its parent + if ($new_child->_parent) { + $new_child->_parent->remove_child($new_child, false); + } + + $new_child->_parent = $this; + $new_child->_next_sibling = $ref; + $new_child->_prev_sibling = $ref->_prev_sibling; + + if ($ref->_prev_sibling) { + $ref->_prev_sibling->_next_sibling = $new_child; + } + + $ref->_prev_sibling = $new_child; + } + + /** + * Inserts a new child immediately after the specified frame + * + * @param $new_child Frame The new Frame to insert + * @param $ref Frame The Frame before the new Frame + * @param $update_node boolean Whether or not to update the DOM + * + * @throws Exception + */ + public function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) + { + if ($ref === $this->_last_child) { + $this->append_child($new_child, $update_node); + + return; + } + + if (is_null($ref)) { + $this->prepend_child($new_child, $update_node); + + return; + } + + if ($ref->_parent !== $this) { + throw new Exception("Reference child is not a child of this node."); + } + + // Update the node + if ($update_node) { + if ($ref->_next_sibling) { + $next_node = $ref->_next_sibling->_node; + $this->_node->insertBefore($new_child->_node, $next_node); + } else { + $new_child->_node = $this->_node->appendChild($new_child->_node); + } + } + + // Remove the child from its parent + if ($new_child->_parent) { + $new_child->_parent->remove_child($new_child, false); + } + + $new_child->_parent = $this; + $new_child->_prev_sibling = $ref; + $new_child->_next_sibling = $ref->_next_sibling; + + if ($ref->_next_sibling) { + $ref->_next_sibling->_prev_sibling = $new_child; + } + + $ref->_next_sibling = $new_child; + } + + /** + * Remove a child frame + * + * @param Frame $child + * @param boolean $update_node Whether or not to remove the DOM node + * + * @throws Exception + * @return Frame The removed child frame + */ + public function remove_child(Frame $child, $update_node = true) + { + if ($child->_parent !== $this) { + throw new Exception("Child not found in this frame"); + } + + if ($update_node) { + $this->_node->removeChild($child->_node); + } + + if ($child === $this->_first_child) { + $this->_first_child = $child->_next_sibling; + } + + if ($child === $this->_last_child) { + $this->_last_child = $child->_prev_sibling; + } + + if ($child->_prev_sibling) { + $child->_prev_sibling->_next_sibling = $child->_next_sibling; + } + + if ($child->_next_sibling) { + $child->_next_sibling->_prev_sibling = $child->_prev_sibling; + } + + $child->_next_sibling = null; + $child->_prev_sibling = null; + $child->_parent = null; + + return $child; + } + + //........................................................................ + + // Debugging function: + /** + * @return string + */ + public function __toString() + { + // Skip empty text frames +// if ( $this->is_text_node() && +// preg_replace("/\s/", "", $this->_node->data) === "" ) +// return ""; + + + $str = "" . $this->_node->nodeName . ":
"; + //$str .= spl_object_hash($this->_node) . "
"; + $str .= "Id: " . $this->get_id() . "
"; + $str .= "Class: " . get_class($this) . "
"; + + if ($this->is_text_node()) { + $tmp = htmlspecialchars($this->_node->nodeValue); + $str .= "
'" . mb_substr($tmp, 0, 70) .
+                (mb_strlen($tmp) > 70 ? "..." : "") . "'
"; + } elseif ($css_class = $this->_node->getAttribute("class")) { + $str .= "CSS class: '$css_class'
"; + } + + if ($this->_parent) { + $str .= "\nParent:" . $this->_parent->_node->nodeName . + " (" . spl_object_hash($this->_parent->_node) . ") " . + "
"; + } + + if ($this->_prev_sibling) { + $str .= "Prev: " . $this->_prev_sibling->_node->nodeName . + " (" . spl_object_hash($this->_prev_sibling->_node) . ") " . + "
"; + } + + if ($this->_next_sibling) { + $str .= "Next: " . $this->_next_sibling->_node->nodeName . + " (" . spl_object_hash($this->_next_sibling->_node) . ") " . + "
"; + } + + $d = $this->get_decorator(); + while ($d && $d != $d->get_decorator()) { + $str .= "Decorator: " . get_class($d) . "
"; + $d = $d->get_decorator(); + } + + $str .= "Position: " . Helpers::pre_r($this->_position, true); + $str .= "\nContaining block: " . Helpers::pre_r($this->_containing_block, true); + $str .= "\nMargin width: " . Helpers::pre_r($this->get_margin_width(), true); + $str .= "\nMargin height: " . Helpers::pre_r($this->get_margin_height(), true); + + $str .= "\nStyle:
" . $this->_style->__toString() . "
"; + + if ($this->_decorator instanceof FrameDecorator\Block) { + $str .= "Lines:
";
+            foreach ($this->_decorator->get_line_boxes() as $line) {
+                foreach ($line->get_frames() as $frame) {
+                    if ($frame instanceof FrameDecorator\Text) {
+                        $str .= "\ntext: ";
+                        $str .= "'" . htmlspecialchars($frame->get_text()) . "'";
+                    } else {
+                        $str .= "\nBlock: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")";
+                    }
+                }
+
+                $str .=
+                    "\ny => " . $line->y . "\n" .
+                    "w => " . $line->w . "\n" .
+                    "h => " . $line->h . "\n" .
+                    "left => " . $line->left . "\n" .
+                    "right => " . $line->right . "\n";
+            }
+            $str .= "
"; + } + + $str .= "\n"; + if (php_sapi_name() === "cli") { + $str = strip_tags(str_replace(array("
", "", ""), + array("\n", "", ""), + $str)); + } + + return $str; + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Frame/Factory.php b/vendor/dompdf/dompdf/src/Frame/Factory.php new file mode 100644 index 000000000..431a5c10c --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/Factory.php @@ -0,0 +1,262 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Frame; + +use Dompdf\Css\Style; +use Dompdf\Dompdf; +use Dompdf\Exception; +use Dompdf\Frame; +use Dompdf\FrameDecorator\AbstractFrameDecorator; +use DOMXPath; +use Dompdf\FrameDecorator\Page as PageFrameDecorator; +use Dompdf\FrameReflower\Page as PageFrameReflower; + +/** + * Contains frame decorating logic + * + * This class is responsible for assigning the correct {@link AbstractFrameDecorator}, + * {@link AbstractPositioner}, and {@link AbstractFrameReflower} objects to {@link Frame} + * objects. This is determined primarily by the Frame's display type, but + * also by the Frame's node's type (e.g. DomElement vs. #text) + * + * @access private + * @package dompdf + */ +class Factory +{ + + /** + * Decorate the root Frame + * + * @param $root Frame The frame to decorate + * @param $dompdf Dompdf The dompdf instance + * + * @return PageFrameDecorator + */ + static function decorate_root(Frame $root, Dompdf $dompdf) + { + $frame = new PageFrameDecorator($root, $dompdf); + $frame->set_reflower(new PageFrameReflower($frame)); + $root->set_decorator($frame); + + return $frame; + } + + /** + * Decorate a Frame + * + * @param Frame $frame The frame to decorate + * @param Dompdf $dompdf The dompdf instance + * @param Frame $root The frame to decorate + * + * @throws Exception + * @return AbstractFrameDecorator + * FIXME: this is admittedly a little smelly... + */ + static function decorate_frame(Frame $frame, Dompdf $dompdf, Frame $root = null) + { + if (is_null($dompdf)) { + throw new Exception("The DOMPDF argument is required"); + } + + $style = $frame->get_style(); + + // Floating (and more generally out-of-flow) elements are blocks + // http://coding.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/ + if (!$frame->is_in_flow() && in_array($style->display, Style::$INLINE_TYPES)) { + $style->display = "block"; + } + + $display = $style->display; + + switch ($display) { + + case "block": + $positioner = "Block"; + $decorator = "Block"; + $reflower = "Block"; + break; + + case "inline-block": + $positioner = "Inline"; + $decorator = "Block"; + $reflower = "Block"; + break; + + case "inline": + $positioner = "Inline"; + if ($frame->is_text_node()) { + $decorator = "Text"; + $reflower = "Text"; + } else { + if ($style->float !== "none") { + $decorator = "Block"; + $reflower = "Block"; + } else { + $decorator = "Inline"; + $reflower = "Inline"; + } + } + break; + + case "table": + $positioner = "Block"; + $decorator = "Table"; + $reflower = "Table"; + break; + + case "inline-table": + $positioner = "Inline"; + $decorator = "Table"; + $reflower = "Table"; + break; + + case "table-row-group": + case "table-header-group": + case "table-footer-group": + $positioner = "NullPositioner"; + $decorator = "TableRowGroup"; + $reflower = "TableRowGroup"; + break; + + case "table-row": + $positioner = "NullPositioner"; + $decorator = "TableRow"; + $reflower = "TableRow"; + break; + + case "table-cell": + $positioner = "TableCell"; + $decorator = "TableCell"; + $reflower = "TableCell"; + break; + + case "list-item": + $positioner = "Block"; + $decorator = "Block"; + $reflower = "Block"; + break; + + case "-dompdf-list-bullet": + if ($style->list_style_position === "inside") { + $positioner = "Inline"; + } else { + $positioner = "ListBullet"; + } + + if ($style->list_style_image !== "none") { + $decorator = "ListBulletImage"; + } else { + $decorator = "ListBullet"; + } + + $reflower = "ListBullet"; + break; + + case "-dompdf-image": + $positioner = "Inline"; + $decorator = "Image"; + $reflower = "Image"; + break; + + case "-dompdf-br": + $positioner = "Inline"; + $decorator = "Inline"; + $reflower = "Inline"; + break; + + default: + // FIXME: should throw some sort of warning or something? + case "none": + if ($style->_dompdf_keep !== "yes") { + // Remove the node and the frame + $frame->get_parent()->remove_child($frame); + return; + } + + $positioner = "NullPositioner"; + $decorator = "NullFrameDecorator"; + $reflower = "NullFrameReflower"; + break; + } + + // Handle CSS position + $position = $style->position; + + if ($position === "absolute") { + $positioner = "Absolute"; + } else { + if ($position === "fixed") { + $positioner = "Fixed"; + } + } + + $node = $frame->get_node(); + + // Handle nodeName + if ($node->nodeName === "img") { + $style->display = "-dompdf-image"; + $decorator = "Image"; + $reflower = "Image"; + } + + $positioner = "Dompdf\\Positioner\\$positioner"; + $decorator = "Dompdf\\FrameDecorator\\$decorator"; + $reflower = "Dompdf\\FrameReflower\\$reflower"; + + /** @var AbstractFrameDecorator $deco */ + $deco = new $decorator($frame, $dompdf); + + $deco->set_positioner(new $positioner($deco)); + $deco->set_reflower(new $reflower($deco, $dompdf->getFontMetrics())); + + if ($root) { + $deco->set_root($root); + } + + if ($display === "list-item") { + // Insert a list-bullet frame + $xml = $dompdf->get_dom(); + $bullet_node = $xml->createElement("bullet"); // arbitrary choice + $b_f = new Frame($bullet_node); + + $node = $frame->get_node(); + $parent_node = $node->parentNode; + + if ($parent_node) { + if (!$parent_node->hasAttribute("dompdf-children-count")) { + $xpath = new DOMXPath($xml); + $count = $xpath->query("li", $parent_node)->length; + $parent_node->setAttribute("dompdf-children-count", $count); + } + + if (is_numeric($node->getAttribute("value"))) { + $index = intval($node->getAttribute("value")); + } else { + if (!$parent_node->hasAttribute("dompdf-counter")) { + $index = ($parent_node->hasAttribute("start") ? $parent_node->getAttribute("start") : 1); + } else { + $index = $parent_node->getAttribute("dompdf-counter") + 1; + } + } + + $parent_node->setAttribute("dompdf-counter", $index); + $bullet_node->setAttribute("dompdf-counter", $index); + } + + $new_style = $dompdf->get_css()->create_style(); + $new_style->display = "-dompdf-list-bullet"; + $new_style->inherit($style); + $b_f->set_style($new_style); + + $deco->prepend_child(Factory::decorate_frame($b_f, $dompdf, $root)); + } + + return $deco; + } +} diff --git a/vendor/dompdf/dompdf/src/Frame/FrameList.php b/vendor/dompdf/dompdf/src/Frame/FrameList.php new file mode 100644 index 000000000..783600dc7 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/FrameList.php @@ -0,0 +1,34 @@ +_frame = $frame; + } + + /** + * @return FrameListIterator + */ + function getIterator() + { + return new FrameListIterator($this->_frame); + } +} diff --git a/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php b/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php new file mode 100644 index 000000000..ada9dde18 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/FrameListIterator.php @@ -0,0 +1,91 @@ +_parent = $frame; + $this->_cur = $frame->get_first_child(); + $this->_num = 0; + } + + /** + * + */ + public function rewind() + { + $this->_cur = $this->_parent->get_first_child(); + $this->_num = 0; + } + + /** + * @return bool + */ + public function valid() + { + return isset($this->_cur); // && ($this->_cur->get_prev_sibling() === $this->_prev); + } + + /** + * @return int + */ + public function key() + { + return $this->_num; + } + + /** + * @return Frame + */ + public function current() + { + return $this->_cur; + } + + /** + * @return Frame + */ + public function next() + { + $ret = $this->_cur; + if (!$ret) { + return null; + } + + $this->_cur = $this->_cur->get_next_sibling(); + $this->_num++; + return $ret; + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Frame/FrameTree.php b/vendor/dompdf/dompdf/src/Frame/FrameTree.php new file mode 100644 index 000000000..ff882ff33 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/FrameTree.php @@ -0,0 +1,300 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +/** + * Represents an entire document as a tree of frames + * + * The FrameTree consists of {@link Frame} objects each tied to specific + * DOMNode objects in a specific DomDocument. The FrameTree has the same + * structure as the DomDocument, but adds additional capabalities for + * styling and layout. + * + * @package dompdf + */ +class FrameTree +{ + /** + * Tags to ignore while parsing the tree + * + * @var array + */ + protected static $HIDDEN_TAGS = array( + "area", + "base", + "basefont", + "head", + "style", + "meta", + "title", + "colgroup", + "noembed", + "noscript", + "param", + "#comment" + ); + + /** + * The main DomDocument + * + * @see http://ca2.php.net/manual/en/ref.dom.php + * @var DOMDocument + */ + protected $_dom; + + /** + * The root node of the FrameTree. + * + * @var Frame + */ + protected $_root; + + /** + * Subtrees of absolutely positioned elements + * + * @var array of Frames + */ + protected $_absolute_frames; + + /** + * A mapping of {@link Frame} objects to DOMNode objects + * + * @var array + */ + protected $_registry; + + /** + * Class constructor + * + * @param DOMDocument $dom the main DomDocument object representing the current html document + */ + public function __construct(DomDocument $dom) + { + $this->_dom = $dom; + $this->_root = null; + $this->_registry = array(); + } + + /** + * Returns the DOMDocument object representing the curent html document + * + * @return DOMDocument + */ + public function get_dom() + { + return $this->_dom; + } + + /** + * Returns the root frame of the tree + * + * @return \Dompdf\FrameDecorator\Page + */ + public function get_root() + { + return $this->_root; + } + + /** + * Returns a specific frame given its id + * + * @param string $id + * + * @return Frame + */ + public function get_frame($id) + { + return isset($this->_registry[$id]) ? $this->_registry[$id] : null; + } + + /** + * Returns a post-order iterator for all frames in the tree + * + * @return FrameTreeList|Frame[] + */ + public function get_frames() + { + return new FrameTreeList($this->_root); + } + + /** + * Builds the tree + */ + public function build_tree() + { + $html = $this->_dom->getElementsByTagName("html")->item(0); + if (is_null($html)) { + $html = $this->_dom->firstChild; + } + + if (is_null($html)) { + throw new Exception("Requested HTML document contains no data."); + } + + $this->fix_tables(); + + $this->_root = $this->_build_tree_r($html); + } + + /** + * Adds missing TBODYs around TR + */ + protected function fix_tables() + { + $xp = new DOMXPath($this->_dom); + + // Move table caption before the table + // FIXME find a better way to deal with it... + $captions = $xp->query("//table/caption"); + foreach ($captions as $caption) { + $table = $caption->parentNode; + $table->parentNode->insertBefore($caption, $table); + } + + $rows = $xp->query("//table/tr"); + foreach ($rows as $row) { + $tbody = $this->_dom->createElement("tbody"); + $tbody = $row->parentNode->insertBefore($tbody, $row); + $tbody->appendChild($row); + } + } + + // FIXME: temporary hack, preferably we will improve rendering of sequential #text nodes + /** + * Remove a child from a node + * + * Remove a child from a node. If the removed node results in two + * adjacent #text nodes then combine them. + * + * @param DONNode $node the current DOMNode being considered + * @param array $children an array of nodes that are the children of $node + * @param $index index from the $children array of the node to remove + */ + protected function _remove_node(DOMNode $node, array &$children, $index) + { + $child = $children[$index]; + $previousChild = $child->previousSibling; + $nextChild = $child->nextSibling; + $node->removeChild($child); + if (isset($previousChild, $nextChild)) { + if ($previousChild->nodeName === "#text" && $nextChild->nodeName === "#text") + { + $previousChild->nodeValue .= $nextChild->nodeValue; + $this->_remove_node($node, $children, $index+1); + } + } + array_splice($children, $index, 1); + } + + /** + * Recursively adds {@link Frame} objects to the tree + * + * Recursively build a tree of Frame objects based on a dom tree. + * No layout information is calculated at this time, although the + * tree may be adjusted (i.e. nodes and frames for generated content + * and images may be created). + * + * @param DOMNode $node the current DOMNode being considered + * + * @return Frame + */ + protected function _build_tree_r(DOMNode $node) + { + $frame = new Frame($node); + $id = $frame->get_id(); + $this->_registry[$id] = $frame; + + if (!$node->hasChildNodes()) { + return $frame; + } + + // Store the children in an array so that the tree can be modified + $children = array(); + $length = $node->childNodes->length; + for ($i = 0; $i < $length; $i++) { + $children[] = $node->childNodes->item($i); + } + $index = 0; + // INFO: We don't advance $index if a node is removed to avoid skipping nodes + while ($index < count($children)) { + $child = $children[$index]; + $nodeName = strtolower($child->nodeName); + + // Skip non-displaying nodes + if (in_array($nodeName, self::$HIDDEN_TAGS)) { + if ($nodeName !== "head" && $nodeName !== "style") { + $this->_remove_node($node, $children, $index); + } else { + $index++; + } + continue; + } + // Skip empty text nodes + if ($nodeName === "#text" && $child->nodeValue === "") { + $this->_remove_node($node, $children, $index); + continue; + } + // Skip empty image nodes + if ($nodeName === "img" && $child->getAttribute("src") === "") { + $this->_remove_node($node, $children, $index); + continue; + } + + if (is_object($child)) { + $frame->append_child($this->_build_tree_r($child), false); + } + $index++; + } + + return $frame; + } + + /** + * @param DOMNode $node + * @param DOMNode $new_node + * @param string $pos + * + * @return mixed + */ + public function insert_node(DOMNode $node, DOMNode $new_node, $pos) + { + if ($pos === "after" || !$node->firstChild) { + $node->appendChild($new_node); + } else { + $node->insertBefore($new_node, $node->firstChild); + } + + $this->_build_tree_r($new_node); + + $frame_id = $new_node->getAttribute("frame_id"); + $frame = $this->get_frame($frame_id); + + $parent_id = $node->getAttribute("frame_id"); + $parent = $this->get_frame($parent_id); + + if ($parent) { + if ($pos === "before") { + $parent->prepend_child($frame, false); + } else { + $parent->append_child($frame, false); + } + } + + return $frame_id; + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php b/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php new file mode 100644 index 000000000..ebca7e99f --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/FrameTreeIterator.php @@ -0,0 +1,96 @@ +_stack[] = $this->_root = $root; + $this->_num = 0; + } + + /** + * + */ + public function rewind() + { + $this->_stack = array($this->_root); + $this->_num = 0; + } + + /** + * @return bool + */ + public function valid() + { + return count($this->_stack) > 0; + } + + /** + * @return int + */ + public function key() + { + return $this->_num; + } + + /** + * @return Frame + */ + public function current() + { + return end($this->_stack); + } + + /** + * @return Frame + */ + public function next() + { + $b = end($this->_stack); + + // Pop last element + unset($this->_stack[key($this->_stack)]); + $this->_num++; + + // Push all children onto the stack in reverse order + if ($c = $b->get_last_child()) { + $this->_stack[] = $c; + while ($c = $c->get_prev_sibling()) { + $this->_stack[] = $c; + } + } + + return $b; + } +} + diff --git a/vendor/dompdf/dompdf/src/Frame/FrameTreeList.php b/vendor/dompdf/dompdf/src/Frame/FrameTreeList.php new file mode 100644 index 000000000..f8b996c68 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Frame/FrameTreeList.php @@ -0,0 +1,35 @@ +_root = $root; + } + + /** + * @return FrameTreeIterator + */ + public function getIterator() + { + return new FrameTreeIterator($this->_root); + } +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php b/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php new file mode 100644 index 000000000..b574991e6 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/AbstractFrameDecorator.php @@ -0,0 +1,808 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +/** + * Base AbstractFrameDecorator class + * + * @package dompdf + */ +abstract class AbstractFrameDecorator extends Frame +{ + const DEFAULT_COUNTER = "-dompdf-default-counter"; + + public $_counters = array(); // array([id] => counter_value) (for generated content) + + /** + * The root node of the DOM tree + * + * @var Frame + */ + protected $_root; + + /** + * The decorated frame + * + * @var Frame + */ + protected $_frame; + + /** + * AbstractPositioner object used to position this frame (Strategy pattern) + * + * @var AbstractPositioner + */ + protected $_positioner; + + /** + * Reflower object used to calculate frame dimensions (Strategy pattern) + * + * @var \Dompdf\FrameReflower\AbstractFrameReflower + */ + protected $_reflower; + + /** + * Reference to the current dompdf instance + * + * @var Dompdf + */ + protected $_dompdf; + + /** + * First block parent + * + * @var Block + */ + private $_block_parent; + + /** + * First positionned parent (position: relative | absolute | fixed) + * + * @var AbstractFrameDecorator + */ + private $_positionned_parent; + + /** + * Class constructor + * + * @param Frame $frame The decoration target + * @param Dompdf $dompdf The Dompdf object + */ + function __construct(Frame $frame, Dompdf $dompdf) + { + $this->_frame = $frame; + $this->_root = null; + $this->_dompdf = $dompdf; + $frame->set_decorator($this); + } + + /** + * "Destructor": foribly free all references held by this object + * + * @param bool $recursive if true, call dispose on all children + */ + function dispose($recursive = false) + { + if ($recursive) { + while ($child = $this->get_first_child()) { + $child->dispose(true); + } + } + + $this->_root = null; + unset($this->_root); + + $this->_frame->dispose(true); + $this->_frame = null; + unset($this->_frame); + + $this->_positioner = null; + unset($this->_positioner); + + $this->_reflower = null; + unset($this->_reflower); + } + + /** + * Return a copy of this frame with $node as its node + * + * @param DOMNode $node + * + * @return Frame + */ + function copy(DOMNode $node) + { + $frame = new Frame($node); + $frame->set_style(clone $this->_frame->get_original_style()); + + return Factory::decorate_frame($frame, $this->_dompdf, $this->_root); + } + + /** + * Create a deep copy: copy this node and all children + * + * @return Frame + */ + function deep_copy() + { + $node = $this->_frame->get_node(); + + if ($node instanceof DOMElement && $node->hasAttribute("id")) { + $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id")); + $node->removeAttribute("id"); + } + + $frame = new Frame($node->cloneNode()); + $frame->set_style(clone $this->_frame->get_original_style()); + + $deco = Factory::decorate_frame($frame, $this->_dompdf, $this->_root); + + foreach ($this->get_children() as $child) { + $deco->append_child($child->deep_copy()); + } + + return $deco; + } + + /** + * Delegate calls to decorated frame object + */ + function reset() + { + $this->_frame->reset(); + + $this->_counters = array(); + + // Reset all children + foreach ($this->get_children() as $child) { + $child->reset(); + } + } + + // Getters ----------- + function get_id() + { + return $this->_frame->get_id(); + } + + /** + * @return Frame + */ + function get_frame() + { + return $this->_frame; + } + + /** + * @return DOMElement|DOMText + */ + function get_node() + { + return $this->_frame->get_node(); + } + + /** + * @return Style + */ + function get_style() + { + return $this->_frame->get_style(); + } + + /** + * @return Style + */ + function get_original_style() + { + return $this->_frame->get_original_style(); + } + + /** + * @param integer $i + * + * @return array|float + */ + function get_containing_block($i = null) + { + return $this->_frame->get_containing_block($i); + } + + /** + * @param integer $i + * + * @return array|float + */ + function get_position($i = null) + { + return $this->_frame->get_position($i); + } + + /** + * @return Dompdf + */ + function get_dompdf() + { + return $this->_dompdf; + } + + /** + * @return float + */ + function get_margin_height() + { + return $this->_frame->get_margin_height(); + } + + /** + * @return float + */ + function get_margin_width() + { + return $this->_frame->get_margin_width(); + } + + /** + * @return array + */ + function get_padding_box() + { + return $this->_frame->get_padding_box(); + } + + /** + * @return array + */ + function get_border_box() + { + return $this->_frame->get_border_box(); + } + + /** + * @param integer $id + */ + function set_id($id) + { + $this->_frame->set_id($id); + } + + /** + * @param Style $style + */ + function set_style(Style $style) + { + $this->_frame->set_style($style); + } + + /** + * @param float $x + * @param float $y + * @param float $w + * @param float $h + */ + function set_containing_block($x = null, $y = null, $w = null, $h = null) + { + $this->_frame->set_containing_block($x, $y, $w, $h); + } + + /** + * @param float $x + * @param float $y + */ + function set_position($x = null, $y = null) + { + $this->_frame->set_position($x, $y); + } + + /** + * @return string + */ + function __toString() + { + return $this->_frame->__toString(); + } + + /** + * @param Frame $child + * @param bool $update_node + */ + function prepend_child(Frame $child, $update_node = true) + { + while ($child instanceof AbstractFrameDecorator) { + $child = $child->_frame; + } + + $this->_frame->prepend_child($child, $update_node); + } + + /** + * @param Frame $child + * @param bool $update_node + */ + function append_child(Frame $child, $update_node = true) + { + while ($child instanceof AbstractFrameDecorator) { + $child = $child->_frame; + } + + $this->_frame->append_child($child, $update_node); + } + + /** + * @param Frame $new_child + * @param Frame $ref + * @param bool $update_node + */ + function insert_child_before(Frame $new_child, Frame $ref, $update_node = true) + { + while ($new_child instanceof AbstractFrameDecorator) { + $new_child = $new_child->_frame; + } + + if ($ref instanceof AbstractFrameDecorator) { + $ref = $ref->_frame; + } + + $this->_frame->insert_child_before($new_child, $ref, $update_node); + } + + /** + * @param Frame $new_child + * @param Frame $ref + * @param bool $update_node + */ + function insert_child_after(Frame $new_child, Frame $ref, $update_node = true) + { + while ($new_child instanceof AbstractFrameDecorator) { + $new_child = $new_child->_frame; + } + + while ($ref instanceof AbstractFrameDecorator) { + $ref = $ref->_frame; + } + + $this->_frame->insert_child_after($new_child, $ref, $update_node); + } + + /** + * @param Frame $child + * @param bool $update_node + * + * @return Frame + */ + function remove_child(Frame $child, $update_node = true) + { + while ($child instanceof AbstractFrameDecorator) { + $child = $child->_frame; + } + + return $this->_frame->remove_child($child, $update_node); + } + + /** + * @return AbstractFrameDecorator + */ + function get_parent() + { + $p = $this->_frame->get_parent(); + if ($p && $deco = $p->get_decorator()) { + while ($tmp = $deco->get_decorator()) { + $deco = $tmp; + } + + return $deco; + } else { + if ($p) { + return $p; + } + } + + return null; + } + + /** + * @return AbstractFrameDecorator + */ + function get_first_child() + { + $c = $this->_frame->get_first_child(); + if ($c && $deco = $c->get_decorator()) { + while ($tmp = $deco->get_decorator()) { + $deco = $tmp; + } + + return $deco; + } else { + if ($c) { + return $c; + } + } + + return null; + } + + /** + * @return AbstractFrameDecorator + */ + function get_last_child() + { + $c = $this->_frame->get_last_child(); + if ($c && $deco = $c->get_decorator()) { + while ($tmp = $deco->get_decorator()) { + $deco = $tmp; + } + + return $deco; + } else { + if ($c) { + return $c; + } + } + + return null; + } + + /** + * @return AbstractFrameDecorator + */ + function get_prev_sibling() + { + $s = $this->_frame->get_prev_sibling(); + if ($s && $deco = $s->get_decorator()) { + while ($tmp = $deco->get_decorator()) { + $deco = $tmp; + } + + return $deco; + } else { + if ($s) { + return $s; + } + } + + return null; + } + + /** + * @return AbstractFrameDecorator + */ + function get_next_sibling() + { + $s = $this->_frame->get_next_sibling(); + if ($s && $deco = $s->get_decorator()) { + while ($tmp = $deco->get_decorator()) { + $deco = $tmp; + } + + return $deco; + } else { + if ($s) { + return $s; + } + } + + return null; + } + + /** + * @return FrameTreeList + */ + function get_subtree() + { + return new FrameTreeList($this); + } + + function set_positioner(AbstractPositioner $posn) + { + $this->_positioner = $posn; + if ($this->_frame instanceof AbstractFrameDecorator) { + $this->_frame->set_positioner($posn); + } + } + + function set_reflower(AbstractFrameReflower $reflower) + { + $this->_reflower = $reflower; + if ($this->_frame instanceof AbstractFrameDecorator) { + $this->_frame->set_reflower($reflower); + } + } + + /** + * @return \Dompdf\FrameReflower\AbstractFrameReflower + */ + function get_reflower() + { + return $this->_reflower; + } + + /** + * @param Frame $root + */ + function set_root(Frame $root) + { + $this->_root = $root; + + if ($this->_frame instanceof AbstractFrameDecorator) { + $this->_frame->set_root($root); + } + } + + /** + * @return Page + */ + function get_root() + { + return $this->_root; + } + + /** + * @return Block + */ + function find_block_parent() + { + // Find our nearest block level parent + $p = $this->get_parent(); + + while ($p) { + if ($p->is_block()) { + break; + } + + $p = $p->get_parent(); + } + + return $this->_block_parent = $p; + } + + /** + * @return AbstractFrameDecorator + */ + function find_positionned_parent() + { + // Find our nearest relative positionned parent + $p = $this->get_parent(); + while ($p) { + if ($p->is_positionned()) { + break; + } + + $p = $p->get_parent(); + } + + if (!$p) { + $p = $this->_root->get_first_child(); // + } + + return $this->_positionned_parent = $p; + } + + /** + * split this frame at $child. + * The current frame is cloned and $child and all children following + * $child are added to the clone. The clone is then passed to the + * current frame's parent->split() method. + * + * @param Frame $child + * @param boolean $force_pagebreak + * + * @throws Exception + * @return void + */ + function split(Frame $child = null, $force_pagebreak = false) + { + // decrement any counters that were incremented on the current node, unless that node is the body + $style = $this->_frame->get_style(); + if ($this->_frame->get_node( + )->nodeName !== "body" && $style->counter_increment && ($decrement = $style->counter_increment) !== "none" + ) { + $this->decrement_counters($decrement); + } + + if (is_null($child)) { + // check for counter increment on :before content (always a child of the selected element @link AbstractFrameReflower::_set_content) + // this can push the current node to the next page before counter rules have bubbled up (but only if + // it's been rendered, thus the position check) + if (!$this->is_text_node() && $this->get_node()->hasAttribute("dompdf_before_frame_id")) { + foreach ($this->_frame->get_children() as $child) { + if ($this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id( + ) && $child->get_position('x') !== null + ) { + $style = $child->get_style(); + if ($style->counter_increment && ($decrement = $style->counter_increment) !== "none") { + $this->decrement_counters($decrement); + } + } + } + } + $this->get_parent()->split($this, $force_pagebreak); + + return; + } + + if ($child->get_parent() !== $this) { + throw new Exception("Unable to split: frame is not a child of this one."); + } + + $node = $this->_frame->get_node(); + + if ($node instanceof DOMElement && $node->hasAttribute("id")) { + $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id")); + $node->removeAttribute("id"); + } + + $split = $this->copy($node->cloneNode()); + $split->reset(); + $split->get_original_style()->text_indent = 0; + $split->_splitted = true; + + // The body's properties must be kept + if ($node->nodeName !== "body") { + // Style reset on the first and second parts + $style = $this->_frame->get_style(); + $style->margin_bottom = 0; + $style->padding_bottom = 0; + $style->border_bottom = 0; + + // second + $orig_style = $split->get_original_style(); + $orig_style->text_indent = 0; + $orig_style->margin_top = 0; + $orig_style->padding_top = 0; + $orig_style->border_top = 0; + $orig_style->page_break_before = "auto"; + } + + $this->get_parent()->insert_child_after($split, $this); + + // Add $frame and all following siblings to the new split node + $iter = $child; + while ($iter) { + $frame = $iter; + $iter = $iter->get_next_sibling(); + $frame->reset(); + $split->append_child($frame); + } + + $this->get_parent()->split($split, $force_pagebreak); + + // If this node resets a counter save the current value to use when rendering on the next page + if ($style->counter_reset && ($reset = $style->counter_reset) !== "none") { + $vars = preg_split('/\s+/', trim($reset), 2); + $split->_counters['__' . $vars[0]] = $this->lookup_counter_frame($vars[0])->_counters[$vars[0]]; + } + } + + function reset_counter($id = self::DEFAULT_COUNTER, $value = 0) + { + $this->get_parent()->_counters[$id] = intval($value); + } + + function decrement_counters($counters) + { + foreach ($counters as $id => $increment) { + $this->increment_counter($id, intval($increment) * -1); + } + } + + function increment_counters($counters) + { + foreach ($counters as $id => $increment) { + $this->increment_counter($id, intval($increment)); + } + } + + function increment_counter($id = self::DEFAULT_COUNTER, $increment = 1) + { + $counter_frame = $this->lookup_counter_frame($id); + + if ($counter_frame) { + if (!isset($counter_frame->_counters[$id])) { + $counter_frame->_counters[$id] = 0; + } + + $counter_frame->_counters[$id] += $increment; + } + } + + function lookup_counter_frame($id = self::DEFAULT_COUNTER) + { + $f = $this->get_parent(); + + while ($f) { + if (isset($f->_counters[$id])) { + return $f; + } + $fp = $f->get_parent(); + + if (!$fp) { + return $f; + } + + $f = $fp; + } + } + + // TODO: What version is the best : this one or the one in ListBullet ? + function counter_value($id = self::DEFAULT_COUNTER, $type = "decimal") + { + $type = mb_strtolower($type); + + if (!isset($this->_counters[$id])) { + $this->_counters[$id] = 0; + } + + $value = $this->_counters[$id]; + + switch ($type) { + default: + case "decimal": + return $value; + + case "decimal-leading-zero": + return str_pad($value, 2, "0", STR_PAD_LEFT); + + case "lower-roman": + return Helpers::dec2roman($value); + + case "upper-roman": + return mb_strtoupper(Helpers::dec2roman($value)); + + case "lower-latin": + case "lower-alpha": + return chr(($value % 26) + ord('a') - 1); + + case "upper-latin": + case "upper-alpha": + return chr(($value % 26) + ord('A') - 1); + + case "lower-greek": + return Helpers::unichr($value + 944); + + case "upper-greek": + return Helpers::unichr($value + 912); + } + } + + final function position() + { + $this->_positioner->position(); + } + + final function move($offset_x, $offset_y, $ignore_self = false) + { + $this->_positioner->move($offset_x, $offset_y, $ignore_self); + } + + final function reflow(Block $block = null) + { + // Uncomment this to see the frames before they're laid out, instead of + // during rendering. + //echo $this->_frame; flush(); + $this->_reflower->reflow($block); + } + + final function get_min_max_width() + { + return $this->_reflower->get_min_max_width(); + } +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Block.php b/vendor/dompdf/dompdf/src/FrameDecorator/Block.php new file mode 100644 index 000000000..c51fe2a80 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Block.php @@ -0,0 +1,252 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\LineBox; + +/** + * Decorates frames for block layout + * + * @access private + * @package dompdf + */ +class Block extends AbstractFrameDecorator +{ + /** + * Current line index + * + * @var int + */ + protected $_cl; + + /** + * The block's line boxes + * + * @var LineBox[] + */ + protected $_line_boxes; + + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + + $this->_line_boxes = array(new LineBox($this)); + $this->_cl = 0; + } + + function reset() + { + parent::reset(); + + $this->_line_boxes = array(new LineBox($this)); + $this->_cl = 0; + } + + /** + * @return LineBox + */ + function get_current_line_box() + { + return $this->_line_boxes[$this->_cl]; + } + + /** + * @return integer + */ + function get_current_line_number() + { + return $this->_cl; + } + + /** + * @return LineBox[] + */ + function get_line_boxes() + { + return $this->_line_boxes; + } + + /** + * @param integer $i + */ + function clear_line($i) + { + if (isset($this->_line_boxes[$i])) { + unset($this->_line_boxes[$i]); + } + } + + /** + * @param Frame $frame + */ + function add_frame_to_line(Frame $frame) + { + if (!$frame->is_in_flow()) { + return; + } + + $style = $frame->get_style(); + + $frame->set_containing_line($this->_line_boxes[$this->_cl]); + + /* + // Adds a new line after a block, only if certain conditions are met + if ((($frame instanceof Inline && $frame->get_node()->nodeName !== "br") || + $frame instanceof Text && trim($frame->get_text())) && + ($frame->get_prev_sibling() && $frame->get_prev_sibling()->get_style()->display === "block" && + $this->_line_boxes[$this->_cl]->w > 0 )) { + + $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame ); + $this->add_line(); + + // Add each child of the inline frame to the line individually + foreach ($frame->get_children() as $child) + $this->add_frame_to_line( $child ); + } + else*/ + + // Handle inline frames (which are effectively wrappers) + if ($frame instanceof Inline) { + + // Handle line breaks + if ($frame->get_node()->nodeName === "br") { + $this->maximize_line_height($style->length_in_pt($style->line_height), $frame); + $this->add_line(true); + } + + return; + } + + // Trim leading text if this is an empty line. Kinda a hack to put it here, + // but what can you do... + if ($this->get_current_line_box()->w == 0 && + $frame->is_text_node() && + !$frame->is_pre() + ) { + + $frame->set_text(ltrim($frame->get_text())); + $frame->recalculate_width(); + } + + $w = $frame->get_margin_width(); + + if ($w == 0) { + return; + } + + // Debugging code: + /* + Helpers::pre_r("\n

Adding frame to line:

"); + + // Helpers::pre_r("Me: " . $this->get_node()->nodeName . " (" . spl_object_hash($this->get_node()) . ")"); + // Helpers::pre_r("Node: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")"); + if ( $frame->is_text_node() ) + Helpers::pre_r('"'.$frame->get_node()->nodeValue.'"'); + + Helpers::pre_r("Line width: " . $this->_line_boxes[$this->_cl]->w); + Helpers::pre_r("Frame: " . get_class($frame)); + Helpers::pre_r("Frame width: " . $w); + Helpers::pre_r("Frame height: " . $frame->get_margin_height()); + Helpers::pre_r("Containing block width: " . $this->get_containing_block("w")); + */ + // End debugging + + $line = $this->_line_boxes[$this->_cl]; + if ($line->left + $line->w + $line->right + $w > $this->get_containing_block("w")) { + $this->add_line(); + } + + $frame->position(); + + $current_line = $this->_line_boxes[$this->_cl]; + $current_line->add_frame($frame); + + if ($frame->is_text_node()) { + $current_line->wc += count(preg_split("/\s+/", trim($frame->get_text()))); + } + + $this->increase_line_width($w); + + $this->maximize_line_height($frame->get_margin_height(), $frame); + } + + function remove_frames_from_line(Frame $frame) + { + // Search backwards through the lines for $frame + $i = $this->_cl; + $j = null; + + while ($i >= 0) { + if (($j = in_array($frame, $this->_line_boxes[$i]->get_frames(), true)) !== false) { + break; + } + + $i--; + } + + if ($j === false) { + return; + } + + // Remove $frame and all frames that follow + while ($j < count($this->_line_boxes[$i]->get_frames())) { + $frames = $this->_line_boxes[$i]->get_frames(); + $f = $frames[$j]; + $frames[$j] = null; + unset($frames[$j]); + $j++; + $this->_line_boxes[$i]->w -= $f->get_margin_width(); + } + + // Recalculate the height of the line + $h = 0; + foreach ($this->_line_boxes[$i]->get_frames() as $f) { + $h = max($h, $f->get_margin_height()); + } + + $this->_line_boxes[$i]->h = $h; + + // Remove all lines that follow + while ($this->_cl > $i) { + $this->_line_boxes[$this->_cl] = null; + unset($this->_line_boxes[$this->_cl]); + $this->_cl--; + } + } + + function increase_line_width($w) + { + $this->_line_boxes[$this->_cl]->w += $w; + } + + function maximize_line_height($val, Frame $frame) + { + if ($val > $this->_line_boxes[$this->_cl]->h) { + $this->_line_boxes[$this->_cl]->tallest_frame = $frame; + $this->_line_boxes[$this->_cl]->h = $val; + } + } + + function add_line($br = false) + { + +// if ( $this->_line_boxes[$this->_cl]["h"] == 0 ) //count($this->_line_boxes[$i]["frames"]) == 0 || +// return; + + $this->_line_boxes[$this->_cl]->br = $br; + $y = $this->_line_boxes[$this->_cl]->y + $this->_line_boxes[$this->_cl]->h; + + $new_line = new LineBox($this, $y); + + $this->_line_boxes[++$this->_cl] = $new_line; + } + + //........................................................................ +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Image.php b/vendor/dompdf/dompdf/src/FrameDecorator/Image.php new file mode 100644 index 000000000..22a308a4a --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Image.php @@ -0,0 +1,90 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\FontMetrics; +use Dompdf\Image\Cache; + +/** + * Decorates frames for image layout and rendering + * + * @package dompdf + */ +class Image extends AbstractFrameDecorator +{ + + /** + * The path to the image file (note that remote images are + * downloaded locally to Options:tempDir). + * + * @var string + */ + protected $_image_url; + + /** + * The image's file error message + * + * @var string + */ + protected $_image_msg; + + /** + * Class constructor + * + * @param Frame $frame the frame to decorate + * @param DOMPDF $dompdf the document's dompdf object (required to resolve relative & remote urls) + */ + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + $url = $frame->get_node()->getAttribute("src"); + + $debug_png = $dompdf->get_option("debug_png"); + if ($debug_png) print '[__construct ' . $url . ']'; + + list($this->_image_url, /*$type*/, $this->_image_msg) = Cache::resolve_url( + $url, + $dompdf->get_protocol(), + $dompdf->get_host(), + $dompdf->get_base_path(), + $dompdf + ); + + if (Cache::is_broken($this->_image_url) && + $alt = $frame->get_node()->getAttribute("alt") + ) { + $style = $frame->get_style(); + $style->width = (4 / 3) * $dompdf->getFontMetrics()->getTextWidth($alt, $style->font_family, $style->font_size, $style->word_spacing); + $style->height = $dompdf->getFontMetrics()->getFontHeight($style->font_family, $style->font_size); + } + } + + /** + * Return the image's url + * + * @return string The url of this image + */ + function get_image_url() + { + return $this->_image_url; + } + + /** + * Return the image's error message + * + * @return string The image's error message + */ + function get_image_msg() + { + return $this->_image_msg; + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php b/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php new file mode 100644 index 000000000..05920f493 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Inline.php @@ -0,0 +1,92 @@ + + * @author Helmut Tischer + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\Exception; + +/** + * Decorates frames for inline layout + * + * @access private + * @package dompdf + */ +class Inline extends AbstractFrameDecorator +{ + + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + } + + function split(Frame $frame = null, $force_pagebreak = false) + { + if (is_null($frame)) { + $this->get_parent()->split($this, $force_pagebreak); + return; + } + + if ($frame->get_parent() !== $this) { + throw new Exception("Unable to split: frame is not a child of this one."); + } + + $node = $this->_frame->get_node(); + + if ($node instanceof DOMElement && $node->hasAttribute("id")) { + $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id")); + $node->removeAttribute("id"); + } + + $split = $this->copy($node->cloneNode()); + $this->get_parent()->insert_child_after($split, $this); + + // Unset the current node's right style properties + $style = $this->_frame->get_style(); + $style->margin_right = 0; + $style->padding_right = 0; + $style->border_right_width = 0; + + // Unset the split node's left style properties since we don't want them + // to propagate + $style = $split->get_style(); + $style->margin_left = 0; + $style->padding_left = 0; + $style->border_left_width = 0; + + //On continuation of inline element on next line, + //don't repeat non-vertically repeatble background images + //See e.g. in testcase image_variants, long desriptions + if (($url = $style->background_image) && $url !== "none" + && ($repeat = $style->background_repeat) && $repeat !== "repeat" && $repeat !== "repeat-y" + ) { + $style->background_image = "none"; + } + + // Add $frame and all following siblings to the new split node + $iter = $frame; + while ($iter) { + $frame = $iter; + $iter = $iter->get_next_sibling(); + $frame->reset(); + $split->append_child($frame); + } + + $page_breaks = array("always", "left", "right"); + $frame_style = $frame->get_style(); + if ($force_pagebreak || + in_array($frame_style->page_break_before, $page_breaks) || + in_array($frame_style->page_break_after, $page_breaks) + ) { + + $this->get_parent()->split($split, true); + } + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php b/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php new file mode 100644 index 000000000..2f9154625 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/ListBullet.php @@ -0,0 +1,75 @@ + + * @author Helmut Tischer + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; + +/** + * Decorates frames for list bullet rendering + * + * @package dompdf + */ +class ListBullet extends AbstractFrameDecorator +{ + + const BULLET_PADDING = 1; // Distance from bullet to text in pt + // As fraction of font size (including descent). See also DECO_THICKNESS. + const BULLET_THICKNESS = 0.04; // Thickness of bullet outline. Screen: 0.08, print: better less, e.g. 0.04 + const BULLET_DESCENT = 0.3; //descent of font below baseline. Todo: Guessed for now. + const BULLET_SIZE = 0.35; // bullet diameter. For now 0.5 of font_size without descent. + + static $BULLET_TYPES = array("disc", "circle", "square"); + + //........................................................................ + + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + } + + function get_margin_width() + { + $style = $this->_frame->get_style(); + + // Small hack to prevent extra indenting of list text on list_style_position === "inside" + // and on suppressed bullet + if ($style->list_style_position === "outside" || + $style->list_style_type === "none" + ) { + return 0; + } + + return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; + } + + //hits only on "inset" lists items, to increase height of box + function get_margin_height() + { + $style = $this->_frame->get_style(); + + if ($style->list_style_type === "none") { + return 0; + } + + return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING; + } + + function get_width() + { + return $this->get_margin_height(); + } + + function get_height() + { + return $this->get_margin_height(); + } + + //........................................................................ +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php b/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php new file mode 100644 index 000000000..159eaec13 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/ListBulletImage.php @@ -0,0 +1,155 @@ + + * @author Helmut Tischer + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\Helpers; + +/** + * Decorates frames for list bullets with custom images + * + * @package dompdf + */ +class ListBulletImage extends AbstractFrameDecorator +{ + + /** + * The underlying image frame + * + * @var Image + */ + protected $_img; + + /** + * The image's width in pixels + * + * @var int + */ + protected $_width; + + /** + * The image's height in pixels + * + * @var int + */ + protected $_height; + + /** + * Class constructor + * + * @param Frame $frame the bullet frame to decorate + * @param Dompdf $dompdf the document's dompdf object + */ + function __construct(Frame $frame, Dompdf $dompdf) + { + $style = $frame->get_style(); + $url = $style->list_style_image; + $frame->get_node()->setAttribute("src", $url); + $this->_img = new Image($frame, $dompdf); + parent::__construct($this->_img, $dompdf); + list($width, $height) = Helpers::dompdf_getimagesize($this->_img->get_image_url(), $dompdf->getHttpContext()); + + // 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. + $dpi = $this->_dompdf->get_option("dpi"); + $this->_width = ((float)rtrim($width, "px") * 72) / $dpi; + $this->_height = ((float)rtrim($height, "px") * 72) / $dpi; + + //If an image is taller as the containing block/box, the box should be extended. + //Neighbour elements are overwriting the overlapping image areas. + //Todo: Where can the box size be extended? + //Code below has no effect. + //See block_frame_reflower _calculate_restricted_height + //See generated_frame_reflower, Dompdf:render() "list-item", "-dompdf-list-bullet"S. + //Leave for now + //if ($style->min_height < $this->_height ) { + // $style->min_height = $this->_height; + //} + //$style->height = "auto"; + } + + /** + * Return the bullet's width + * + * @return int + */ + function get_width() + { + //ignore image width, use same width as on predefined bullet ListBullet + //for proper alignment of bullet image and text. Allow image to not fitting on left border. + //This controls the distance between bullet image and text + //return $this->_width; + return $this->_frame->get_style()->get_font_size() * ListBullet::BULLET_SIZE + + 2 * ListBullet::BULLET_PADDING; + } + + /** + * Return the bullet's height + * + * @return int + */ + function get_height() + { + //based on image height + return $this->_height; + } + + /** + * Override get_margin_width + * + * @return int + */ + function get_margin_width() + { + //ignore image width, use same width as on predefined bullet ListBullet + //for proper alignment of bullet image and text. Allow image to not fitting on left border. + //This controls the extra indentation of text to make room for the bullet image. + //Here use actual image size, not predefined bullet size + //return $this->_frame->get_style()->get_font_size()*ListBullet::BULLET_SIZE + + // 2 * ListBullet::BULLET_PADDING; + + // Small hack to prevent indenting of list text + // Image Might not exist, then position like on list_bullet_frame_decorator fallback to none. + if ($this->_frame->get_style()->list_style_position === "outside" || + $this->_width == 0 + ) + return 0; + //This aligns the "inside" image position with the text. + //The text starts to the right of the image. + //Between the image and the text there is an added margin of image width. + //Where this comes from is unknown. + //The corresponding ListBullet sets a smaller margin. bullet size? + return $this->_width + 2 * ListBullet::BULLET_PADDING; + } + + /** + * Override get_margin_height() + * + * @return int + */ + function get_margin_height() + { + //Hits only on "inset" lists items, to increase height of box + //based on image height + return $this->_height + 2 * ListBullet::BULLET_PADDING; + } + + /** + * Return image url + * + * @return string + */ + function get_image_url() + { + return $this->_img->get_image_url(); + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php b/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php new file mode 100644 index 000000000..c9f2d94c4 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/NullFrameDecorator.php @@ -0,0 +1,31 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; + +/** + * Dummy decorator + * + * @package dompdf + */ +class NullFrameDecorator extends AbstractFrameDecorator +{ + + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + $style = $this->_frame->get_style(); + $style->width = 0; + $style->height = 0; + $style->margin = 0; + $style->padding = 0; + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Page.php b/vendor/dompdf/dompdf/src/FrameDecorator/Page.php new file mode 100644 index 000000000..0310f60c2 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Page.php @@ -0,0 +1,658 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Css\Style; +use Dompdf\Dompdf; +use Dompdf\Helpers; +use Dompdf\Frame; +use Dompdf\Renderer; + +/** + * Decorates frames for page layout + * + * @access private + * @package dompdf + */ +class Page extends AbstractFrameDecorator +{ + + /** + * y value of bottom page margin + * + * @var float + */ + protected $_bottom_page_margin; + + /** + * Flag indicating page is full. + * + * @var bool + */ + protected $_page_full; + + /** + * Number of tables currently being reflowed + * + * @var int + */ + protected $_in_table; + + /** + * The pdf renderer + * + * @var Renderer + */ + protected $_renderer; + + /** + * This page's floating frames + * + * @var array + */ + protected $_floating_frames = array(); + + //........................................................................ + + /** + * Class constructor + * + * @param Frame $frame the frame to decorate + * @param Dompdf $dompdf + */ + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + $this->_page_full = false; + $this->_in_table = 0; + $this->_bottom_page_margin = null; + } + + /** + * Set the renderer used for this pdf + * + * @param Renderer $renderer the renderer to use + */ + function set_renderer($renderer) + { + $this->_renderer = $renderer; + } + + /** + * Return the renderer used for this pdf + * + * @return Renderer + */ + function get_renderer() + { + return $this->_renderer; + } + + /** + * Set the frame's containing block. Overridden to set $this->_bottom_page_margin. + * + * @param float $x + * @param float $y + * @param float $w + * @param float $h + */ + function set_containing_block($x = null, $y = null, $w = null, $h = null) + { + parent::set_containing_block($x, $y, $w, $h); + //$w = $this->get_containing_block("w"); + if (isset($h)) { + $this->_bottom_page_margin = $h; + } // - $this->_frame->get_style()->length_in_pt($this->_frame->get_style()->margin_bottom, $w); + } + + /** + * Returns true if the page is full and is no longer accepting frames. + * + * @return bool + */ + function is_full() + { + return $this->_page_full; + } + + /** + * Start a new page by resetting the full flag. + */ + function next_page() + { + $this->_floating_frames = array(); + $this->_renderer->new_page(); + $this->_page_full = false; + } + + /** + * Indicate to the page that a table is currently being reflowed. + */ + function table_reflow_start() + { + $this->_in_table++; + } + + /** + * Indicate to the page that table reflow is finished. + */ + function table_reflow_end() + { + $this->_in_table--; + } + + /** + * Return whether we are currently in a nested table or not + * + * @return bool + */ + function in_nested_table() + { + return $this->_in_table > 1; + } + + /** + * Check if a forced page break is required before $frame. This uses the + * frame's page_break_before property as well as the preceeding frame's + * page_break_after property. + * + * @link http://www.w3.org/TR/CSS21/page.html#forced + * + * @param Frame $frame the frame to check + * + * @return bool true if a page break occured + */ + function check_forced_page_break(Frame $frame) + { + + // Skip check if page is already split + if ($this->_page_full) { + return null; + } + + $block_types = array("block", "list-item", "table", "inline"); + $page_breaks = array("always", "left", "right"); + + $style = $frame->get_style(); + + if (!in_array($style->display, $block_types)) { + return false; + } + + // Find the previous block-level sibling + $prev = $frame->get_prev_sibling(); + + while ($prev && !in_array($prev->get_style()->display, $block_types)) { + $prev = $prev->get_prev_sibling(); + } + + + if (in_array($style->page_break_before, $page_breaks)) { + + // Prevent cascading splits + $frame->split(null, true); + // We have to grab the style again here because split() resets + // $frame->style to the frame's orignal style. + $frame->get_style()->page_break_before = "auto"; + $this->_page_full = true; + + return true; + } + + if ($prev && in_array($prev->get_style()->page_break_after, $page_breaks)) { + // Prevent cascading splits + $frame->split(null, true); + $prev->get_style()->page_break_after = "auto"; + $this->_page_full = true; + + return true; + } + + if ($prev && $prev->get_last_child() && $frame->get_node()->nodeName != "body") { + $prev_last_child = $prev->get_last_child(); + if (in_array($prev_last_child->get_style()->page_break_after, $page_breaks)) { + $frame->split(null, true); + $prev_last_child->get_style()->page_break_after = "auto"; + $this->_page_full = true; + + return true; + } + } + + + return false; + } + + /** + * Determine if a page break is allowed before $frame + * http://www.w3.org/TR/CSS21/page.html#allowed-page-breaks + * + * In the normal flow, page breaks can occur at the following places: + * + * 1. In the vertical margin between block boxes. When a page + * break occurs here, the used values of the relevant + * 'margin-top' and 'margin-bottom' properties are set to '0'. + * 2. Between line boxes inside a block box. + * + * These breaks are subject to the following rules: + * + * * Rule A: Breaking at (1) is allowed only if the + * 'page-break-after' and 'page-break-before' properties of + * all the elements generating boxes that meet at this margin + * allow it, which is when at least one of them has the value + * 'always', 'left', or 'right', or when all of them are + * 'auto'. + * + * * Rule B: However, if all of them are 'auto' and the + * nearest common ancestor of all the elements has a + * 'page-break-inside' value of 'avoid', then breaking here is + * not allowed. + * + * * Rule C: Breaking at (2) is allowed only if the number of + * line boxes between the break and the start of the enclosing + * block box is the value of 'orphans' or more, and the number + * of line boxes between the break and the end of the box is + * the value of 'widows' or more. + * + * * Rule D: In addition, breaking at (2) is allowed only if + * the 'page-break-inside' property is 'auto'. + * + * If the above doesn't provide enough break points to keep + * content from overflowing the page boxes, then rules B and D are + * dropped in order to find additional breakpoints. + * + * If that still does not lead to sufficient break points, rules A + * and C are dropped as well, to find still more break points. + * + * We will also allow breaks between table rows. However, when + * splitting a table, the table headers should carry over to the + * next page (but they don't yet). + * + * @param Frame $frame the frame to check + * + * @return bool true if a break is allowed, false otherwise + */ + protected function _page_break_allowed(Frame $frame) + { + + $block_types = array("block", "list-item", "table", "-dompdf-image"); + Helpers::dompdf_debug("page-break", "_page_break_allowed(" . $frame->get_node()->nodeName . ")"); + $display = $frame->get_style()->display; + + // Block Frames (1): + if (in_array($display, $block_types)) { + + // Avoid breaks within table-cells + if ($this->_in_table) { + Helpers::dompdf_debug("page-break", "In table: " . $this->_in_table); + + return false; + } + + // Rules A & B + + if ($frame->get_style()->page_break_before === "avoid") { + Helpers::dompdf_debug("page-break", "before: avoid"); + + return false; + } + + // Find the preceeding block-level sibling + $prev = $frame->get_prev_sibling(); + while ($prev && !in_array($prev->get_style()->display, $block_types)) { + $prev = $prev->get_prev_sibling(); + } + + // Does the previous element allow a page break after? + if ($prev && $prev->get_style()->page_break_after === "avoid") { + Helpers::dompdf_debug("page-break", "after: avoid"); + + return false; + } + + // If both $prev & $frame have the same parent, check the parent's + // page_break_inside property. + $parent = $frame->get_parent(); + if ($prev && $parent && $parent->get_style()->page_break_inside === "avoid") { + Helpers::dompdf_debug("page-break", "parent inside: avoid"); + + return false; + } + + // To prevent cascading page breaks when a top-level element has + // page-break-inside: avoid, ensure that at least one frame is + // on the page before splitting. + if ($parent->get_node()->nodeName === "body" && !$prev) { + // We are the body's first child + Helpers::dompdf_debug("page-break", "Body's first child."); + + return false; + } + + // If the frame is the first block-level frame, use the value from + // $frame's parent instead. + if (!$prev && $parent) { + return $this->_page_break_allowed($parent); + } + + Helpers::dompdf_debug("page-break", "block: break allowed"); + + return true; + + } // Inline frames (2): + else { + if (in_array($display, Style::$INLINE_TYPES)) { + + // Avoid breaks within table-cells + if ($this->_in_table) { + Helpers::dompdf_debug("page-break", "In table: " . $this->_in_table); + + return false; + } + + // Rule C + $block_parent = $frame->find_block_parent(); + if (count($block_parent->get_line_boxes()) < $frame->get_style()->orphans) { + Helpers::dompdf_debug("page-break", "orphans"); + + return false; + } + + // FIXME: Checking widows is tricky without having laid out the + // remaining line boxes. Just ignore it for now... + + // Rule D + $p = $block_parent; + while ($p) { + if ($p->get_style()->page_break_inside === "avoid") { + Helpers::dompdf_debug("page-break", "parent->inside: avoid"); + + return false; + } + $p = $p->find_block_parent(); + } + + // To prevent cascading page breaks when a top-level element has + // page-break-inside: avoid, ensure that at least one frame with + // some content is on the page before splitting. + $prev = $frame->get_prev_sibling(); + while ($prev && ($prev->is_text_node() && trim($prev->get_node()->nodeValue) == "")) { + $prev = $prev->get_prev_sibling(); + } + + if ($block_parent->get_node()->nodeName === "body" && !$prev) { + // We are the body's first child + Helpers::dompdf_debug("page-break", "Body's first child."); + + return false; + } + + // Skip breaks on empty text nodes + if ($frame->is_text_node() && + $frame->get_node()->nodeValue == "" + ) { + return false; + } + + Helpers::dompdf_debug("page-break", "inline: break allowed"); + + return true; + + // Table-rows + } else { + if ($display === "table-row") { + + // Simply check if the parent table's page_break_inside property is + // not 'avoid' + $p = Table::find_parent_table($frame); + + while ($p) { + if ($p->get_style()->page_break_inside === "avoid") { + Helpers::dompdf_debug("page-break", "parent->inside: avoid"); + + return false; + } + $p = $p->find_block_parent(); + } + + // Avoid breaking after the first row of a table + if ($p && $p->get_first_child() === $frame) { + Helpers::dompdf_debug("page-break", "table: first-row"); + + return false; + } + + // If this is a nested table, prevent the page from breaking + if ($this->_in_table > 1) { + Helpers::dompdf_debug("page-break", "table: nested table"); + + return false; + } + + Helpers::dompdf_debug("page-break", "table-row/row-groups: break allowed"); + + return true; + + } else { + if (in_array($display, Table::$ROW_GROUPS)) { + + // Disallow breaks at row-groups: only split at row boundaries + return false; + + } else { + + Helpers::dompdf_debug("page-break", "? " . $frame->get_style()->display . ""); + + return false; + } + } + } + } + + } + + /** + * Check if $frame will fit on the page. If the frame does not fit, + * the frame tree is modified so that a page break occurs in the + * correct location. + * + * @param Frame $frame the frame to check + * + * @return Frame the frame following the page break + */ + function check_page_break(Frame $frame) + { + // Do not split if we have already or if the frame was already + // pushed to the next page (prevents infinite loops) + if ($this->_page_full || $frame->_already_pushed) { + return false; + } + + // If the frame is absolute of fixed it shouldn't break + $p = $frame; + do { + if ($p->is_absolute()) + return false; + } while ($p = $p->get_parent()); + + $margin_height = $frame->get_margin_height(); + + // FIXME If the row is taller than the page and + // if it the first of the page, we don't break + if ($frame->get_style()->display === "table-row" && + !$frame->get_prev_sibling() && + $margin_height > $this->get_margin_height() + ) + return false; + + // Determine the frame's maximum y value + $max_y = $frame->get_position("y") + $margin_height; + + // If a split is to occur here, then the bottom margins & paddings of all + // parents of $frame must fit on the page as well: + $p = $frame->get_parent(); + while ($p) { + $style = $p->get_style(); + $max_y += $style->length_in_pt( + array( + $style->margin_bottom, + $style->padding_bottom, + $style->border_bottom_width + ) + ); + $p = $p->get_parent(); + } + + + // Check if $frame flows off the page + if ($max_y <= $this->_bottom_page_margin) + // no: do nothing + return false; + + Helpers::dompdf_debug("page-break", "check_page_break"); + Helpers::dompdf_debug("page-break", "in_table: " . $this->_in_table); + + // yes: determine page break location + $iter = $frame; + $flg = false; + + $in_table = $this->_in_table; + + Helpers::dompdf_debug("page-break", "Starting search"); + while ($iter) { + // echo "\nbacktrack: " .$iter->get_node()->nodeName ." ".spl_object_hash($iter->get_node()). ""; + if ($iter === $this) { + Helpers::dompdf_debug("page-break", "reached root."); + // We've reached the root in our search. Just split at $frame. + break; + } + + if ($this->_page_break_allowed($iter)) { + Helpers::dompdf_debug("page-break", "break allowed, splitting."); + $iter->split(null, true); + $this->_page_full = true; + $this->_in_table = $in_table; + $frame->_already_pushed = true; + + return true; + } + + if (!$flg && $next = $iter->get_last_child()) { + Helpers::dompdf_debug("page-break", "following last child."); + + if ($next->is_table()) + $this->_in_table++; + + $iter = $next; + continue; + } + + if ($next = $iter->get_prev_sibling()) { + Helpers::dompdf_debug("page-break", "following prev sibling."); + + if ($next->is_table() && !$iter->is_table()) + $this->_in_table++; + + else if (!$next->is_table() && $iter->is_table()) + $this->_in_table--; + + $iter = $next; + $flg = false; + continue; + } + + if ($next = $iter->get_parent()) { + Helpers::dompdf_debug("page-break", "following parent."); + + if ($iter->is_table()) + $this->_in_table--; + + $iter = $next; + $flg = true; + continue; + } + + break; + } + + $this->_in_table = $in_table; + + // No valid page break found. Just break at $frame. + Helpers::dompdf_debug("page-break", "no valid break found, just splitting."); + + // If we are in a table, backtrack to the nearest top-level table row + if ($this->_in_table) { + $iter = $frame; + while ($iter && $iter->get_style()->display !== "table-row" && $iter->get_style()->display !== 'table-row-group') + $iter = $iter->get_parent(); + + $iter->split(null, true); + } else { + $frame->split(null, true); + } + + $this->_page_full = true; + $frame->_already_pushed = true; + + return true; + } + + //........................................................................ + + function split(Frame $frame = null, $force_pagebreak = false) + { + // Do nothing + } + + /** + * Add a floating frame + * + * @param Frame $frame + * + * @return void + */ + function add_floating_frame(Frame $frame) + { + array_unshift($this->_floating_frames, $frame); + } + + /** + * @return Frame[] + */ + function get_floating_frames() + { + return $this->_floating_frames; + } + + public function remove_floating_frame($key) + { + unset($this->_floating_frames[$key]); + } + + public function get_lowest_float_offset(Frame $child) + { + $style = $child->get_style(); + $side = $style->clear; + $float = $style->float; + + $y = 0; + + foreach ($this->_floating_frames as $key => $frame) { + if ($side === "both" || $frame->get_style()->float === $side) { + $y = max($y, $frame->get_position("y") + $frame->get_margin_height()); + + if ($float !== "none") { + $this->remove_floating_frame($key); + } + } + } + + return $y; + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Table.php b/vendor/dompdf/dompdf/src/FrameDecorator/Table.php new file mode 100644 index 000000000..bdbead59e --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Table.php @@ -0,0 +1,370 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Cellmap; +use DOMNode; +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\Frame\Factory; + +/** + * Decorates Frames for table layout + * + * @package dompdf + */ +class Table extends AbstractFrameDecorator +{ + public static $VALID_CHILDREN = array( + "table-row-group", + "table-row", + "table-header-group", + "table-footer-group", + "table-column", + "table-column-group", + "table-caption", + "table-cell" + ); + + public static $ROW_GROUPS = array( + 'table-row-group', + 'table-header-group', + 'table-footer-group' + ); + + /** + * The Cellmap object for this table. The cellmap maps table cells + * to rows and columns, and aids in calculating column widths. + * + * @var \Dompdf\Cellmap + */ + protected $_cellmap; + + /** + * The minimum width of the table, in pt + * + * @var float + */ + protected $_min_width; + + /** + * The maximum width of the table, in pt + * + * @var float + */ + protected $_max_width; + + /** + * Table header rows. Each table header is duplicated when a table + * spans pages. + * + * @var array + */ + protected $_headers; + + /** + * Table footer rows. Each table footer is duplicated when a table + * spans pages. + * + * @var array + */ + protected $_footers; + + /** + * Class constructor + * + * @param Frame $frame the frame to decorate + * @param Dompdf $dompdf + */ + public function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + $this->_cellmap = new Cellmap($this); + + if ($frame->get_style()->table_layout === "fixed") { + $this->_cellmap->set_layout_fixed(true); + } + + $this->_min_width = null; + $this->_max_width = null; + $this->_headers = array(); + $this->_footers = array(); + } + + + public function reset() + { + parent::reset(); + $this->_cellmap->reset(); + $this->_min_width = null; + $this->_max_width = null; + $this->_headers = array(); + $this->_footers = array(); + $this->_reflower->reset(); + } + + //........................................................................ + + /** + * split the table at $row. $row and all subsequent rows will be + * added to the clone. This method is overidden in order to remove + * frames from the cellmap properly. + * + * @param Frame $child + * @param bool $force_pagebreak + * + * @return void + */ + public function split(Frame $child = null, $force_pagebreak = false) + { + if (is_null($child)) { + parent::split(); + + return; + } + + // If $child is a header or if it is the first non-header row, do + // not duplicate headers, simply move the table to the next page. + if (count($this->_headers) && !in_array($child, $this->_headers, true) && + !in_array($child->get_prev_sibling(), $this->_headers, true) + ) { + + $first_header = null; + + // Insert copies of the table headers before $child + foreach ($this->_headers as $header) { + + $new_header = $header->deep_copy(); + + if (is_null($first_header)) { + $first_header = $new_header; + } + + $this->insert_child_before($new_header, $child); + } + + parent::split($first_header); + + } elseif (in_array($child->get_style()->display, self::$ROW_GROUPS)) { + + // Individual rows should have already been handled + parent::split($child); + + } else { + + $iter = $child; + + while ($iter) { + $this->_cellmap->remove_row($iter); + $iter = $iter->get_next_sibling(); + } + + parent::split($child); + } + } + + /** + * Return a copy of this frame with $node as its node + * + * @param DOMNode $node + * + * @return Frame + */ + public function copy(DOMNode $node) + { + $deco = parent::copy($node); + + // In order to keep columns' widths through pages + $deco->_cellmap->set_columns($this->_cellmap->get_columns()); + $deco->_cellmap->lock_columns(); + + return $deco; + } + + /** + * Static function to locate the parent table of a frame + * + * @param Frame $frame + * + * @return Table the table that is an ancestor of $frame + */ + public static function find_parent_table(Frame $frame) + { + + while ($frame = $frame->get_parent()) + if ($frame->is_table()) + break; + + return $frame; + } + + /** + * Return this table's Cellmap + * + * @return \Dompdf\Cellmap + */ + public function get_cellmap() + { + return $this->_cellmap; + } + + /** + * Return the minimum width of this table + * + * @return float + */ + public function get_min_width() + { + return $this->_min_width; + } + + /** + * Return the maximum width of this table + * + * @return float + */ + public function get_max_width() + { + return $this->_max_width; + } + + /** + * Set the minimum width of the table + * + * @param float $width the new minimum width + */ + public function set_min_width($width) + { + $this->_min_width = $width; + } + + /** + * Set the maximum width of the table + * + * @param float $width the new maximum width + */ + public function set_max_width($width) + { + $this->_max_width = $width; + } + + /** + * Restructure tree so that the table has the correct structure. + * Invalid children (i.e. all non-table-rows) are moved below the + * table. + */ + public function normalise() + { + // Store frames generated by invalid tags and move them outside the table + $erroneous_frames = array(); + $anon_row = false; + $iter = $this->get_first_child(); + while ($iter) { + $child = $iter; + $iter = $iter->get_next_sibling(); + + $display = $child->get_style()->display; + + if ($anon_row) { + + if ($display === "table-row") { + // Add the previous anonymous row + $this->insert_child_before($table_row, $child); + + $table_row->normalise(); + $child->normalise(); + $anon_row = false; + continue; + } + + // add the child to the anonymous row + $table_row->append_child($child); + continue; + + } else { + + if ($display === "table-row") { + $child->normalise(); + continue; + } + + if ($display === "table-cell") { + // Create an anonymous table row + $tr = $this->get_node()->ownerDocument->createElement("tr"); + + $frame = new Frame($tr); + + $css = $this->get_style()->get_stylesheet(); + $style = $css->create_style(); + $style->inherit($this->get_style()); + + // Lookup styles for tr tags. If the user wants styles to work + // better, they should make the tr explicit... I'm not going to + // try to guess what they intended. + if ($tr_style = $css->lookup("tr")) { + $style->merge($tr_style); + } + + // Okay, I have absolutely no idea why I need this clone here, but + // if it's omitted, php (as of 2004-07-28) segfaults. + $frame->set_style(clone $style); + $table_row = Factory::decorate_frame($frame, $this->_dompdf, $this->_root); + + // Add the cell to the row + $table_row->append_child($child); + + $anon_row = true; + continue; + } + + if (!in_array($display, self::$VALID_CHILDREN)) { + $erroneous_frames[] = $child; + continue; + } + + // Normalise other table parts (i.e. row groups) + foreach ($child->get_children() as $grandchild) { + if ($grandchild->get_style()->display === "table-row") { + $grandchild->normalise(); + } + } + + // Add headers and footers + if ($display === "table-header-group") { + $this->_headers[] = $child; + } elseif ($display === "table-footer-group") { + $this->_footers[] = $child; + } + } + } + + if ($anon_row && $table_row instanceof DOMNode) { + // Add the row to the table + $this->_frame->append_child($table_row); + $table_row->normalise(); + $this->_cellmap->add_row(); + } + + foreach ($erroneous_frames as $frame) { + $this->move_after($frame); + } + } + + //........................................................................ + + /** + * Moves the specified frame and it's corresponding node outside of + * the table. + * + * @param Frame $frame the frame to move + */ + public function move_after(Frame $frame) + { + $this->get_parent()->insert_child_after($frame, $this); + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php b/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php new file mode 100644 index 000000000..b8259d72f --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/TableCell.php @@ -0,0 +1,117 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; + +/** + * Decorates table cells for layout + * + * @package dompdf + */ +class TableCell extends BlockFrameDecorator +{ + + protected $_resolved_borders; + protected $_content_height; + + //........................................................................ + + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + $this->_resolved_borders = array(); + $this->_content_height = 0; + } + + //........................................................................ + + function reset() + { + parent::reset(); + $this->_resolved_borders = array(); + $this->_content_height = 0; + $this->_frame->reset(); + } + + function get_content_height() + { + return $this->_content_height; + } + + function set_content_height($height) + { + $this->_content_height = $height; + } + + function set_cell_height($height) + { + $style = $this->get_style(); + $v_space = $style->length_in_pt(array($style->margin_top, + $style->padding_top, + $style->border_top_width, + $style->border_bottom_width, + $style->padding_bottom, + $style->margin_bottom), + $style->width); + + $new_height = $height - $v_space; + $style->height = $new_height; + + if ($new_height > $this->_content_height) { + $y_offset = 0; + + // Adjust our vertical alignment + switch ($style->vertical_align) { + default: + case "baseline": + // FIXME: this isn't right + + case "top": + // Don't need to do anything + return; + + case "middle": + $y_offset = ($new_height - $this->_content_height) / 2; + break; + + case "bottom": + $y_offset = $new_height - $this->_content_height; + break; + } + + if ($y_offset) { + // Move our children + foreach ($this->get_line_boxes() as $line) { + foreach ($line->get_frames() as $frame) + $frame->move(0, $y_offset); + } + } + } + + } + + function set_resolved_border($side, $border_spec) + { + $this->_resolved_borders[$side] = $border_spec; + } + + //........................................................................ + + function get_resolved_border($side) + { + return $this->_resolved_borders[$side]; + } + + function get_resolved_borders() + { + return $this->_resolved_borders; + } +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php b/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php new file mode 100644 index 000000000..7f33082a2 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/TableRow.php @@ -0,0 +1,52 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\FrameDecorator\Table as TableFrameDecorator; + +/** + * Decorates Frames for table row layout + * + * @package dompdf + */ +class TableRow extends AbstractFrameDecorator +{ + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + } + + //........................................................................ + + /** + * Remove all non table-cell frames from this row and move them after + * the table. + */ + function normalise() + { + + // Find our table parent + $p = TableFrameDecorator::find_parent_table($this); + + $erroneous_frames = array(); + foreach ($this->get_children() as $child) { + $display = $child->get_style()->display; + + if ($display !== "table-cell") + $erroneous_frames[] = $child; + } + + // dump the extra nodes after the table. + foreach ($erroneous_frames as $frame) + $p->move_after($frame); + } + + +} diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/TableRowGroup.php b/vendor/dompdf/dompdf/src/FrameDecorator/TableRowGroup.php new file mode 100644 index 000000000..0f2bb7967 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/TableRowGroup.php @@ -0,0 +1,72 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; + +/** + * Table row group decorator + * + * Overrides split() method for tbody, thead & tfoot elements + * + * @package dompdf + */ +class TableRowGroup extends AbstractFrameDecorator +{ + + /** + * Class constructor + * + * @param Frame $frame Frame to decorate + * @param Dompdf $dompdf Current dompdf instance + */ + function __construct(Frame $frame, Dompdf $dompdf) + { + parent::__construct($frame, $dompdf); + } + + /** + * Override split() to remove all child rows and this element from the cellmap + * + * @param Frame $child + * @param bool $force_pagebreak + * + * @return void + */ + function split(Frame $child = null, $force_pagebreak = false) + { + + if (is_null($child)) { + parent::split(); + return; + } + + // Remove child & all subsequent rows from the cellmap + $cellmap = $this->get_parent()->get_cellmap(); + $iter = $child; + + while ($iter) { + $cellmap->remove_row($iter); + $iter = $iter->get_next_sibling(); + } + + // If we are splitting at the first child remove the + // table-row-group from the cellmap as well + if ($child === $this->get_first_child()) { + $cellmap->remove_row_group($this); + parent::split(); + return; + } + + $cellmap->update_row_group($this, $child->get_prev_sibling()); + parent::split($child); + + } +} + diff --git a/vendor/dompdf/dompdf/src/FrameDecorator/Text.php b/vendor/dompdf/dompdf/src/FrameDecorator/Text.php new file mode 100644 index 000000000..7a78879cb --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameDecorator/Text.php @@ -0,0 +1,182 @@ + + * @author Brian Sweeney + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameDecorator; + +use Dompdf\Dompdf; +use Dompdf\Frame; +use Dompdf\Exception; +use DOMText; +use Dompdf\FontMetrics; + +/** + * Decorates Frame objects for text layout + * + * @access private + * @package dompdf + */ +class Text extends AbstractFrameDecorator +{ + + // protected members + protected $_text_spacing; + + function __construct(Frame $frame, Dompdf $dompdf) + { + if (!$frame->is_text_node()) { + throw new Exception("Text_Decorator can only be applied to #text nodes."); + } + + parent::__construct($frame, $dompdf); + $this->_text_spacing = null; + } + + //........................................................................ + + function reset() + { + parent::reset(); + $this->_text_spacing = null; + } + + //........................................................................ + + // Accessor methods + function get_text_spacing() + { + return $this->_text_spacing; + } + + function get_text() + { + // FIXME: this should be in a child class (and is incorrect) +// if ( $this->_frame->get_style()->content !== "normal" ) { +// $this->_frame->get_node()->data = $this->_frame->get_style()->content; +// $this->_frame->get_style()->content = "normal"; +// } + +// Helpers::pre_r("---"); +// $style = $this->_frame->get_style(); +// var_dump($text = $this->_frame->get_node()->data); +// var_dump($asc = utf8_decode($text)); +// for ($i = 0; $i < strlen($asc); $i++) +// Helpers::pre_r("$i: " . $asc[$i] . " - " . ord($asc[$i])); +// Helpers::pre_r("width: " . $this->_dompdf->getFontMetrics()->getTextWidth($text, $style->font_family, $style->font_size)); + + return $this->_frame->get_node()->data; + } + + //........................................................................ + + // Vertical margins & padding do not apply to text frames + + // http://www.w3.org/TR/CSS21/visudet.html#inline-non-replaced: + // + // The vertical padding, border and margin of an inline, non-replaced box + // start at the top and bottom of the content area, not the + // 'line-height'. But only the 'line-height' is used to calculate the + // height of the line box. + function get_margin_height() + { + // This function is called in add_frame_to_line() and is used to + // determine the line height, so we actually want to return the + // 'line-height' property, not the actual margin box + $style = $this->get_parent()->get_style(); + $font = $style->font_family; + $size = $style->font_size; + + /* + Helpers::pre_r('-----'); + Helpers::pre_r($style->line_height); + Helpers::pre_r($style->font_size); + Helpers::pre_r($this->_dompdf->getFontMetrics()->getFontHeight($font, $size)); + Helpers::pre_r(($style->line_height / $size) * $this->_dompdf->getFontMetrics()->getFontHeight($font, $size)); + */ + + return ($style->line_height / ($size > 0 ? $size : 1)) * $this->_dompdf->getFontMetrics()->getFontHeight($font, $size); + + } + + function get_padding_box() + { + $pb = $this->_frame->get_padding_box(); + $pb[3] = $pb["h"] = $this->_frame->get_style()->height; + + return $pb; + } + //........................................................................ + + // Set method + function set_text_spacing($spacing) + { + $style = $this->_frame->get_style(); + + $this->_text_spacing = $spacing; + $char_spacing = $style->length_in_pt($style->letter_spacing); + + // Re-adjust our width to account for the change in spacing + $style->width = $this->_dompdf->getFontMetrics()->getTextWidth($this->get_text(), $style->font_family, $style->font_size, $spacing, $char_spacing); + } + + //........................................................................ + + // Recalculate the text width + function recalculate_width() + { + $style = $this->get_style(); + $text = $this->get_text(); + $size = $style->font_size; + $font = $style->font_family; + $word_spacing = $style->length_in_pt($style->word_spacing); + $char_spacing = $style->length_in_pt($style->letter_spacing); + + return $style->width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing); + } + + //........................................................................ + + // Text manipulation methods + + // split the text in this frame at the offset specified. The remaining + // text is added a sibling frame following this one and is returned. + function split_text($offset) + { + if ($offset == 0) { + return null; + } + + $split = $this->_frame->get_node()->splitText($offset); + + $deco = $this->copy($split); + + $p = $this->get_parent(); + $p->insert_child_after($deco, $this, false); + + if ($p instanceof Inline) { + $p->split($deco); + } + + return $deco; + } + + //........................................................................ + + function delete_text($offset, $count) + { + $this->_frame->get_node()->deleteData($offset, $count); + } + + //........................................................................ + + function set_text($text) + { + $this->_frame->get_node()->data = $text; + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php b/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php new file mode 100644 index 000000000..281ae44e4 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/AbstractFrameReflower.php @@ -0,0 +1,460 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\Adapter\CPDF; +use Dompdf\Css\Style; +use Dompdf\Dompdf; +use Dompdf\Helpers; +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block; +use Dompdf\Frame\Factory; + +/** + * Base reflower class + * + * Reflower objects are responsible for determining the width and height of + * individual frames. They also create line and page breaks as necessary. + * + * @package dompdf + */ +abstract class AbstractFrameReflower +{ + + /** + * Frame for this reflower + * + * @var Frame + */ + protected $_frame; + + /** + * Cached min/max size + * + * @var array + */ + protected $_min_max_cache; + + function __construct(Frame $frame) + { + $this->_frame = $frame; + $this->_min_max_cache = null; + } + + function dispose() + { + } + + /** + * @return Dompdf + */ + function get_dompdf() + { + return $this->_frame->get_dompdf(); + } + + /** + * Collapse frames margins + * http://www.w3.org/TR/CSS2/box.html#collapsing-margins + */ + protected function _collapse_margins() + { + $frame = $this->_frame; + $cb = $frame->get_containing_block(); + $style = $frame->get_style(); + + if (!$frame->is_in_flow()) { + return; + } + + $t = $style->length_in_pt($style->margin_top, $cb["h"]); + $b = $style->length_in_pt($style->margin_bottom, $cb["h"]); + + // Handle 'auto' values + if ($t === "auto") { + $style->margin_top = "0pt"; + $t = 0; + } + + if ($b === "auto") { + $style->margin_bottom = "0pt"; + $b = 0; + } + + // Collapse vertical margins: + $n = $frame->get_next_sibling(); + if ($n && !$n->is_block()) { + while ($n = $n->get_next_sibling()) { + if ($n->is_block()) { + break; + } + + if (!$n->get_first_child()) { + $n = null; + break; + } + } + } + + if ($n) { + $n_style = $n->get_style(); + $b = max($b, $n_style->length_in_pt($n_style->margin_top, $cb["h"])); + $n_style->margin_top = "0pt"; + $style->margin_bottom = $b . "pt"; + } + + // Collapse our first child's margin + /*$f = $this->_frame->get_first_child(); + if ( $f && !$f->is_block() ) { + while ( $f = $f->get_next_sibling() ) { + if ( $f->is_block() ) { + break; + } + + if ( !$f->get_first_child() ) { + $f = null; + break; + } + } + } + + // Margin are collapsed only between block elements + if ( $f ) { + $f_style = $f->get_style(); + $t = max($t, $f_style->length_in_pt($f_style->margin_top, $cb["h"])); + $style->margin_top = $t."pt"; + $f_style->margin_bottom = "0pt"; + }*/ + } + + //........................................................................ + + abstract function reflow(Block $block = null); + + //........................................................................ + + // Required for table layout: Returns an array(0 => min, 1 => max, "min" + // => min, "max" => max) of the minimum and maximum widths of this frame. + // This provides a basic implementation. Child classes should override + // this if necessary. + 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); + } + + /** + * Parses a CSS string containing quotes and escaped hex characters + * + * @param $string string The CSS string to parse + * @param $single_trim + * @return string + */ + protected function _parse_string($string, $single_trim = false) + { + if ($single_trim) { + $string = preg_replace('/^[\"\']/', "", $string); + $string = preg_replace('/[\"\']$/', "", $string); + } else { + $string = trim($string, "'\""); + } + + $string = str_replace(array("\\\n", '\\"', "\\'"), + array("", '"', "'"), $string); + + // Convert escaped hex characters into ascii characters (e.g. \A => newline) + $string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/", + function ($matches) { return \Dompdf\Helpers::unichr(hexdec($matches[1])); }, + $string); + return $string; + } + + /** + * Parses a CSS "quotes" property + * + * @return array|null An array of pairs of quotes + */ + protected function _parse_quotes() + { + + // Matches quote types + $re = '/(\'[^\']*\')|(\"[^\"]*\")/'; + + $quotes = $this->_frame->get_style()->quotes; + + // split on spaces, except within quotes + if (!preg_match_all($re, "$quotes", $matches, PREG_SET_ORDER)) { + return null; + } + + $quotes_array = array(); + foreach ($matches as $_quote) { + $quotes_array[] = $this->_parse_string($_quote[0], true); + } + + if (empty($quotes_array)) { + $quotes_array = array('"', '"'); + } + + return array_chunk($quotes_array, 2); + } + + /** + * Parses the CSS "content" property + * + * @return string|null The resulting string + */ + protected function _parse_content() + { + + // Matches generated content + $re = "/\n" . + "\s(counters?\\([^)]*\\))|\n" . + "\A(counters?\\([^)]*\\))|\n" . + "\s([\"']) ( (?:[^\"']|\\\\[\"'])+ )(?_frame->get_style()->content; + + $quotes = $this->_parse_quotes(); + + // split on spaces, except within quotes + if (!preg_match_all($re, $content, $matches, PREG_SET_ORDER)) { + return null; + } + + $text = ""; + + foreach ($matches as $match) { + + if (isset($match[2]) && $match[2] !== "") { + $match[1] = $match[2]; + } + + if (isset($match[6]) && $match[6] !== "") { + $match[4] = $match[6]; + } + + if (isset($match[8]) && $match[8] !== "") { + $match[7] = $match[8]; + } + + if (isset($match[1]) && $match[1] !== "") { + + // counters?(...) + $match[1] = mb_strtolower(trim($match[1])); + + // Handle counter() references: + // http://www.w3.org/TR/CSS21/generate.html#content + + $i = mb_strpos($match[1], ")"); + if ($i === false) { + continue; + } + + preg_match('/(counters?)(^\()*?\(\s*([^\s,]+)\s*(,\s*["\']?([^"\'\)]+)["\']?\s*(,\s*([^\s)]+)\s*)?)?\)/i', $match[1], $args); + $counter_id = $args[3]; + if (strtolower($args[1]) == 'counter') { + // counter(name [,style]) + if (isset($args[5])) { + $type = trim($args[5]); + } else { + $type = null; + } + $p = $this->_frame->lookup_counter_frame($counter_id); + + $text .= $p->counter_value($counter_id, $type); + + } else if (strtolower($args[1]) == 'counters') { + // counters(name, string [,style]) + if (isset($args[5])) { + $string = $this->_parse_string($args[5]); + } else { + $string = ""; + } + + if (isset($args[7])) { + $type = trim($args[7]); + } else { + $type = null; + } + + $p = $this->_frame->lookup_counter_frame($counter_id); + $tmp = array(); + while ($p) { + // We only want to use the counter values when they actually increment the counter + if (array_key_exists($counter_id, $p->_counters)) { + array_unshift($tmp, $p->counter_value($counter_id, $type)); + } + $p = $p->lookup_counter_frame($counter_id); + + } + $text .= implode($string, $tmp); + + } else { + // countertops? + continue; + } + + } else if (isset($match[4]) && $match[4] !== "") { + // String match + $text .= $this->_parse_string($match[4]); + } else if (isset($match[7]) && $match[7] !== "") { + // Directive match + + if ($match[7] === "open-quote") { + // FIXME: do something here + $text .= $quotes[0][0]; + } else if ($match[7] === "close-quote") { + // FIXME: do something else here + $text .= $quotes[0][1]; + } else if ($match[7] === "no-open-quote") { + // FIXME: + } else if ($match[7] === "no-close-quote") { + // FIXME: + } else if (mb_strpos($match[7], "attr(") === 0) { + + $i = mb_strpos($match[7], ")"); + if ($i === false) { + continue; + } + + $attr = mb_substr($match[7], 5, $i - 5); + if ($attr == "") { + continue; + } + + $text .= $this->_frame->get_parent()->get_node()->getAttribute($attr); + } else { + continue; + } + } + } + + return $text; + } + + /** + * Sets the generated content of a generated frame + */ + protected function _set_content() + { + $frame = $this->_frame; + $style = $frame->get_style(); + + // if the element was pushed to a new page use the saved counter value, otherwise use the CSS reset value + if ($style->counter_reset && ($reset = $style->counter_reset) !== "none") { + $vars = preg_split('/\s+/', trim($reset), 2); + $frame->reset_counter($vars[0], (isset($frame->_counters['__' . $vars[0]]) ? $frame->_counters['__' . $vars[0]] : (isset($vars[1]) ? $vars[1] : 0))); + } + + if ($style->counter_increment && ($increment = $style->counter_increment) !== "none") { + $frame->increment_counters($increment); + } + + if ($style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated") { + $content = $this->_parse_content(); + // add generated content to the font subset + // FIXME: This is currently too late because the font subset has already been generated. + // See notes in issue #750. + if ($frame->get_dompdf()->get_option("enable_font_subsetting") && $frame->get_dompdf()->get_canvas() instanceof CPDF) { + $frame->get_dompdf()->get_canvas()->register_string_subset($style->font_family, $content); + } + + $node = $frame->get_node()->ownerDocument->createTextNode($content); + + $new_style = $style->get_stylesheet()->create_style(); + $new_style->inherit($style); + + $new_frame = new Frame($node); + $new_frame->set_style($new_style); + + Factory::decorate_frame($new_frame, $frame->get_dompdf(), $frame->get_root()); + $frame->append_child($new_frame); + } + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Block.php b/vendor/dompdf/dompdf/src/FrameReflower/Block.php new file mode 100644 index 000000000..db5da39c9 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Block.php @@ -0,0 +1,793 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FontMetrics; +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Text as TextFrameDecorator; +use Dompdf\Exception; + +/** + * Reflows block frames + * + * @package dompdf + */ +class Block extends AbstractFrameReflower +{ + // Minimum line width to justify, as fraction of available width + const MIN_JUSTIFY_WIDTH = 0.80; + + /** + * @var BlockFrameDecorator + */ + protected $_frame; + + function __construct(BlockFrameDecorator $frame) + { + parent::__construct($frame); + } + + /** + * Calculate the ideal used value for the width property as per: + * http://www.w3.org/TR/CSS21/visudet.html#Computing_widths_and_margins + * + * @param float $width + * + * @return array + */ + protected function _calculate_width($width) + { + $frame = $this->_frame; + $style = $frame->get_style(); + $w = $frame->get_containing_block("w"); + + if ($style->position === "fixed") { + $w = $frame->get_parent()->get_containing_block("w"); + } + + $rm = $style->length_in_pt($style->margin_right, $w); + $lm = $style->length_in_pt($style->margin_left, $w); + + $left = $style->length_in_pt($style->left, $w); + $right = $style->length_in_pt($style->right, $w); + + // Handle 'auto' values + $dims = array($style->border_left_width, + $style->border_right_width, + $style->padding_left, + $style->padding_right, + $width !== "auto" ? $width : 0, + $rm !== "auto" ? $rm : 0, + $lm !== "auto" ? $lm : 0); + + // absolutely positioned boxes take the 'left' and 'right' properties into account + if ($frame->is_absolute()) { + $absolute = true; + $dims[] = $left !== "auto" ? $left : 0; + $dims[] = $right !== "auto" ? $right : 0; + } else { + $absolute = false; + } + + $sum = $style->length_in_pt($dims, $w); + + // Compare to the containing block + $diff = $w - $sum; + + if ($diff > 0) { + + if ($absolute) { + + // resolve auto properties: see + // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width + + if ($width === "auto" && $left === "auto" && $right === "auto") { + + if ($lm === "auto") $lm = 0; + if ($rm === "auto") $rm = 0; + + // Technically, the width should be "shrink-to-fit" i.e. based on the + // preferred width of the content... a little too costly here as a + // special case. Just get the width to take up the slack: + $left = 0; + $right = 0; + $width = $diff; + } else if ($width === "auto") { + + if ($lm === "auto") $lm = 0; + if ($rm === "auto") $rm = 0; + if ($left === "auto") $left = 0; + if ($right === "auto") $right = 0; + + $width = $diff; + } else if ($left === "auto") { + + if ($lm === "auto") $lm = 0; + if ($rm === "auto") $rm = 0; + if ($right === "auto") $right = 0; + + $left = $diff; + } else if ($right === "auto") { + + if ($lm === "auto") $lm = 0; + if ($rm === "auto") $rm = 0; + + $right = $diff; + } + + } else { + + // Find auto properties and get them to take up the slack + if ($width === "auto") { + $width = $diff; + } else if ($lm === "auto" && $rm === "auto") { + $lm = $rm = round($diff / 2); + } else if ($lm === "auto") { + $lm = $diff; + } else if ($rm === "auto") { + $rm = $diff; + } + } + + } else if ($diff < 0) { + + // We are over constrained--set margin-right to the difference + $rm = $diff; + + } + + return array( + "width" => $width, + "margin_left" => $lm, + "margin_right" => $rm, + "left" => $left, + "right" => $right, + ); + } + + /** + * Call the above function, but resolve max/min widths + * + * @throws Exception + * @return array + */ + protected function _calculate_restricted_width() + { + $frame = $this->_frame; + $style = $frame->get_style(); + $cb = $frame->get_containing_block(); + + if ($style->position === "fixed") { + $cb = $frame->get_root()->get_containing_block(); + } + + //if ( $style->position === "absolute" ) + // $cb = $frame->find_positionned_parent()->get_containing_block(); + + if (!isset($cb["w"])) { + throw new Exception("Box property calculation requires containing block width"); + } + + // Treat width 100% as auto + if ($style->width === "100%") { + $width = "auto"; + } else { + $width = $style->length_in_pt($style->width, $cb["w"]); + } + + extract($this->_calculate_width($width)); + + // Handle min/max width + $min_width = $style->length_in_pt($style->min_width, $cb["w"]); + $max_width = $style->length_in_pt($style->max_width, $cb["w"]); + + if ($max_width !== "none" && $min_width > $max_width) { + list($max_width, $min_width) = array($min_width, $max_width); + } + + if ($max_width !== "none" && $width > $max_width) { + extract($this->_calculate_width($max_width)); + } + + if ($width < $min_width) { + extract($this->_calculate_width($min_width)); + } + + return array($width, $margin_left, $margin_right, $left, $right); + } + + /** + * Determine the unrestricted height of content within the block + * not by adding each line's height, but by getting the last line's position. + * This because lines could have been pushed lower by a clearing element. + * + * @return float + */ + protected function _calculate_content_height() + { + $lines = $this->_frame->get_line_boxes(); + $height = 0; + + foreach ($lines as $line) { + $height += $line->h; + } + + /* + $first_line = reset($lines); + $last_line = end($lines); + $height2 = $last_line->y + $last_line->h - $first_line->y; + */ + + return $height; + } + + /** + * Determine the frame's restricted height + * + * @return array + */ + protected function _calculate_restricted_height() + { + $frame = $this->_frame; + $style = $frame->get_style(); + $content_height = $this->_calculate_content_height(); + $cb = $frame->get_containing_block(); + + $height = $style->length_in_pt($style->height, $cb["h"]); + + $top = $style->length_in_pt($style->top, $cb["h"]); + $bottom = $style->length_in_pt($style->bottom, $cb["h"]); + + $margin_top = $style->length_in_pt($style->margin_top, $cb["h"]); + $margin_bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); + + if ($frame->is_absolute()) { + + // see http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height + + $dims = array($top !== "auto" ? $top : 0, + $style->margin_top !== "auto" ? $style->margin_top : 0, + $style->padding_top, + $style->border_top_width, + $height !== "auto" ? $height : 0, + $style->border_bottom_width, + $style->padding_bottom, + $style->margin_bottom !== "auto" ? $style->margin_bottom : 0, + $bottom !== "auto" ? $bottom : 0); + + $sum = $style->length_in_pt($dims, $cb["h"]); + + $diff = $cb["h"] - $sum; + + if ($diff > 0) { + + if ($height === "auto" && $top === "auto" && $bottom === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $height = $diff; + } else if ($height === "auto" && $top === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $height = $content_height; + $top = $diff - $content_height; + } else if ($height === "auto" && $bottom === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $height = $content_height; + $bottom = $diff - $content_height; + } else if ($top === "auto" && $bottom === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $bottom = $diff; + } else if ($top === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $top = $diff; + } else if ($height === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $height = $diff; + } else if ($bottom === "auto") { + + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + + $bottom = $diff; + } else { + + if ($style->overflow === "visible") { + // set all autos to zero + if ($margin_top === "auto") $margin_top = 0; + if ($margin_bottom === "auto") $margin_bottom = 0; + if ($top === "auto") $top = 0; + if ($bottom === "auto") $bottom = 0; + if ($height === "auto") $height = $content_height; + } + + // FIXME: overflow hidden + } + + } + + } else { + + // Expand the height if overflow is visible + if ($height === "auto" && $content_height > $height /* && $style->overflow === "visible" */) { + $height = $content_height; + } + + // FIXME: this should probably be moved to a seperate function as per + // _calculate_restricted_width + + // Only handle min/max height if the height is independent of the frame's content + if (!($style->overflow === "visible" || + ($style->overflow === "hidden" && $height === "auto")) + ) { + + $min_height = $style->min_height; + $max_height = $style->max_height; + + if (isset($cb["h"])) { + $min_height = $style->length_in_pt($min_height, $cb["h"]); + $max_height = $style->length_in_pt($max_height, $cb["h"]); + + } else if (isset($cb["w"])) { + + if (mb_strpos($min_height, "%") !== false) { + $min_height = 0; + } else { + $min_height = $style->length_in_pt($min_height, $cb["w"]); + } + + if (mb_strpos($max_height, "%") !== false) { + $max_height = "none"; + } else { + $max_height = $style->length_in_pt($max_height, $cb["w"]); + } + } + + if ($max_height !== "none" && $min_height > $max_height) { + // Swap 'em + list($max_height, $min_height) = array($min_height, $max_height); + } + + if ($max_height !== "none" && $height > $max_height) { + $height = $max_height; + } + + if ($height < $min_height) { + $height = $min_height; + } + } + + } + + return array($height, $margin_top, $margin_bottom, $top, $bottom); + + } + + /** + * Adjust the justification of each of our lines. + * http://www.w3.org/TR/CSS21/text.html#propdef-text-align + */ + protected function _text_align() + { + $style = $this->_frame->get_style(); + $w = $this->_frame->get_containing_block("w"); + $width = $style->length_in_pt($style->width, $w); + + switch ($style->text_align) { + default: + case "left": + foreach ($this->_frame->get_line_boxes() as $line) { + if (!$line->left) { + continue; + } + + foreach ($line->get_frames() as $frame) { + if ($frame instanceof BlockFrameDecorator) { + continue; + } + $frame->set_position($frame->get_position("x") + $line->left); + } + } + return; + + case "right": + foreach ($this->_frame->get_line_boxes() as $line) { + // Move each child over by $dx + $dx = $width - $line->w - $line->right; + + foreach ($line->get_frames() as $frame) { + // Block frames are not aligned by text-align + if ($frame instanceof BlockFrameDecorator) { + continue; + } + + $frame->set_position($frame->get_position("x") + $dx); + } + } + break; + + + case "justify": + // We justify all lines except the last one + $lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards) + array_pop($lines); + + foreach ($lines as $i => $line) { + if ($line->br) { + unset($lines[$i]); + } + } + + // One space character's width. Will be used to get a more accurate spacing + $space_width = $this->get_dompdf()->getFontMetrics()->getTextWidth(" ", $style->font_family, $style->font_size); + + foreach ($lines as $line) { + if ($line->left) { + foreach ($line->get_frames() as $frame) { + if (!$frame instanceof TextFrameDecorator) { + continue; + } + + $frame->set_position($frame->get_position("x") + $line->left); + } + } + + // Only set the spacing if the line is long enough. This is really + // just an aesthetic choice ;) + //if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) { + + // Set the spacing for each child + if ($line->wc > 1) { + $spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1); + } else { + $spacing = 0; + } + + $dx = 0; + foreach ($line->get_frames() as $frame) { + if (!$frame instanceof TextFrameDecorator) { + continue; + } + + $text = $frame->get_text(); + $spaces = mb_substr_count($text, " "); + + $char_spacing = $style->length_in_pt($style->letter_spacing); + $_spacing = $spacing + $char_spacing; + + $frame->set_position($frame->get_position("x") + $dx); + $frame->set_text_spacing($_spacing); + + $dx += $spaces * $_spacing; + } + + // The line (should) now occupy the entire width + $line->w = $width; + + //} + } + break; + + case "center": + case "centre": + foreach ($this->_frame->get_line_boxes() as $line) { + // Centre each line by moving each frame in the line by: + $dx = ($width + $line->left - $line->w - $line->right) / 2; + + foreach ($line->get_frames() as $frame) { + // Block frames are not aligned by text-align + if ($frame instanceof BlockFrameDecorator) { + continue; + } + + $frame->set_position($frame->get_position("x") + $dx); + } + } + break; + } + } + + /** + * Align inline children vertically. + * Aligns each child vertically after each line is reflowed + */ + function vertical_align() + { + + $canvas = null; + + foreach ($this->_frame->get_line_boxes() as $line) { + + $height = $line->h; + + foreach ($line->get_frames() as $frame) { + $style = $frame->get_style(); + + if ($style->display !== "inline") { + continue; + } + + $align = $frame->get_parent()->get_style()->vertical_align; + + if (!isset($canvas)) { + $canvas = $frame->get_root()->get_dompdf()->get_canvas(); + } + + $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size); + $y_offset = 0; + + switch ($align) { + case "baseline": + $y_offset = $height * 0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning + break; + + case "middle": + $y_offset = ($height * 0.8 - $baseline) / 2; + break; + + case "sub": + $y_offset = 0.3 * $height; + break; + + case "super": + $y_offset = -0.2 * $height; + break; + + case "text-top": + case "top": // Not strictly accurate, but good enough for now + break; + + case "text-bottom": + case "bottom": + $y_offset = $height * 0.8 - $baseline; + break; + } + + if ($y_offset) { + $frame->move(0, $y_offset); + } + } + } + } + + /** + * @param Frame $child + */ + function process_clear(Frame $child) + { + $child_style = $child->get_style(); + $root = $this->_frame->get_root(); + + // Handle "clear" + if ($child_style->clear !== "none") { + $lowest_y = $root->get_lowest_float_offset($child); + + // If a float is still applying, we handle it + if ($lowest_y) { + if ($child->is_in_flow()) { + $line_box = $this->_frame->get_current_line_box(); + $line_box->y = $lowest_y + $child->get_margin_height(); + $line_box->left = 0; + $line_box->right = 0; + } + + $child->move(0, $lowest_y - $child->get_position("y")); + } + } + } + + /** + * @param Frame $child + * @param float $cb_x + * @param float $cb_w + */ + function process_float(Frame $child, $cb_x, $cb_w) + { + $child_style = $child->get_style(); + $root = $this->_frame->get_root(); + + // Handle "float" + if ($child_style->float !== "none") { + $root->add_floating_frame($child); + + // Remove next frame's beginning whitespace + $next = $child->get_next_sibling(); + if ($next && $next instanceof TextFrameDecorator) { + $next->set_text(ltrim($next->get_text())); + } + + $line_box = $this->_frame->get_current_line_box(); + list($old_x, $old_y) = $child->get_position(); + + $float_x = $cb_x; + $float_y = $old_y; + $float_w = $child->get_margin_width(); + + if ($child_style->clear === "none") { + switch ($child_style->float) { + case "left": + $float_x += $line_box->left; + break; + case "right": + $float_x += ($cb_w - $line_box->right - $float_w); + break; + } + } else { + if ($child_style->float === "right") { + $float_x += ($cb_w - $float_w); + } + } + + if ($cb_w < $float_x + $float_w - $old_x) { + // TODO handle when floating elements don't fit + } + + $line_box->get_float_offsets(); + + if ($child->_float_next_line) { + $float_y += $line_box->h; + } + + $child->set_position($float_x, $float_y); + $child->move($float_x - $old_x, $float_y - $old_y, true); + } + } + + /** + * @param BlockFrameDecorator $block + */ + function reflow(BlockFrameDecorator $block = null) + { + + // Check if a page break is forced + $page = $this->_frame->get_root(); + $page->check_forced_page_break($this->_frame); + + // Bail if the page is full + if ($page->is_full()) { + return; + } + + // Generated content + $this->_set_content(); + + // Collapse margins if required + $this->_collapse_margins(); + + $style = $this->_frame->get_style(); + $cb = $this->_frame->get_containing_block(); + + if ($style->position === "fixed") { + $cb = $this->_frame->get_root()->get_containing_block(); + } + + // Determine the constraints imposed by this frame: calculate the width + // of the content area: + list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width(); + + // Store the calculated properties + $style->width = $w . "pt"; + $style->margin_left = $left_margin . "pt"; + $style->margin_right = $right_margin . "pt"; + $style->left = $left . "pt"; + $style->right = $right . "pt"; + + // Update the position + $this->_frame->position(); + list($x, $y) = $this->_frame->get_position(); + + // Adjust the first line based on the text-indent property + $indent = $style->length_in_pt($style->text_indent, $cb["w"]); + $this->_frame->increase_line_width($indent); + + // Determine the content edge + $top = $style->length_in_pt(array($style->margin_top, + $style->padding_top, + $style->border_top_width), $cb["h"]); + + $bottom = $style->length_in_pt(array($style->border_bottom_width, + $style->margin_bottom, + $style->padding_bottom), $cb["h"]); + + $cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width, + $style->padding_left), $cb["w"]); + + $cb_y = $y + $top; + + $cb_h = ($cb["h"] + $cb["y"]) - $bottom - $cb_y; + + // Set the y position of the first line in this block + $line_box = $this->_frame->get_current_line_box(); + $line_box->y = $cb_y; + $line_box->get_float_offsets(); + + // Set the containing blocks and reflow each child + foreach ($this->_frame->get_children() as $child) { + + // Bail out if the page is full + if ($page->is_full()) { + break; + } + + $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); + + $this->process_clear($child); + + $child->reflow($this->_frame); + + // Don't add the child to the line if a page break has occurred + if ($page->check_page_break($child)) { + break; + } + + $this->process_float($child, $cb_x, $w); + } + + // Determine our height + list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height(); + $style->height = $height; + $style->margin_top = $margin_top; + $style->margin_bottom = $margin_bottom; + $style->top = $top; + $style->bottom = $bottom; + + $needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto")); + + // Absolute positioning measurement + if ($needs_reposition) { + $orig_style = $this->_frame->get_original_style(); + if ($orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto")) { + $width = 0; + foreach ($this->_frame->get_line_boxes() as $line) { + $width = max($line->w, $width); + } + $style->width = $width; + } + + $style->left = $orig_style->left; + $style->right = $orig_style->right; + } + + $this->_text_align(); + $this->vertical_align(); + + // Absolute positioning + if ($needs_reposition) { + list($x, $y) = $this->_frame->get_position(); + $this->_frame->position(); + list($new_x, $new_y) = $this->_frame->get_position(); + $this->_frame->move($new_x - $x, $new_y - $y, true); + } + + if ($block && $this->_frame->is_in_flow()) { + $block->add_frame_to_line($this->_frame); + + // May be inline-block + if ($style->display === "block") { + $block->add_line(); + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Image.php b/vendor/dompdf/dompdf/src/FrameReflower/Image.php new file mode 100644 index 000000000..c59814d5c --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Image.php @@ -0,0 +1,195 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\Helpers; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Image as ImageFrameDecorator; + +/** + * Image reflower class + * + * @package dompdf + */ +class Image extends AbstractFrameReflower +{ + + function __construct(ImageFrameDecorator $frame) + { + parent::__construct($frame); + } + + function reflow(BlockFrameDecorator $block = null) + { + $this->_frame->position(); + + //FLOAT + //$frame = $this->_frame; + //$page = $frame->get_root(); + + //if ($frame->get_style()->float !== "none" ) { + // $page->add_floating_frame($this); + //} + + // Set the frame's width + $this->get_min_max_width(); + + if ($block) { + $block->add_frame_to_line($this->_frame); + } + } + + function get_min_max_width() + { + if ($this->get_dompdf()->get_option("debugPng")) { + // Determine the image's size. Time consuming. Only when really needed? + list($img_width, $img_height) = Helpers::dompdf_getimagesize($this->_frame->get_image_url(), $this->get_dompdf()->getHttpContext()); + print "get_min_max_width() " . + $this->_frame->get_style()->width . ' ' . + $this->_frame->get_style()->height . ';' . + $this->_frame->get_parent()->get_style()->width . " " . + $this->_frame->get_parent()->get_style()->height . ";" . + $this->_frame->get_parent()->get_parent()->get_style()->width . ' ' . + $this->_frame->get_parent()->get_parent()->get_style()->height . ';' . + $img_width . ' ' . + $img_height . '|'; + } + + $style = $this->_frame->get_style(); + + $width_forced = true; + $height_forced = true; + + //own style auto or invalid value: use natural size in px + //own style value: ignore suffix text including unit, use given number as px + //own style %: walk up parent chain until found available space in pt; fill available space + // + //special ignored unit: e.g. 10ex: e treated as exponent; x ignored; 10e completely invalid ->like auto + + $width = ($style->width > 0 ? $style->width : 0); + if (Helpers::is_percent($width)) { + $t = 0.0; + for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) { + $f_style = $f->get_style(); + $t = $f_style->length_in_pt($f_style->width); + if ($t != 0) { + break; + } + } + $width = ((float)rtrim($width, "%") * $t) / 100; //maybe 0 + } elseif (!mb_strpos($width, 'pt')) { + // Don't set image original size if "%" branch was 0 or size not given. + // Otherwise aspect changed on %/auto combination for width/height + // Resample according to px per inch + // See also ListBulletImage::__construct + $width = $style->length_in_pt($width); + } + + $height = ($style->height > 0 ? $style->height : 0); + if (Helpers::is_percent($height)) { + $t = 0.0; + for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) { + $f_style = $f->get_style(); + $t = $f_style->length_in_pt($f_style->height); + if ($t != 0) { + break; + } + } + $height = ((float)rtrim($height, "%") * $t) / 100; //maybe 0 + } elseif (!mb_strpos($height, 'pt')) { + // Don't set image original size if "%" branch was 0 or size not given. + // Otherwise aspect changed on %/auto combination for width/height + // Resample according to px per inch + // See also ListBulletImage::__construct + $height = $style->length_in_pt($height); + } + + if ($width == 0 || $height == 0) { + // Determine the image's size. Time consuming. Only when really needed! + list($img_width, $img_height) = Helpers::dompdf_getimagesize($this->_frame->get_image_url(), $this->get_dompdf()->getHttpContext()); + + // don't treat 0 as error. Can be downscaled or can be catched elsewhere if image not readable. + // Resample according to px per inch + // See also ListBulletImage::__construct + if ($width == 0 && $height == 0) { + $dpi = $this->_frame->get_dompdf()->get_option("dpi"); + $width = (float)($img_width * 72) / $dpi; + $height = (float)($img_height * 72) / $dpi; + $width_forced = false; + $height_forced = false; + } elseif ($height == 0 && $width != 0) { + $height_forced = false; + $height = ($width / $img_width) * $img_height; //keep aspect ratio + } elseif ($width == 0 && $height != 0) { + $width_forced = false; + $width = ($height / $img_height) * $img_width; //keep aspect ratio + } + } + + // Handle min/max width/height + if ($style->min_width !== "none" || + $style->max_width !== "none" || + $style->min_height !== "none" || + $style->max_height !== "none" + ) { + + list( /*$x*/, /*$y*/, $w, $h) = $this->_frame->get_containing_block(); + + $min_width = $style->length_in_pt($style->min_width, $w); + $max_width = $style->length_in_pt($style->max_width, $w); + $min_height = $style->length_in_pt($style->min_height, $h); + $max_height = $style->length_in_pt($style->max_height, $h); + + if ($max_width !== "none" && $width > $max_width) { + if (!$height_forced) { + $height *= $max_width / $width; + } + + $width = $max_width; + } + + if ($min_width !== "none" && $width < $min_width) { + if (!$height_forced) { + $height *= $min_width / $width; + } + + $width = $min_width; + } + + if ($max_height !== "none" && $height > $max_height) { + if (!$width_forced) { + $width *= $max_height / $height; + } + + $height = $max_height; + } + + if ($min_height !== "none" && $height < $min_height) { + if (!$width_forced) { + $width *= $min_height / $height; + } + + $height = $min_height; + } + } + + if ($this->get_dompdf()->get_option("debugPng")) print $width . ' ' . $height . ';'; + + $style->width = $width . "pt"; + $style->height = $height . "pt"; + + $style->min_width = "none"; + $style->max_width = "none"; + $style->min_height = "none"; + $style->max_height = "none"; + + return array($width, $width, "min" => $width, "max" => $width); + + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Inline.php b/vendor/dompdf/dompdf/src/FrameReflower/Inline.php new file mode 100644 index 000000000..1f05fa9ef --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Inline.php @@ -0,0 +1,76 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Text as TextFrameDecorator; + +/** + * Reflows inline frames + * + * @package dompdf + */ +class Inline extends AbstractFrameReflower +{ + + function __construct(Frame $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function reflow(BlockFrameDecorator $block = null) + { + $frame = $this->_frame; + + // Check if a page break is forced + $page = $frame->get_root(); + $page->check_forced_page_break($frame); + + if ($page->is_full()) { + return; + } + + $style = $frame->get_style(); + + // Generated content + $this->_set_content(); + + $frame->position(); + + $cb = $frame->get_containing_block(); + + // Add our margin, padding & border to the first and last children + if (($f = $frame->get_first_child()) && $f instanceof TextFrameDecorator) { + $f_style = $f->get_style(); + $f_style->margin_left = $style->margin_left; + $f_style->padding_left = $style->padding_left; + $f_style->border_left = $style->border_left; + } + + if (($l = $frame->get_last_child()) && $l instanceof TextFrameDecorator) { + $l_style = $l->get_style(); + $l_style->margin_right = $style->margin_right; + $l_style->padding_right = $style->padding_right; + $l_style->border_right = $style->border_right; + } + + if ($block) { + $block->add_frame_to_line($this->_frame); + } + + // Set the containing blocks and reflow each child. The containing + // block is not changed by line boxes. + foreach ($frame->get_children() as $child) { + $child->set_containing_block($cb); + $child->reflow($block); + } + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php b/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php new file mode 100644 index 000000000..553195db5 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/ListBullet.php @@ -0,0 +1,41 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Reflows list bullets + * + * @package dompdf + */ +class ListBullet extends AbstractFrameReflower +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function reflow(BlockFrameDecorator $block = null) + { + $style = $this->_frame->get_style(); + + $style->width = $this->_frame->get_width(); + $this->_frame->position(); + + if ($style->list_style_position === "inside") { + $p = $this->_frame->find_block_parent(); + $p->add_frame_to_line($this->_frame); + } + + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php b/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php new file mode 100644 index 000000000..1f9d2e2c0 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/NullFrameReflower.php @@ -0,0 +1,32 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\FrameReflower; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; + +/** + * Dummy reflower + * + * @package dompdf + */ +class NullFrameReflower extends AbstractFrameReflower +{ + + function __construct(Frame $frame) + { + parent::__construct($frame); + } + + function reflow(BlockFrameDecorator $block = null) + { + return; + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Page.php b/vendor/dompdf/dompdf/src/FrameReflower/Page.php new file mode 100644 index 000000000..770eb6c83 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Page.php @@ -0,0 +1,199 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Page as PageFrameDecorator; + +/** + * Reflows pages + * + * @package dompdf + */ +class Page extends AbstractFrameReflower +{ + + /** + * Cache of the callbacks array + * + * @var array + */ + private $_callbacks; + + /** + * Cache of the canvas + * + * @var \Dompdf\Canvas + */ + private $_canvas; + + function __construct(PageFrameDecorator $frame) + { + parent::__construct($frame); + } + + function apply_page_style(Frame $frame, $page_number) + { + $style = $frame->get_style(); + $page_styles = $style->get_stylesheet()->get_page_styles(); + + // http://www.w3.org/TR/CSS21/page.html#page-selectors + if (count($page_styles) > 1) { + $odd = $page_number % 2 == 1; + $first = $page_number == 1; + + $style = clone $page_styles["base"]; + + // FIXME RTL + if ($odd && isset($page_styles[":right"])) { + $style->merge($page_styles[":right"]); + } + + if ($odd && isset($page_styles[":odd"])) { + $style->merge($page_styles[":odd"]); + } + + // FIXME RTL + if (!$odd && isset($page_styles[":left"])) { + $style->merge($page_styles[":left"]); + } + + if (!$odd && isset($page_styles[":even"])) { + $style->merge($page_styles[":even"]); + } + + if ($first && isset($page_styles[":first"])) { + $style->merge($page_styles[":first"]); + } + + $frame->set_style($style); + } + } + + //........................................................................ + + /** + * Paged layout: + * http://www.w3.org/TR/CSS21/page.html + */ + function reflow(BlockFrameDecorator $block = null) + { + $fixed_children = array(); + $prev_child = null; + $child = $this->_frame->get_first_child(); + $current_page = 0; + + while ($child) { + $this->apply_page_style($this->_frame, $current_page + 1); + + $style = $this->_frame->get_style(); + + // Pages are only concerned with margins + $cb = $this->_frame->get_containing_block(); + $left = $style->length_in_pt($style->margin_left, $cb["w"]); + $right = $style->length_in_pt($style->margin_right, $cb["w"]); + $top = $style->length_in_pt($style->margin_top, $cb["h"]); + $bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]); + + $content_x = $cb["x"] + $left; + $content_y = $cb["y"] + $top; + $content_width = $cb["w"] - $left - $right; + $content_height = $cb["h"] - $top - $bottom; + + // Only if it's the first page, we save the nodes with a fixed position + if ($current_page == 0) { + $children = $child->get_children(); + foreach ($children as $onechild) { + if ($onechild->get_style()->position === "fixed") { + $fixed_children[] = $onechild->deep_copy(); + } + } + $fixed_children = array_reverse($fixed_children); + } + + $child->set_containing_block($content_x, $content_y, $content_width, $content_height); + + // Check for begin reflow callback + $this->_check_callbacks("begin_page_reflow", $child); + + //Insert a copy of each node which have a fixed position + if ($current_page >= 1) { + foreach ($fixed_children as $fixed_child) { + $child->insert_child_before($fixed_child->deep_copy(), $child->get_first_child()); + } + } + + $child->reflow(); + $next_child = $child->get_next_sibling(); + + // Check for begin render callback + $this->_check_callbacks("begin_page_render", $child); + + // Render the page + $this->_frame->get_renderer()->render($child); + + // Check for end render callback + $this->_check_callbacks("end_page_render", $child); + + if ($next_child) { + $this->_frame->next_page(); + } + + // Wait to dispose of all frames on the previous page + // so callback will have access to them + if ($prev_child) { + $prev_child->dispose(true); + } + $prev_child = $child; + $child = $next_child; + $current_page++; + } + + // Dispose of previous page if it still exists + if ($prev_child) { + $prev_child->dispose(true); + } + } + + //........................................................................ + + /** + * Check for callbacks that need to be performed when a given event + * gets triggered on a page + * + * @param string $event the type of event + * @param Frame $frame the frame that event is triggered on + */ + protected function _check_callbacks($event, $frame) + { + if (!isset($this->_callbacks)) { + $dompdf = $this->_frame->get_dompdf(); + $this->_callbacks = $dompdf->get_callbacks(); + $this->_canvas = $dompdf->get_canvas(); + } + + if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) { + $info = array( + 0 => $this->_canvas, "canvas" => $this->_canvas, + 1 => $frame, "frame" => $frame, + ); + $fs = $this->_callbacks[$event]; + foreach ($fs as $f) { + if (is_callable($f)) { + if (is_array($f)) { + $f[0]->{$f[1]}($info); + } else { + $f($info); + } + } + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Table.php b/vendor/dompdf/dompdf/src/FrameReflower/Table.php new file mode 100644 index 000000000..a3626d8c7 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Table.php @@ -0,0 +1,587 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Table as TableFrameDecorator; + +/** + * Reflows tables + * + * @access private + * @package dompdf + */ +class Table extends AbstractFrameReflower +{ + /** + * Frame for this reflower + * + * @var TableFrameDecorator + */ + protected $_frame; + + /** + * Cache of results between call to get_min_max_width and assign_widths + * + * @var array + */ + protected $_state; + + function __construct(TableFrameDecorator $frame) + { + $this->_state = null; + parent::__construct($frame); + } + + /** + * State is held here so it needs to be reset along with the decorator + */ + function reset() + { + $this->_state = null; + $this->_min_max_cache = null; + } + + //........................................................................ + + protected function _assign_widths() + { + $style = $this->_frame->get_style(); + + // Find the min/max width of the table and sort the columns into + // absolute/percent/auto arrays + $min_width = $this->_state["min_width"]; + $max_width = $this->_state["max_width"]; + $percent_used = $this->_state["percent_used"]; + $absolute_used = $this->_state["absolute_used"]; + $auto_min = $this->_state["auto_min"]; + + $absolute =& $this->_state["absolute"]; + $percent =& $this->_state["percent"]; + $auto =& $this->_state["auto"]; + + // Determine the actual width of the table + $cb = $this->_frame->get_containing_block(); + $columns =& $this->_frame->get_cellmap()->get_columns(); + + $width = $style->width; + + // Calculate padding & border fudge factor + $left = $style->margin_left; + $right = $style->margin_right; + + $centered = ($left === "auto" && $right === "auto"); + + $left = $left === "auto" ? 0 : $style->length_in_pt($left, $cb["w"]); + $right = $right === "auto" ? 0 : $style->length_in_pt($right, $cb["w"]); + + $delta = $left + $right; + + if (!$centered) { + $delta += $style->length_in_pt(array( + $style->padding_left, + $style->border_left_width, + $style->border_right_width, + $style->padding_right), + $cb["w"]); + } + + $min_table_width = $style->length_in_pt($style->min_width, $cb["w"] - $delta); + + // min & max widths already include borders & padding + $min_width -= $delta; + $max_width -= $delta; + + if ($width !== "auto") { + + $preferred_width = $style->length_in_pt($width, $cb["w"]) - $delta; + + if ($preferred_width < $min_table_width) + $preferred_width = $min_table_width; + + if ($preferred_width > $min_width) + $width = $preferred_width; + else + $width = $min_width; + + } else { + + if ($max_width + $delta < $cb["w"]) + $width = $max_width; + else if ($cb["w"] - $delta > $min_width) + $width = $cb["w"] - $delta; + else + $width = $min_width; + + if ($width < $min_table_width) + $width = $min_table_width; + + } + + // Store our resolved width + $style->width = $width; + + $cellmap = $this->_frame->get_cellmap(); + + if ($cellmap->is_columns_locked()) { + return; + } + + // If the whole table fits on the page, then assign each column it's max width + if ($width == $max_width) { + + foreach (array_keys($columns) as $i) + $cellmap->set_column_width($i, $columns[$i]["max-width"]); + + return; + } + + // Determine leftover and assign it evenly to all columns + if ($width > $min_width) { + + // We have four cases to deal with: + // + // 1. All columns are auto--no widths have been specified. In this + // case we distribute extra space across all columns weighted by max-width. + // + // 2. Only absolute widths have been specified. In this case we + // distribute any extra space equally among 'width: auto' columns, or all + // columns if no auto columns have been specified. + // + // 3. Only percentage widths have been specified. In this case we + // normalize the percentage values and distribute any remaining % to + // width: auto columns. We then proceed to assign widths as fractions + // of the table width. + // + // 4. Both absolute and percentage widths have been specified. + + $increment = 0; + + // Case 1: + if ($absolute_used == 0 && $percent_used == 0) { + $increment = $width - $min_width; + + foreach (array_keys($columns) as $i) { + $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment * ($columns[$i]["max-width"] / $max_width)); + } + return; + } + + + // Case 2 + if ($absolute_used > 0 && $percent_used == 0) { + + if (count($auto) > 0) + $increment = ($width - $auto_min - $absolute_used) / count($auto); + + // Use the absolutely specified width or the increment + foreach (array_keys($columns) as $i) { + + if ($columns[$i]["absolute"] > 0 && count($auto)) + $cellmap->set_column_width($i, $columns[$i]["min-width"]); + else if (count($auto)) + $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment); + else { + // All absolute columns + $increment = ($width - $absolute_used) * $columns[$i]["absolute"] / $absolute_used; + + $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment); + } + + } + return; + } + + + // Case 3: + if ($absolute_used == 0 && $percent_used > 0) { + + $scale = null; + $remaining = null; + + // Scale percent values if the total percentage is > 100, or if all + // values are specified as percentages. + if ($percent_used > 100 || count($auto) == 0) + $scale = 100 / $percent_used; + else + $scale = 1; + + // Account for the minimum space used by the unassigned auto columns + $used_width = $auto_min; + + foreach ($percent as $i) { + $columns[$i]["percent"] *= $scale; + + $slack = $width - $used_width; + + $w = min($columns[$i]["percent"] * $width / 100, $slack); + + if ($w < $columns[$i]["min-width"]) + $w = $columns[$i]["min-width"]; + + $cellmap->set_column_width($i, $w); + $used_width += $w; + + } + + // This works because $used_width includes the min-width of each + // unassigned column + if (count($auto) > 0) { + $increment = ($width - $used_width) / count($auto); + + foreach ($auto as $i) + $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment); + + } + return; + } + + // Case 4: + + // First-come, first served + if ($absolute_used > 0 && $percent_used > 0) { + + $used_width = $auto_min; + + foreach ($absolute as $i) { + $cellmap->set_column_width($i, $columns[$i]["min-width"]); + $used_width += $columns[$i]["min-width"]; + } + + // Scale percent values if the total percentage is > 100 or there + // are no auto values to take up slack + if ($percent_used > 100 || count($auto) == 0) + $scale = 100 / $percent_used; + else + $scale = 1; + + $remaining_width = $width - $used_width; + + foreach ($percent as $i) { + $slack = $remaining_width - $used_width; + + $columns[$i]["percent"] *= $scale; + $w = min($columns[$i]["percent"] * $remaining_width / 100, $slack); + + if ($w < $columns[$i]["min-width"]) + $w = $columns[$i]["min-width"]; + + $columns[$i]["used-width"] = $w; + $used_width += $w; + } + + if (count($auto) > 0) { + $increment = ($width - $used_width) / count($auto); + + foreach ($auto as $i) + $cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment); + + } + + return; + } + + + } else { // we are over constrained + + // Each column gets its minimum width + foreach (array_keys($columns) as $i) + $cellmap->set_column_width($i, $columns[$i]["min-width"]); + + } + } + + //........................................................................ + + // Determine the frame's height based on min/max height + protected function _calculate_height() + { + + $style = $this->_frame->get_style(); + $height = $style->height; + + $cellmap = $this->_frame->get_cellmap(); + $cellmap->assign_frame_heights(); + $rows = $cellmap->get_rows(); + + // Determine our content height + $content_height = 0; + foreach ($rows as $r) + $content_height += $r["height"]; + + $cb = $this->_frame->get_containing_block(); + + if (!($style->overflow === "visible" || + ($style->overflow === "hidden" && $height === "auto")) + ) { + + // Only handle min/max height if the height is independent of the frame's content + + $min_height = $style->min_height; + $max_height = $style->max_height; + + if (isset($cb["h"])) { + $min_height = $style->length_in_pt($min_height, $cb["h"]); + $max_height = $style->length_in_pt($max_height, $cb["h"]); + + } else if (isset($cb["w"])) { + + if (mb_strpos($min_height, "%") !== false) + $min_height = 0; + else + $min_height = $style->length_in_pt($min_height, $cb["w"]); + + if (mb_strpos($max_height, "%") !== false) + $max_height = "none"; + else + $max_height = $style->length_in_pt($max_height, $cb["w"]); + } + + if ($max_height !== "none" && $min_height > $max_height) + // Swap 'em + list($max_height, $min_height) = array($min_height, $max_height); + + if ($max_height !== "none" && $height > $max_height) + $height = $max_height; + + if ($height < $min_height) + $height = $min_height; + + } else { + + // Use the content height or the height value, whichever is greater + if ($height !== "auto") { + $height = $style->length_in_pt($height, $cb["h"]); + + if ($height <= $content_height) + $height = $content_height; + else + $cellmap->set_frame_heights($height, $content_height); + + } else + $height = $content_height; + + } + + return $height; + + } + //........................................................................ + + /** + * @param BlockFrameDecorator $block + */ + function reflow(BlockFrameDecorator $block = null) + { + /** @var TableFrameDecorator */ + $frame = $this->_frame; + + // Check if a page break is forced + $page = $frame->get_root(); + $page->check_forced_page_break($frame); + + // Bail if the page is full + if ($page->is_full()) + return; + + // Let the page know that we're reflowing a table so that splits + // are suppressed (simply setting page-break-inside: avoid won't + // work because we may have an arbitrary number of block elements + // inside tds.) + $page->table_reflow_start(); + + // Collapse vertical margins, if required + $this->_collapse_margins(); + + $frame->position(); + + // Table layout algorithm: + // http://www.w3.org/TR/CSS21/tables.html#auto-table-layout + + if (is_null($this->_state)) + $this->get_min_max_width(); + + $cb = $frame->get_containing_block(); + $style = $frame->get_style(); + + // This is slightly inexact, but should be okay. Add half the + // border-spacing to the table as padding. The other half is added to + // the cells themselves. + if ($style->border_collapse === "separate") { + list($h, $v) = $style->border_spacing; + + $v = $style->length_in_pt($v) / 2; + $h = $style->length_in_pt($h) / 2; + + $style->padding_left = $style->length_in_pt($style->padding_left, $cb["w"]) + $h; + $style->padding_right = $style->length_in_pt($style->padding_right, $cb["w"]) + $h; + $style->padding_top = $style->length_in_pt($style->padding_top, $cb["h"]) + $v; + $style->padding_bottom = $style->length_in_pt($style->padding_bottom, $cb["h"]) + $v; + + } + + $this->_assign_widths(); + + // Adjust left & right margins, if they are auto + $width = $style->width; + $left = $style->margin_left; + $right = $style->margin_right; + + $diff = $cb["w"] - $width; + + if ($left === "auto" && $right === "auto") { + if ($diff < 0) { + $left = 0; + $right = $diff; + } else { + $left = $right = $diff / 2; + } + + $style->margin_left = "$left pt"; + $style->margin_right = "$right pt"; + + } else { + if ($left === "auto") { + $left = $style->length_in_pt($cb["w"] - $right - $width, $cb["w"]); + } + if ($right === "auto") { + $left = $style->length_in_pt($left, $cb["w"]); + } + } + + list($x, $y) = $frame->get_position(); + + // Determine the content edge + $content_x = $x + $left + $style->length_in_pt(array($style->padding_left, + $style->border_left_width), $cb["w"]); + $content_y = $y + $style->length_in_pt(array($style->margin_top, + $style->border_top_width, + $style->padding_top), $cb["h"]); + + if (isset($cb["h"])) + $h = $cb["h"]; + else + $h = null; + + $cellmap = $frame->get_cellmap(); + $col =& $cellmap->get_column(0); + $col["x"] = $content_x; + + $row =& $cellmap->get_row(0); + $row["y"] = $content_y; + + $cellmap->assign_x_positions(); + + // Set the containing block of each child & reflow + foreach ($frame->get_children() as $child) { + + // Bail if the page is full + if (!$page->in_nested_table() && $page->is_full()) + break; + + $child->set_containing_block($content_x, $content_y, $width, $h); + $child->reflow(); + + if (!$page->in_nested_table()) + // Check if a split has occured + $page->check_page_break($child); + + } + + // Assign heights to our cells: + $style->height = $this->_calculate_height(); + + if ($style->border_collapse === "collapse") { + // Unset our borders because our cells are now using them + $style->border_style = "none"; + } + + $page->table_reflow_end(); + + // Debugging: + //echo ($this->_frame->get_cellmap()); + + if ($block && $style->float === "none" && $frame->is_in_flow()) { + $block->add_frame_to_line($frame); + $block->add_line(); + } + } + + //........................................................................ + + function get_min_max_width() + { + + if (!is_null($this->_min_max_cache)) + return $this->_min_max_cache; + + $style = $this->_frame->get_style(); + + $this->_frame->normalise(); + + // Add the cells to the cellmap (this will calcluate column widths as + // frames are added) + $this->_frame->get_cellmap()->add_frame($this->_frame); + + // Find the min/max width of the table and sort the columns into + // absolute/percent/auto arrays + $this->_state = array(); + $this->_state["min_width"] = 0; + $this->_state["max_width"] = 0; + + $this->_state["percent_used"] = 0; + $this->_state["absolute_used"] = 0; + $this->_state["auto_min"] = 0; + + $this->_state["absolute"] = array(); + $this->_state["percent"] = array(); + $this->_state["auto"] = array(); + + $columns =& $this->_frame->get_cellmap()->get_columns(); + foreach (array_keys($columns) as $i) { + $this->_state["min_width"] += $columns[$i]["min-width"]; + $this->_state["max_width"] += $columns[$i]["max-width"]; + + if ($columns[$i]["absolute"] > 0) { + $this->_state["absolute"][] = $i; + $this->_state["absolute_used"] += $columns[$i]["absolute"]; + + } else if ($columns[$i]["percent"] > 0) { + $this->_state["percent"][] = $i; + $this->_state["percent_used"] += $columns[$i]["percent"]; + + } else { + $this->_state["auto"][] = $i; + $this->_state["auto_min"] += $columns[$i]["min-width"]; + } + } + + // Account for margins & padding + $dims = array($style->border_left_width, + $style->border_right_width, + $style->padding_left, + $style->padding_right, + $style->margin_left, + $style->margin_right); + + if ($style->border_collapse !== "collapse") + list($dims[]) = $style->border_spacing; + + $delta = $style->length_in_pt($dims, $this->_frame->get_containing_block("w")); + + $this->_state["min_width"] += $delta; + $this->_state["max_width"] += $delta; + + return $this->_min_max_cache = array( + $this->_state["min_width"], + $this->_state["max_width"], + "min" => $this->_state["min_width"], + "max" => $this->_state["max_width"], + ); + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php b/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php new file mode 100644 index 000000000..0dc74a1f3 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/TableCell.php @@ -0,0 +1,120 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Table as TableFrameDecorator; + +/** + * Reflows table cells + * + * @package dompdf + */ +class TableCell extends Block +{ + function __construct(BlockFrameDecorator $frame) + { + parent::__construct($frame); + } + + function reflow(BlockFrameDecorator $block = null) + { + + $style = $this->_frame->get_style(); + + $table = TableFrameDecorator::find_parent_table($this->_frame); + $cellmap = $table->get_cellmap(); + + list($x, $y) = $cellmap->get_frame_position($this->_frame); + $this->_frame->set_position($x, $y); + + $cells = $cellmap->get_spanned_cells($this->_frame); + + $w = 0; + foreach ($cells["columns"] as $i) { + $col = $cellmap->get_column($i); + $w += $col["used-width"]; + } + + //FIXME? + $h = $this->_frame->get_containing_block("h"); + + $left_space = $style->length_in_pt(array($style->margin_left, + $style->padding_left, + $style->border_left_width), + $w); + + $right_space = $style->length_in_pt(array($style->padding_right, + $style->margin_right, + $style->border_right_width), + $w); + + $top_space = $style->length_in_pt(array($style->margin_top, + $style->padding_top, + $style->border_top_width), + $h); + $bottom_space = $style->length_in_pt(array($style->margin_bottom, + $style->padding_bottom, + $style->border_bottom_width), + $h); + + $style->width = $cb_w = $w - $left_space - $right_space; + + $content_x = $x + $left_space; + $content_y = $line_y = $y + $top_space; + + // Adjust the first line based on the text-indent property + $indent = $style->length_in_pt($style->text_indent, $w); + $this->_frame->increase_line_width($indent); + + $page = $this->_frame->get_root(); + + // Set the y position of the first line in the cell + $line_box = $this->_frame->get_current_line_box(); + $line_box->y = $line_y; + + // Set the containing blocks and reflow each child + foreach ($this->_frame->get_children() as $child) { + + if ($page->is_full()) + break; + + $child->set_containing_block($content_x, $content_y, $cb_w, $h); + + $this->process_clear($child); + + $child->reflow($this->_frame); + + $this->process_float($child, $x + $left_space, $w - $right_space - $left_space); + } + + // Determine our height + $style_height = $style->length_in_pt($style->height, $h); + + $this->_frame->set_content_height($this->_calculate_content_height()); + + $height = max($style_height, $this->_frame->get_content_height()); + + // Let the cellmap know our height + $cell_height = $height / count($cells["rows"]); + + if ($style_height <= $height) + $cell_height += $top_space + $bottom_space; + + foreach ($cells["rows"] as $i) + $cellmap->set_row_height($i, $cell_height); + + $style->height = $height; + + $this->_text_align(); + + $this->vertical_align(); + + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php b/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php new file mode 100644 index 000000000..7f2de4cff --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/TableRow.php @@ -0,0 +1,68 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Table as TableFrameDecorator; +use Dompdf\FrameDecorator\TableRow as TableRowFrameDecorator; +use Dompdf\Exception; + +/** + * Reflows table rows + * + * @package dompdf + */ +class TableRow extends AbstractFrameReflower +{ + function __construct(TableRowFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function reflow(BlockFrameDecorator $block = null) + { + $page = $this->_frame->get_root(); + + if ($page->is_full()) + return; + + $this->_frame->position(); + $style = $this->_frame->get_style(); + $cb = $this->_frame->get_containing_block(); + + foreach ($this->_frame->get_children() as $child) { + + if ($page->is_full()) + return; + + $child->set_containing_block($cb); + $child->reflow(); + + } + + if ($page->is_full()) + return; + + $table = TableFrameDecorator::find_parent_table($this->_frame); + $cellmap = $table->get_cellmap(); + $style->width = $cellmap->get_frame_width($this->_frame); + $style->height = $cellmap->get_frame_height($this->_frame); + + $this->_frame->set_position($cellmap->get_frame_position($this->_frame)); + + } + + //........................................................................ + + function get_min_max_width() + { + throw new Exception("Min/max width is undefined for table rows"); + } +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php b/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php new file mode 100644 index 000000000..eb13dd599 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/TableRowGroup.php @@ -0,0 +1,65 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Table as TableFrameDecorator; + +/** + * Reflows table row groups (e.g. tbody tags) + * + * @package dompdf + */ +class TableRowGroup extends AbstractFrameReflower +{ + + function __construct($frame) + { + parent::__construct($frame); + } + + function reflow(BlockFrameDecorator $block = null) + { + $page = $this->_frame->get_root(); + + $style = $this->_frame->get_style(); + + // Our width is equal to the width of our parent table + $table = TableFrameDecorator::find_parent_table($this->_frame); + + $cb = $this->_frame->get_containing_block(); + + foreach ($this->_frame->get_children() as $child) { + // Bail if the page is full + if ($page->is_full()) + return; + + $child->set_containing_block($cb["x"], $cb["y"], $cb["w"], $cb["h"]); + $child->reflow(); + + // Check if a split has occured + $page->check_page_break($child); + + } + + if ($page->is_full()) + return; + + $cellmap = $table->get_cellmap(); + $style->width = $cellmap->get_frame_width($this->_frame); + $style->height = $cellmap->get_frame_height($this->_frame); + + $this->_frame->set_position($cellmap->get_frame_position($this->_frame)); + + if ($table->get_style()->border_collapse === "collapse") + // Unset our borders because our cells are now using them + $style->border_style = "none"; + + } + +} diff --git a/vendor/dompdf/dompdf/src/FrameReflower/Text.php b/vendor/dompdf/dompdf/src/FrameReflower/Text.php new file mode 100644 index 000000000..950f7fae9 --- /dev/null +++ b/vendor/dompdf/dompdf/src/FrameReflower/Text.php @@ -0,0 +1,487 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\FrameReflower; + +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\FrameDecorator\Text as TextFrameDecorator; +use Dompdf\FontMetrics; + +/** + * Reflows text frames. + * + * @package dompdf + */ +class Text extends AbstractFrameReflower +{ + + /** + * @var BlockFrameDecorator + */ + protected $_block_parent; // Nearest block-level ancestor + + /** + * @var TextFrameDecorator + */ + protected $_frame; + + public static $_whitespace_pattern = "/[ \t\r\n\f]+/u"; + + /** + * @var FontMetrics + */ + private $fontMetrics; + + /** + * @param TextFrameDecorator $frame + * @param FontMetrics $fontMetrics + */ + public function __construct(TextFrameDecorator $frame, FontMetrics $fontMetrics) + { + parent::__construct($frame); + $this->setFontMetrics($fontMetrics); + } + + //........................................................................ + + protected function _collapse_white_space($text) + { + //$text = $this->_frame->get_text(); +// if ( $this->_block_parent->get_current_line_box->w == 0 ) +// $text = ltrim($text, " \n\r\t"); + return preg_replace(self::$_whitespace_pattern, " ", $text); + } + + //........................................................................ + + protected function _line_break($text) + { + $style = $this->_frame->get_style(); + $size = $style->font_size; + $font = $style->font_family; + $current_line = $this->_block_parent->get_current_line_box(); + + // Determine the available width + $line_width = $this->_frame->get_containing_block("w"); + $current_line_width = $current_line->left + $current_line->w + $current_line->right; + + $available_width = $line_width - $current_line_width; + + // Account for word-spacing + $word_spacing = $style->length_in_pt($style->word_spacing); + $char_spacing = $style->length_in_pt($style->letter_spacing); + + // Determine the frame width including margin, padding & border + $text_width = $this->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing); + $mbp_width = + $style->length_in_pt(array($style->margin_left, + $style->border_left_width, + $style->padding_left, + $style->padding_right, + $style->border_right_width, + $style->margin_right), $line_width); + + $frame_width = $text_width + $mbp_width; + +// Debugging: +// Helpers::pre_r("Text: '" . htmlspecialchars($text). "'"); +// Helpers::pre_r("width: " .$frame_width); +// Helpers::pre_r("textwidth + delta: $text_width + $mbp_width"); +// Helpers::pre_r("font-size: $size"); +// Helpers::pre_r("cb[w]: " .$line_width); +// Helpers::pre_r("available width: " . $available_width); +// Helpers::pre_r("current line width: " . $current_line_width); + +// Helpers::pre_r($words); + + if ($frame_width <= $available_width) + return false; + + // split the text into words + $words = preg_split('/([\s-]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE); + $wc = count($words); + + // Determine the split point + $width = 0; + $str = ""; + reset($words); + + // @todo support , + for ($i = 0; $i < $wc; $i += 2) { + $word = $words[$i] . (isset($words[$i + 1]) ? $words[$i + 1] : ""); + $word_width = $this->getFontMetrics()->getTextWidth($word, $font, $size, $word_spacing, $char_spacing); + if ($width + $word_width + $mbp_width > $available_width) + break; + + $width += $word_width; + $str .= $word; + } + + $break_word = ($style->word_wrap === "break-word"); + + // The first word has overflowed. Force it onto the line + if ($current_line_width == 0 && $width == 0) { + + $s = ""; + $last_width = 0; + + if ($break_word) { + for ($j = 0; $j < strlen($word); $j++) { + $s .= $word[$j]; + $_width = $this->getFontMetrics()->getTextWidth($s, $font, $size, $word_spacing, $char_spacing); + if ($_width > $available_width) { + break; + } + + $last_width = $_width; + } + } + + if ($break_word && $last_width > 0) { + $width += $last_width; + $str .= substr($s, 0, -1); + } else { + $width += $word_width; + $str .= $word; + } + } + + $offset = mb_strlen($str); + +// More debugging: +// var_dump($str); +// print_r("Width: ". $width); +// print_r("Offset: " . $offset); + + return $offset; + + } + + //........................................................................ + + protected function _newline_break($text) + { + + if (($i = mb_strpos($text, "\n")) === false) + return false; + + return $i + 1; + + } + + //........................................................................ + + protected function _layout_line() + { + $frame = $this->_frame; + $style = $frame->get_style(); + $text = $frame->get_text(); + $size = $style->font_size; + $font = $style->font_family; + + // Determine the text height + $style->height = $this->getFontMetrics()->getFontHeight($font, $size); + + $split = false; + $add_line = false; + + // Handle text transform: + // http://www.w3.org/TR/CSS21/text.html#propdef-text-transform + switch (strtolower($style->text_transform)) { + default: + break; + case "capitalize": + $text = mb_convert_case($text, MB_CASE_TITLE); + break; + case "uppercase": + $text = mb_convert_case($text, MB_CASE_UPPER); + break; + case "lowercase": + $text = mb_convert_case($text, MB_CASE_LOWER); + break; + } + + // Handle white-space property: + // http://www.w3.org/TR/CSS21/text.html#propdef-white-space + switch ($style->white_space) { + + default: + case "normal": + $frame->set_text($text = $this->_collapse_white_space($text)); + if ($text == "") + break; + + $split = $this->_line_break($text); + break; + + case "pre": + $split = $this->_newline_break($text); + $add_line = $split !== false; + break; + + case "nowrap": + $frame->set_text($text = $this->_collapse_white_space($text)); + break; + + case "pre-wrap": + $split = $this->_newline_break($text); + + if (($tmp = $this->_line_break($text)) !== false) { + $add_line = $split < $tmp; + $split = min($tmp, $split); + } else + $add_line = true; + + break; + + case "pre-line": + // Collapse white-space except for \n + $frame->set_text($text = preg_replace("/[ \t]+/u", " ", $text)); + + if ($text == "") + break; + + $split = $this->_newline_break($text); + + if (($tmp = $this->_line_break($text)) !== false) { + $add_line = $split < $tmp; + $split = min($tmp, $split); + } else + $add_line = true; + + break; + + } + + // Handle degenerate case + if ($text === "") + return; + + if ($split !== false) { + + // Handle edge cases + if ($split == 0 && $text === " ") { + $frame->set_text(""); + return; + } + + if ($split == 0) { + + // Trim newlines from the beginning of the line + //$this->_frame->set_text(ltrim($text, "\n\r")); + + $this->_block_parent->add_line(); + $frame->position(); + + // Layout the new line + $this->_layout_line(); + + } else if ($split < mb_strlen($frame->get_text())) { + // split the line if required + $frame->split_text($split); + + $t = $frame->get_text(); + + // Remove any trailing newlines + if ($split > 1 && $t[$split - 1] === "\n" && !$frame->is_pre()) + $frame->set_text(mb_substr($t, 0, -1)); + + // Do we need to trim spaces on wrapped lines? This might be desired, however, we + // can't trim the lines here or the layout will be affected if trimming the line + // leaves enough space to fit the next word in the text stream (because pdf layout + // is performed elsewhere). + /*if (!$this->_frame->get_prev_sibling() && !$this->_frame->get_next_sibling()) { + $t = $this->_frame->get_text(); + $this->_frame->set_text( trim($t) ); + }*/ + } + + if ($add_line) { + $this->_block_parent->add_line(); + $frame->position(); + } + + } else { + + // Remove empty space from start and end of line, but only where there isn't an inline sibling + // and the parent node isn't an inline element with siblings + // FIXME: Include non-breaking spaces? + $t = $frame->get_text(); + $parent = $frame->get_parent(); + $is_inline_frame = get_class($parent) === 'Inline_Frame_Decorator'; + + if ((!$is_inline_frame && !$frame->get_next_sibling()) /* || + ( $is_inline_frame && !$parent->get_next_sibling())*/ + ) { // fails BOLD UNDERLINED becomes BOLDUNDERLINED + $t = rtrim($t); + } + + if ((!$is_inline_frame && !$frame->get_prev_sibling()) /* || + ( $is_inline_frame && !$parent->get_prev_sibling())*/ + ) { // AB C fails (the whitespace is removed) + $t = ltrim($t); + } + + $frame->set_text($t); + + } + + // Set our new width + $width = $frame->recalculate_width(); + } + + //........................................................................ + + function reflow(BlockFrameDecorator $block = null) + { + $frame = $this->_frame; + $page = $frame->get_root(); + $page->check_forced_page_break($this->_frame); + + if ($page->is_full()) + return; + + $this->_block_parent = /*isset($block) ? $block : */ + $frame->find_block_parent(); + + // Left trim the text if this is the first text on the line and we're + // collapsing white space +// if ( $this->_block_parent->get_current_line()->w == 0 && +// ($frame->get_style()->white_space !== "pre" || +// $frame->get_style()->white_space !== "pre-wrap") ) { +// $frame->set_text( ltrim( $frame->get_text() ) ); +// } + + $frame->position(); + + $this->_layout_line(); + + if ($block) { + $block->add_frame_to_line($frame); + } + } + + //........................................................................ + + // Returns an array(0 => min, 1 => max, "min" => min, "max" => max) of the + // minimum and maximum widths of this frame + function get_min_max_width() + { + /*if ( !is_null($this->_min_max_cache) ) + return $this->_min_max_cache;*/ + $frame = $this->_frame; + $style = $frame->get_style(); + $this->_block_parent = $frame->find_block_parent(); + $line_width = $frame->get_containing_block("w"); + + $str = $text = $frame->get_text(); + $size = $style->font_size; + $font = $style->font_family; + + $word_spacing = $style->length_in_pt($style->word_spacing); + $char_spacing = $style->length_in_pt($style->letter_spacing); + + switch ($style->white_space) { + + default: + case "normal": + $str = preg_replace(self::$_whitespace_pattern, " ", $str); + case "pre-wrap": + case "pre-line": + + // Find the longest word (i.e. minimum length) + + // This technique (using arrays & an anonymous function) is actually + // faster than doing a single-pass character by character scan. Heh, + // yes I took the time to bench it ;) + $words = array_flip(preg_split("/[\s-]+/u", $str, -1, PREG_SPLIT_DELIM_CAPTURE)); + $root = $this; + array_walk($words, function(&$val, $str) use ($font, $size, $word_spacing, $char_spacing, $root) { + $val = $root->getFontMetrics()->getTextWidth($str, $font, $size, $word_spacing, $char_spacing); + }); + + arsort($words); + $min = reset($words); + break; + + case "pre": + $lines = array_flip(preg_split("/\n/u", $str)); + $root = $this; + array_walk($lines, function(&$val, $str) use ($font, $size, $word_spacing, $char_spacing, $root) { + $val = $root->getFontMetrics()->getTextWidth($str, $font, $size, $word_spacing, $char_spacing); + }); + + arsort($lines); + $min = reset($lines); + break; + + case "nowrap": + $min = $this->getFontMetrics()->getTextWidth($this->_collapse_white_space($str), $font, $size, $word_spacing, $char_spacing); + break; + + } + + switch ($style->white_space) { + + default: + case "normal": + case "nowrap": + $str = preg_replace(self::$_whitespace_pattern, " ", $text); + break; + + case "pre-line": + //XXX: Is this correct? + $str = preg_replace("/[ \t]+/u", " ", $text); + + case "pre-wrap": + // Find the longest word (i.e. minimum length) + $lines = array_flip(preg_split("/\n/", $text)); + $root = $this; + array_walk($lines, function(&$val, $str) use ($font, $size, $word_spacing, $char_spacing, $root) { + $val = $root->getFontMetrics()->getTextWidth($str, $font, $size, $word_spacing, $char_spacing); + }); + arsort($lines); + reset($lines); + $str = key($lines); + break; + + } + + $max = $this->getFontMetrics()->getTextWidth($str, $font, $size, $word_spacing, $char_spacing); + + $delta = $style->length_in_pt(array($style->margin_left, + $style->border_left_width, + $style->padding_left, + $style->padding_right, + $style->border_right_width, + $style->margin_right), $line_width); + $min += $delta; + $max += $delta; + + return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max); + + } + + /** + * @param FontMetrics $fontMetrics + * @return $this + */ + public function setFontMetrics(FontMetrics $fontMetrics) + { + $this->fontMetrics = $fontMetrics; + return $this; + } + + /** + * @return FontMetrics + */ + public function getFontMetrics() + { + return $this->fontMetrics; + } +} diff --git a/vendor/dompdf/dompdf/src/Helpers.php b/vendor/dompdf/dompdf/src/Helpers.php new file mode 100644 index 000000000..5b19f6812 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Helpers.php @@ -0,0 +1,733 @@ + tags if the current sapi is not 'cli'. + * Returns the output string instead of displaying it if $return is true. + * + * @param mixed $mixed variable or expression to display + * @param bool $return + * + * @return string + */ + public static function pre_r($mixed, $return = false) + { + if ($return) { + return "
" . print_r($mixed, true) . "
"; + } + + if (php_sapi_name() !== "cli") { + echo "
";
+        }
+
+        print_r($mixed);
+
+        if (php_sapi_name() !== "cli") {
+            echo "
"; + } else { + echo "\n"; + } + + flush(); + } + + /** + * builds a full url given a protocol, hostname, base path and url + * + * @param string $protocol + * @param string $host + * @param string $base_path + * @param string $url + * @return string + * + * Initially the trailing slash of $base_path was optional, and conditionally appended. + * However on dynamically created sites, where the page is given as url parameter, + * the base path might not end with an url. + * Therefore do not append a slash, and **require** the $base_url to ending in a slash + * when needed. + * Vice versa, on using the local file system path of a file, make sure that the slash + * is appended (o.k. also for Windows) + */ + public static function build_url($protocol, $host, $base_path, $url) + { + $protocol = mb_strtolower($protocol); + if (strlen($url) == 0) { + //return $protocol . $host . rtrim($base_path, "/\\") . "/"; + return $protocol . $host . $base_path; + } + + // Is the url already fully qualified, a Data URI, or a reference to a named anchor? + if (mb_strpos($url, "://") !== false || mb_substr($url, 0, 1) === "#" || mb_strpos($url, "data:") === 0 || mb_strpos($url, "mailto:") === 0) { + return $url; + } + + $ret = $protocol; + + if (!in_array(mb_strtolower($protocol), array("http://", "https://", "ftp://", "ftps://"))) { + //On Windows local file, an abs path can begin also with a '\' or a drive letter and colon + //drive: followed by a relative path would be a drive specific default folder. + //not known in php app code, treat as abs path + //($url[1] !== ':' || ($url[2]!=='\\' && $url[2]!=='/')) + if ($url[0] !== '/' && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || ($url[0] !== '\\' && $url[1] !== ':'))) { + // For rel path and local acess we ignore the host, and run the path through realpath() + $ret .= realpath($base_path) . '/'; + } + $ret .= $url; + $ret = preg_replace('/\?(.*)$/', "", $ret); + return $ret; + } + + // Protocol relative urls (e.g. "//example.org/style.css") + if (strpos($url, '//') === 0) { + $ret .= substr($url, 2); + //remote urls with backslash in html/css are not really correct, but lets be genereous + } elseif ($url[0] === '/' || $url[0] === '\\') { + // Absolute path + $ret .= $host . $url; + } else { + // Relative path + //$base_path = $base_path !== "" ? rtrim($base_path, "/\\") . "/" : ""; + $ret .= $host . $base_path . $url; + } + + return $ret; + } + + /** + * Converts decimal numbers to roman numerals + * + * @param int $num + * + * @throws Exception + * @return string + */ + public static function dec2roman($num) + { + + static $ones = array("", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"); + static $tens = array("", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"); + static $hund = array("", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"); + static $thou = array("", "m", "mm", "mmm"); + + if (!is_numeric($num)) { + throw new Exception("dec2roman() requires a numeric argument."); + } + + if ($num > 4000 || $num < 0) { + return "(out of range)"; + } + + $num = strrev((string)$num); + + $ret = ""; + switch (mb_strlen($num)) { + case 4: + $ret .= $thou[$num[3]]; + case 3: + $ret .= $hund[$num[2]]; + case 2: + $ret .= $tens[$num[1]]; + case 1: + $ret .= $ones[$num[0]]; + default: + break; + } + + return $ret; + } + + /** + * Determines whether $value is a percentage or not + * + * @param float $value + * + * @return bool + */ + public static function is_percent($value) + { + return false !== mb_strpos($value, "%"); + } + + /** + * Parses a data URI scheme + * http://en.wikipedia.org/wiki/Data_URI_scheme + * + * @param string $data_uri The data URI to parse + * + * @return array The result with charset, mime type and decoded data + */ + public static function parse_data_uri($data_uri) + { + if (!preg_match('/^data:(?P[a-z0-9\/+-.]+)(;charset=(?P[a-z0-9-])+)?(?P;base64)?\,(?P.*)?/is', $data_uri, $match)) { + return false; + } + + $match['data'] = rawurldecode($match['data']); + $result = array( + 'charset' => $match['charset'] ? $match['charset'] : 'US-ASCII', + 'mime' => $match['mime'] ? $match['mime'] : 'text/plain', + 'data' => $match['base64'] ? base64_decode($match['data']) : $match['data'], + ); + + return $result; + } + + /** + * Decoder for RLE8 compression in windows bitmaps + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp + * + * @param string $str Data to decode + * @param integer $width Image width + * + * @return string + */ + public static function rle8_decode($str, $width) + { + $lineWidth = $width + (3 - ($width - 1) % 4); + $out = ''; + $cnt = strlen($str); + + for ($i = 0; $i < $cnt; $i++) { + $o = ord($str[$i]); + switch ($o) { + case 0: # ESCAPE + $i++; + switch (ord($str[$i])) { + case 0: # NEW LINE + $padCnt = $lineWidth - strlen($out) % $lineWidth; + if ($padCnt < $lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line + break; + case 1: # END OF FILE + $padCnt = $lineWidth - strlen($out) % $lineWidth; + if ($padCnt < $lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line + break 3; + case 2: # DELTA + $i += 2; + break; + default: # ABSOLUTE MODE + $num = ord($str[$i]); + for ($j = 0; $j < $num; $j++) + $out .= $str[++$i]; + if ($num % 2) $i++; + } + break; + default: + $out .= str_repeat($str[++$i], $o); + } + } + return $out; + } + + /** + * Decoder for RLE4 compression in windows bitmaps + * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp + * + * @param string $str Data to decode + * @param integer $width Image width + * + * @return string + */ + public static function rle4_decode($str, $width) + { + $w = floor($width / 2) + ($width % 2); + $lineWidth = $w + (3 - (($width - 1) / 2) % 4); + $pixels = array(); + $cnt = strlen($str); + $c = 0; + + for ($i = 0; $i < $cnt; $i++) { + $o = ord($str[$i]); + switch ($o) { + case 0: # ESCAPE + $i++; + switch (ord($str[$i])) { + case 0: # NEW LINE + while (count($pixels) % $lineWidth != 0) { + $pixels[] = 0; + } + break; + case 1: # END OF FILE + while (count($pixels) % $lineWidth != 0) { + $pixels[] = 0; + } + break 3; + case 2: # DELTA + $i += 2; + break; + default: # ABSOLUTE MODE + $num = ord($str[$i]); + for ($j = 0; $j < $num; $j++) { + if ($j % 2 == 0) { + $c = ord($str[++$i]); + $pixels[] = ($c & 240) >> 4; + } else { + $pixels[] = $c & 15; + } + } + + if ($num % 2 == 0) { + $i++; + } + } + break; + default: + $c = ord($str[++$i]); + for ($j = 0; $j < $o; $j++) { + $pixels[] = ($j % 2 == 0 ? ($c & 240) >> 4 : $c & 15); + } + } + } + + $out = ''; + if (count($pixels) % 2) { + $pixels[] = 0; + } + + $cnt = count($pixels) / 2; + + for ($i = 0; $i < $cnt; $i++) { + $out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]); + } + + return $out; + } + + /** + * parse a full url or pathname and return an array(protocol, host, path, + * file + query + fragment) + * + * @param string $url + * @return array + */ + public static function explode_url($url) + { + $protocol = ""; + $host = ""; + $path = ""; + $file = ""; + + $arr = parse_url($url); + if ( isset($arr["scheme"]) ) { + $arr["scheme"] = mb_strtolower($arr["scheme"]); + } + + // Exclude windows drive letters... + if (isset($arr["scheme"]) && $arr["scheme"] !== "file" && strlen($arr["scheme"]) > 1) { + $protocol = $arr["scheme"] . "://"; + + if (isset($arr["user"])) { + $host .= $arr["user"]; + + if (isset($arr["pass"])) { + $host .= ":" . $arr["pass"]; + } + + $host .= "@"; + } + + if (isset($arr["host"])) { + $host .= $arr["host"]; + } + + if (isset($arr["port"])) { + $host .= ":" . $arr["port"]; + } + + if (isset($arr["path"]) && $arr["path"] !== "") { + // Do we have a trailing slash? + if ($arr["path"][mb_strlen($arr["path"]) - 1] === "/") { + $path = $arr["path"]; + $file = ""; + } else { + $path = rtrim(dirname($arr["path"]), '/\\') . "/"; + $file = basename($arr["path"]); + } + } + + if (isset($arr["query"])) { + $file .= "?" . $arr["query"]; + } + + if (isset($arr["fragment"])) { + $file .= "#" . $arr["fragment"]; + } + + } else { + + $i = mb_stripos($url, "file://"); + if ($i !== false) { + $url = mb_substr($url, $i + 7); + } + + $protocol = ""; // "file://"; ? why doesn't this work... It's because of + // network filenames like //COMPU/SHARENAME + + $host = ""; // localhost, really + $file = basename($url); + + $path = dirname($url); + + // Check that the path exists + if ($path !== false) { + $path .= '/'; + + } else { + // generate a url to access the file if no real path found. + $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://'; + + $host = isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : php_uname("n"); + + if (substr($arr["path"], 0, 1) === '/') { + $path = dirname($arr["path"]); + } else { + $path = '/' . rtrim(dirname($_SERVER["SCRIPT_NAME"]), '/') . '/' . $arr["path"]; + } + } + } + + $ret = array($protocol, $host, $path, $file, + "protocol" => $protocol, + "host" => $host, + "path" => $path, + "file" => $file); + return $ret; + } + + /** + * Print debug messages + * + * @param string $type The type of debug messages to print + * @param string $msg The message to show + */ + public static function dompdf_debug($type, $msg) + { + global $_DOMPDF_DEBUG_TYPES, $_dompdf_show_warnings, $_dompdf_debug; + if (isset($_DOMPDF_DEBUG_TYPES[$type]) && ($_dompdf_show_warnings || $_dompdf_debug)) { + $arr = debug_backtrace(); + + echo basename($arr[0]["file"]) . " (" . $arr[0]["line"] . "): " . $arr[1]["function"] . ": "; + Helpers::pre_r($msg); + } + } + + /** + * Stores warnings in an array for display later + * This function allows warnings generated by the DomDocument parser + * and CSS loader ({@link Stylesheet}) to be captured and displayed + * later. Without this function, errors are displayed immediately and + * PDF streaming is impossible. + * @see http://www.php.net/manual/en/function.set-error_handler.php + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param string $errline + * + * @throws Exception + */ + public static function record_warnings($errno, $errstr, $errfile, $errline) + { + // Not a warning or notice + if (!($errno & (E_WARNING | E_NOTICE | E_USER_NOTICE | E_USER_WARNING))) { + throw new Exception($errstr . " $errno"); + } + + global $_dompdf_warnings; + global $_dompdf_show_warnings; + + if ($_dompdf_show_warnings) { + echo $errstr . "\n"; + } + + $_dompdf_warnings[] = $errstr; + } + + /** + * @param $c + * @return bool|string + */ + public static function unichr($c) + { + if ($c <= 0x7F) { + return chr($c); + } else if ($c <= 0x7FF) { + return chr(0xC0 | $c >> 6) . chr(0x80 | $c & 0x3F); + } else if ($c <= 0xFFFF) { + return chr(0xE0 | $c >> 12) . chr(0x80 | $c >> 6 & 0x3F) + . chr(0x80 | $c & 0x3F); + } else if ($c <= 0x10FFFF) { + return chr(0xF0 | $c >> 18) . chr(0x80 | $c >> 12 & 0x3F) + . chr(0x80 | $c >> 6 & 0x3F) + . chr(0x80 | $c & 0x3F); + } + return false; + } + + /** + * Converts a CMYK color to RGB + * + * @param float|float[] $c + * @param float $m + * @param float $y + * @param float $k + * + * @return float[] + */ + public static function cmyk_to_rgb($c, $m = null, $y = null, $k = null) + { + if (is_array($c)) { + list($c, $m, $y, $k) = $c; + } + + $c *= 255; + $m *= 255; + $y *= 255; + $k *= 255; + + $r = (1 - round(2.55 * ($c + $k))); + $g = (1 - round(2.55 * ($m + $k))); + $b = (1 - round(2.55 * ($y + $k))); + + if ($r < 0) $r = 0; + if ($g < 0) $g = 0; + if ($b < 0) $b = 0; + + return array( + $r, $g, $b, + "r" => $r, "g" => $g, "b" => $b + ); + } + + /** + * getimagesize doesn't give a good size for 32bit BMP image v5 + * + * @param string $filename + * @return array The same format as getimagesize($filename) + */ + public static function dompdf_getimagesize($filename, $context = null) + { + static $cache = array(); + + if (isset($cache[$filename])) { + return $cache[$filename]; + } + + list($width, $height, $type) = getimagesize($filename); + + // Custom types + $types = array( + IMAGETYPE_JPEG => "jpeg", + IMAGETYPE_GIF => "gif", + IMAGETYPE_BMP => "bmp", + IMAGETYPE_PNG => "png", + ); + + $type = isset($types[$type]) ? $types[$type] : null; + + if ($width == null || $height == null) { + $data = file_get_contents($filename, null, $context, 0, 26); + + if (substr($data, 0, 2) === "BM") { + $meta = unpack('vtype/Vfilesize/Vreserved/Voffset/Vheadersize/Vwidth/Vheight', $data); + $width = (int)$meta['width']; + $height = (int)$meta['height']; + $type = "bmp"; + } + else { + if (strpos(file_get_contents($filename), "loadFile($filename); + + list($width, $height) = $doc->getDimensions(); + $type = "svg"; + } + } + + } + + return $cache[$filename] = array($width, $height, $type); + } + + /** + * Credit goes to mgutt + * http://www.programmierer-forum.de/function-imagecreatefrombmp-welche-variante-laeuft-t143137.htm + * Modified by Fabien Menager to support RGB555 BMP format + */ + public static function imagecreatefrombmp($filename, $context = null) + { + if (!function_exists("imagecreatetruecolor")) { + trigger_error("The PHP GD extension is required, but is not installed.", E_ERROR); + return false; + } + + // version 1.00 + if (!($fh = fopen($filename, 'rb'))) { + trigger_error('imagecreatefrombmp: Can not open ' . $filename, E_USER_WARNING); + return false; + } + + $bytes_read = 0; + + // read file header + $meta = unpack('vtype/Vfilesize/Vreserved/Voffset', fread($fh, 14)); + + // check for bitmap + if ($meta['type'] != 19778) { + trigger_error('imagecreatefrombmp: ' . $filename . ' is not a bitmap!', E_USER_WARNING); + return false; + } + + // read image header + $meta += unpack('Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant', fread($fh, 40)); + $bytes_read += 40; + + // read additional bitfield header + if ($meta['compression'] == 3) { + $meta += unpack('VrMask/VgMask/VbMask', fread($fh, 12)); + $bytes_read += 12; + } + + // set bytes and padding + $meta['bytes'] = $meta['bits'] / 8; + $meta['decal'] = 4 - (4 * (($meta['width'] * $meta['bytes'] / 4) - floor($meta['width'] * $meta['bytes'] / 4))); + if ($meta['decal'] == 4) { + $meta['decal'] = 0; + } + + // obtain imagesize + if ($meta['imagesize'] < 1) { + $meta['imagesize'] = $meta['filesize'] - $meta['offset']; + // in rare cases filesize is equal to offset so we need to read physical size + if ($meta['imagesize'] < 1) { + $meta['imagesize'] = @filesize($filename) - $meta['offset']; + if ($meta['imagesize'] < 1) { + trigger_error('imagecreatefrombmp: Can not obtain filesize of ' . $filename . '!', E_USER_WARNING); + return false; + } + } + } + + // calculate colors + $meta['colors'] = !$meta['colors'] ? pow(2, $meta['bits']) : $meta['colors']; + + // read color palette + $palette = array(); + if ($meta['bits'] < 16) { + $palette = unpack('l' . $meta['colors'], fread($fh, $meta['colors'] * 4)); + // in rare cases the color value is signed + if ($palette[1] < 0) { + foreach ($palette as $i => $color) { + $palette[$i] = $color + 16777216; + } + } + } + + // ignore extra bitmap headers + if ($meta['headersize'] > $bytes_read) { + fread($fh, $meta['headersize'] - $bytes_read); + } + + // create gd image + $im = imagecreatetruecolor($meta['width'], $meta['height']); + $data = fread($fh, $meta['imagesize']); + + // uncompress data + switch ($meta['compression']) { + case 1: + $data = Helpers::rle8_decode($data, $meta['width']); + break; + case 2: + $data = Helpers::rle4_decode($data, $meta['width']); + break; + } + + $p = 0; + $vide = chr(0); + $y = $meta['height'] - 1; + $error = 'imagecreatefrombmp: ' . $filename . ' has not enough data!'; + + // loop through the image data beginning with the lower left corner + while ($y >= 0) { + $x = 0; + while ($x < $meta['width']) { + switch ($meta['bits']) { + case 32: + case 24: + if (!($part = substr($data, $p, 3 /*$meta['bytes']*/))) { + trigger_error($error, E_USER_WARNING); + return $im; + } + $color = unpack('V', $part . $vide); + break; + case 16: + if (!($part = substr($data, $p, 2 /*$meta['bytes']*/))) { + trigger_error($error, E_USER_WARNING); + return $im; + } + $color = unpack('v', $part); + + if (empty($meta['rMask']) || $meta['rMask'] != 0xf800) { + $color[1] = (($color[1] & 0x7c00) >> 7) * 65536 + (($color[1] & 0x03e0) >> 2) * 256 + (($color[1] & 0x001f) << 3); // 555 + } else { + $color[1] = (($color[1] & 0xf800) >> 8) * 65536 + (($color[1] & 0x07e0) >> 3) * 256 + (($color[1] & 0x001f) << 3); // 565 + } + break; + case 8: + $color = unpack('n', $vide . substr($data, $p, 1)); + $color[1] = $palette[$color[1] + 1]; + break; + case 4: + $color = unpack('n', $vide . substr($data, floor($p), 1)); + $color[1] = ($p * 2) % 2 == 0 ? $color[1] >> 4 : $color[1] & 0x0F; + $color[1] = $palette[$color[1] + 1]; + break; + case 1: + $color = unpack('n', $vide . substr($data, floor($p), 1)); + switch (($p * 8) % 8) { + case 0: + $color[1] = $color[1] >> 7; + break; + case 1: + $color[1] = ($color[1] & 0x40) >> 6; + break; + case 2: + $color[1] = ($color[1] & 0x20) >> 5; + break; + case 3: + $color[1] = ($color[1] & 0x10) >> 4; + break; + case 4: + $color[1] = ($color[1] & 0x8) >> 3; + break; + case 5: + $color[1] = ($color[1] & 0x4) >> 2; + break; + case 6: + $color[1] = ($color[1] & 0x2) >> 1; + break; + case 7: + $color[1] = ($color[1] & 0x1); + break; + } + $color[1] = $palette[$color[1] + 1]; + break; + default: + trigger_error('imagecreatefrombmp: ' . $filename . ' has ' . $meta['bits'] . ' bits and this is not supported!', E_USER_WARNING); + return false; + } + imagesetpixel($im, $x, $y, $color[1]); + $x++; + $p += $meta['bytes']; + } + $y--; + $p += $meta['decal']; + } + fclose($fh); + return $im; + } + +} diff --git a/vendor/dompdf/dompdf/src/Image/Cache.php b/vendor/dompdf/dompdf/src/Image/Cache.php new file mode 100644 index 000000000..8e9e70e49 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Image/Cache.php @@ -0,0 +1,186 @@ + + * @author Helmut Tischer + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Image; + +use Dompdf\Dompdf; +use Dompdf\Helpers; +use Dompdf\Exception\ImageException; + +/** + * Static class that resolves image urls and downloads and caches + * remote images if required. + * + * @package dompdf + */ +class Cache +{ + /** + * Array of downloaded images. Cached so that identical images are + * not needlessly downloaded. + * + * @var array + */ + protected static $_cache = array(); + + /** + * The url to the "broken image" used when images can't be loaded + * + * @var string + */ + public static $broken_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAA3NCSVQICAjb4U/gAAAAHlBMVEWZmZn////g4OCkpKS1tbXv7++9vb2tra3m5ub5+fkFnN6oAAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M0BrLToAAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNC8xMi8xMRPnI58AAAGZSURBVEiJhZbPasMwDMbTw2DHKhDQcbDQPsEge4BAjg0Mxh5gkBcY7Niwkpx32PvOjv9JspX60It/+fxJsqxW1b11gN11rA7N3v6vAd5nfR9fDYCTDiyzAeA6qgKd9QDNoAtsAKyKCxzAAfhdBuyHGwC3oovNvQOaxxJwnSNg3ZQFAlBy4ax7AG6ZBLrgA5Cn038SAPgREiaJHJASwXYEhEQQIACyikTTCWCBJJoANBfpPAKQdBLHFMBYkctcBKIE9lAGggt6gRjgA2GV44CL7m1WgS08fAAdsPHxyyMAIyHujgRwEldHArCKy5cBz90+gNOyf8TTyKOUQN2LPEmgnWWPcKD+sr+rnuqTK1avAcHfRSv3afTgVAbqmCPiggLtGM8aSkBNOidVjADrmIDYebT1PoGsWJEE8Oc0b96aZoe4iMBZPiADB6RAzEUA2vwRmyiAL3Lfv6MBSEmUEg7ALt/3LhxwLgj4QNw4UCbKEsaBNpPsyRbgVRASFig78BIGyJNIJQyQTwIi0RvgT98H+Mi6W67j3X8H/427u5bfpQGVAAAAAElFTkSuQmCC"; + + /** + * Current dompdf instance + * + * @var Dompdf + */ + protected static $_dompdf; + + /** + * Resolve and fetch an image for use. + * + * @param string $url The url of the image + * @param string $protocol Default protocol if none specified in $url + * @param string $host Default host if none specified in $url + * @param string $base_path Default path if none specified in $url + * @param Dompdf $dompdf The Dompdf instance + * + * @throws ImageException + * @return array An array with two elements: The local path to the image and the image extension + */ + static function resolve_url($url, $protocol, $host, $base_path, Dompdf $dompdf) + { + self::$_dompdf = $dompdf; + + $protocol = mb_strtolower($protocol); + $parsed_url = Helpers::explode_url($url); + $message = null; + + $remote = ($protocol && $protocol !== "file://") || ($parsed_url['protocol'] != ""); + + $data_uri = strpos($parsed_url['protocol'], "data:") === 0; + $full_url = null; + $enable_remote = $dompdf->get_option("enable_remote"); + + try { + + // Remote not allowed and is not DataURI + if (!$enable_remote && $remote && !$data_uri) { + throw new ImageException("Remote file access is disabled.", E_WARNING); + } // Remote allowed or DataURI + else { + if ($enable_remote && $remote || $data_uri) { + // Download remote files to a temporary directory + $full_url = Helpers::build_url($protocol, $host, $base_path, $url); + + // From cache + if (isset(self::$_cache[$full_url])) { + $resolved_url = self::$_cache[$full_url]; + } // From remote + else { + $tmp_dir = $dompdf->get_option("temp_dir"); + $resolved_url = tempnam($tmp_dir, "ca_dompdf_img_"); + $image = ""; + + if ($data_uri) { + if ($parsed_data_uri = Helpers::parse_data_uri($url)) { + $image = $parsed_data_uri['data']; + } + } else { + set_error_handler(array("\\Dompdf\\Helpers", "record_warnings")); + $image = file_get_contents($full_url, null, $dompdf->getHttpContext()); + restore_error_handler(); + } + + // Image not found or invalid + if (strlen($image) == 0) { + $msg = ($data_uri ? "Data-URI could not be parsed" : "Image not found"); + throw new ImageException($msg, E_WARNING); + } // Image found, put in cache and process + else { + //e.g. fetch.php?media=url.jpg&cache=1 + //- Image file name might be one of the dynamic parts of the url, don't strip off! + //- a remote url does not need to have a file extension at all + //- local cached file does not have a matching file extension + //Therefore get image type from the content + file_put_contents($resolved_url, $image); + } + } + } // Not remote, local image + else { + $resolved_url = Helpers::build_url($protocol, $host, $base_path, $url); + } + } + + // Check if the local file is readable + if (!is_readable($resolved_url) || !filesize($resolved_url)) { + throw new ImageException("Image not readable or empty", E_WARNING); + } // Check is the file is an image + else { + list($width, $height, $type) = Helpers::dompdf_getimagesize($resolved_url, $dompdf->getHttpContext()); + + // Known image type + if ($width && $height && in_array($type, array("gif", "png", "jpeg", "bmp", "svg"))) { + //Don't put replacement image into cache - otherwise it will be deleted on cache cleanup. + //Only execute on successful caching of remote image. + if ($enable_remote && $remote || $data_uri) { + self::$_cache[$full_url] = $resolved_url; + } + } // Unknown image type + else { + throw new ImageException("Image type unknown", E_WARNING); + } + } + } catch (ImageException $e) { + $resolved_url = self::$broken_image; + $type = "png"; + $message = "Image not found or type unknown"; + Helpers::record_warnings($e->getCode(), $e->getMessage() . " \n $url", $e->getFile(), $e->getLine()); + } + + return array($resolved_url, $type, $message); + } + + /** + * Unlink all cached images (i.e. temporary images either downloaded + * or converted) + */ + static function clear() + { + if (empty(self::$_cache) || self::$_dompdf->get_option("debugKeepTemp")) { + return; + } + + foreach (self::$_cache as $file) { + if (self::$_dompdf->get_option("debugPng")) { + print "[clear unlink $file]"; + } + unlink($file); + } + + self::$_cache = array(); + } + + static function detect_type($file, $context = null) + { + list(, , $type) = Helpers::dompdf_getimagesize($file, $context); + + return $type; + } + + static function is_broken($url) + { + return $url === self::$broken_image; + } +} + +if (file_exists(realpath(__DIR__ . "/../../lib/res/broken_image.png"))) { + Cache::$broken_image = realpath(__DIR__ . "/../../lib/res/broken_image.png"); +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/JavascriptEmbedder.php b/vendor/dompdf/dompdf/src/JavascriptEmbedder.php new file mode 100644 index 000000000..1463f2315 --- /dev/null +++ b/vendor/dompdf/dompdf/src/JavascriptEmbedder.php @@ -0,0 +1,43 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf; + +use Dompdf\Frame; + +/** + * Embeds Javascript into the PDF document + * + * @package dompdf + */ +class JavascriptEmbedder +{ + + /** + * @var Dompdf + */ + protected $_dompdf; + + function __construct(Dompdf $dompdf) + { + $this->_dompdf = $dompdf; + } + + function insert($script) + { + $this->_dompdf->get_canvas()->javascript($script); + } + + function render(Frame $frame) + { + if (!$this->_dompdf->get_option("enable_javascript")) { + return; + } + + $this->insert($frame->get_node()->nodeValue); + } +} diff --git a/vendor/dompdf/dompdf/src/LineBox.php b/vendor/dompdf/dompdf/src/LineBox.php new file mode 100644 index 000000000..b94e08917 --- /dev/null +++ b/vendor/dompdf/dompdf/src/LineBox.php @@ -0,0 +1,260 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\Block; +use Dompdf\FrameDecorator\Page; + +/** + * The line box class + * + * This class represents a line box + * http://www.w3.org/TR/CSS2/visuren.html#line-box + * + * @package dompdf + */ +class LineBox +{ + + /** + * @var Block + */ + protected $_block_frame; + + /** + * @var Frame[] + */ + protected $_frames = array(); + + /** + * @var integer + */ + public $wc = 0; + + /** + * @var float + */ + public $y = null; + + /** + * @var float + */ + public $w = 0.0; + + /** + * @var float + */ + public $h = 0.0; + + /** + * @var float + */ + public $left = 0.0; + + /** + * @var float + */ + public $right = 0.0; + + /** + * @var Frame + */ + public $tallest_frame = null; + + /** + * @var bool[] + */ + public $floating_blocks = array(); + + /** + * @var bool + */ + public $br = false; + + /** + * Class constructor + * + * @param Block $frame the Block containing this line + */ + function __construct(Block $frame, $y = 0) + { + $this->_block_frame = $frame; + $this->_frames = array(); + $this->y = $y; + + $this->get_float_offsets(); + } + + /** + * Returns the floating elements inside the first floating parent + * + * @param Page $root + * + * @return Frame[] + */ + function get_floats_inside(Page $root) + { + $floating_frames = $root->get_floating_frames(); + + if (count($floating_frames) == 0) { + return $floating_frames; + } + + // Find nearest floating element + $p = $this->_block_frame; + while ($p->get_style()->float === "none") { + $parent = $p->get_parent(); + + if (!$parent) { + break; + } + + $p = $parent; + } + + if ($p == $root) { + return $floating_frames; + } + + $parent = $p; + + $childs = array(); + + foreach ($floating_frames as $_floating) { + $p = $_floating->get_parent(); + + while (($p = $p->get_parent()) && $p !== $parent) ; + + if ($p) { + $childs[] = $p; + } + } + + return $childs; + } + + function get_float_offsets() + { + static $anti_infinite_loop = 500; // FIXME smelly hack + + $reflower = $this->_block_frame->get_reflower(); + + if (!$reflower) { + return; + } + + $cb_w = null; + + $block = $this->_block_frame; + $root = $block->get_root(); + + if (!$root) { + return; + } + + $floating_frames = $this->get_floats_inside($root); + + foreach ($floating_frames as $child_key => $floating_frame) { + $id = $floating_frame->get_id(); + + if (isset($this->floating_blocks[$id])) { + continue; + } + + $floating_style = $floating_frame->get_style(); + $float = $floating_style->float; + + $floating_width = $floating_frame->get_margin_width(); + + if (!$cb_w) { + $cb_w = $floating_frame->get_containing_block("w"); + } + + $line_w = $this->get_width(); + + if (!$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w)) { + $floating_frame->_float_next_line = true; + continue; + } + + // If the child is still shifted by the floating element + if ($anti_infinite_loop-- > 0 && + $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y && + $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x") + ) { + if ($float === "left") { + $this->left += $floating_width; + } else { + $this->right += $floating_width; + } + + $this->floating_blocks[$id] = true; + } // else, the floating element won't shift anymore + else { + $root->remove_floating_frame($child_key); + } + } + } + + /** + * @return float + */ + function get_width() + { + return $this->left + $this->w + $this->right; + } + + /** + * @return Block + */ + function get_block_frame() + { + return $this->_block_frame; + } + + /** + * @return Frame[] + */ + function &get_frames() + { + return $this->_frames; + } + + /** + * @param Frame $frame + */ + function add_frame(Frame $frame) + { + $this->_frames[] = $frame; + } + + function __toString() + { + $props = array("wc", "y", "w", "h", "left", "right", "br"); + $s = ""; + foreach ($props as $prop) { + $s .= "$prop: " . $this->$prop . "\n"; + } + $s .= count($this->_frames) . " frames\n"; + + return $s; + } + /*function __get($prop) { + if (!isset($this->{"_$prop"})) return; + return $this->{"_$prop"}; + }*/ +} + +/* +class LineBoxList implements Iterator { + private $_p = 0; + private $_lines = array(); + +} +*/ diff --git a/vendor/dompdf/dompdf/src/Options.php b/vendor/dompdf/dompdf/src/Options.php new file mode 100644 index 000000000..d46914517 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Options.php @@ -0,0 +1,974 @@ + ... tags. + * + * ==== IMPORTANT ==== + * Enabling this for documents you do not trust (e.g. arbitrary remote html + * pages) is a security risk. Embedded scripts are run with the same level of + * system access available to dompdf. Set this option to false (recommended) + * if you wish to process untrusted documents. + * + * This setting may increase the risk of system exploit. Do not change + * this settings without understanding the consequences. Additional + * documentation is available on the dompdf wiki at: + * https://github.com/dompdf/dompdf/wiki + * + * @var bool + */ + private $isPhpEnabled = false; + + /** + * Enable remote file access + * + * If this setting is set to true, DOMPDF will access remote sites for + * images and CSS files as required. + * + * ==== IMPORTANT ==== + * This can be a security risk, in particular in combination with isPhpEnabled and + * allowing remote html code to be passed to $dompdf = new DOMPDF(); $dompdf->load_html(...); + * This allows anonymous users to download legally doubtful internet content which on + * tracing back appears to being downloaded by your server, or allows malicious php code + * in remote html pages to be executed by your server with your account privileges. + * + * This setting may increase the risk of system exploit. Do not change + * this settings without understanding the consequences. Additional + * documentation is available on the dompdf wiki at: + * https://github.com/dompdf/dompdf/wiki + * + * @var bool + */ + private $isRemoteEnabled = false; + + /** + * Enable inline Javascript + * + * If this setting is set to true then DOMPDF will automatically insert + * JavaScript code contained within tags. + * + * @var bool + */ + private $isJavascriptEnabled = true; + + /** + * Use the more-than-experimental HTML5 Lib parser + * + * @var bool + */ + private $isHtml5ParserEnabled = false; + + /** + * Whether to enable font subsetting or not. + * + * @var is_bool + */ + private $isFontSubsettingEnabled = false; + + /** + * @var bool + */ + private $debugPng = false; + + /** + * @var bool + */ + private $debugKeepTemp = false; + + /** + * @var bool + */ + private $debugCss = false; + + /** + * @var bool + */ + private $debugLayout = false; + + /** + * @var bool + */ + private $debugLayoutLines = true; + + /** + * @var bool + */ + private $debugLayoutBlocks = true; + + /** + * @var bool + */ + private $debugLayoutInline = true; + + /** + * @var bool + */ + private $debugLayoutPaddingBox = true; + + /** + * The PDF rendering backend to use + * + * Valid settings are 'PDFLib', 'CPDF', 'GD', and 'auto'. 'auto' will + * look for PDFLib and use it if found, or if not it will fall back on + * CPDF. 'GD' renders PDFs to graphic files. {@link Dompdf\CanvasFactory} + * ultimately determines which rendering class to instantiate + * based on this setting. + * + * @var string + */ + private $pdfBackend = "CPDF"; + + /** + * PDFlib license key + * + * If you are using a licensed, commercial version of PDFlib, specify + * your license key here. If you are using PDFlib-Lite or are evaluating + * the commercial version of PDFlib, comment out this setting. + * + * @link http://www.pdflib.com + * + * If pdflib present in web server and auto or selected explicitely above, + * a real license code must exist! + * + * @var string + */ + private $pdflibLicense = ""; + + /** + * @var string + * @deprecated + */ + private $adminUsername = "user"; + + /** + * @var string + * @deprecated + */ + private $adminPassword = "password"; + + /** + * @param array $attributes + */ + public function __construct(array $attributes = null) + { + $this->setChroot(realpath(__DIR__ . "/../")); + $this->setRootDir($this->getChroot()); + $this->setTempDir(sys_get_temp_dir()); + $this->setFontDir($this->chroot . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "fonts"); + $this->setFontCache($this->getFontDir()); + $this->setLogOutputFile($this->getTempDir() . DIRECTORY_SEPARATOR . "log.htm"); + + if (null !== $attributes) { + $this->set($attributes); + } + } + + /** + * @param array|string $attributes + * @param null|mixed $value + * @return $this + */ + public function set($attributes, $value = null) + { + if (!is_array($attributes)) { + $attributes = array($attributes => $value); + } + foreach ($attributes as $key => $value) { + if ($key === 'tempDir' || $key === 'temp_dir') { + $this->setTempDir($value); + } elseif ($key === 'fontDir' || $key === 'font_dir') { + $this->setFontDir($value); + } elseif ($key === 'fontCache' || $key === 'font_cache') { + $this->setFontCache($value); + } elseif ($key === 'chroot') { + $this->setChroot($value); + } elseif ($key === 'logOutputFile' || $key === 'log_output_file') { + $this->setLogOutputFile($value); + } elseif ($key === 'defaultMediaType' || $key === 'default_media_type') { + $this->setDefaultMediaType($value); + } elseif ($key === 'defaultPaperSize' || $key === 'default_paper_size') { + $this->setDefaultPaperSize($value); + } elseif ($key === 'defaultFont' || $key === 'default_font') { + $this->setDefaultFont($value); + } elseif ($key === 'dpi') { + $this->setDpi($value); + } elseif ($key === 'fontHeightRatio' || $key === 'font_height_ratio') { + $this->setFontHeightRatio($value); + } elseif ($key === 'isPhpEnabled' || $key === 'is_php_enabled' || $key === 'enable_php') { + $this->setIsPhpEnabled($value); + } elseif ($key === 'isRemoteEnabled' || $key === 'is_remote_enabled' || $key === 'enable_remote') { + $this->setIsRemoteEnabled($value); + } elseif ($key === 'isJavascriptEnabled' || $key === 'is_javascript_enabled' || $key === 'enable_javascript') { + $this->setIsJavascriptEnabled($value); + } elseif ($key === 'isHtml5ParserEnabled' || $key === 'is_html5_parser_enabled' || $key === 'enable_html5_parser') { + $this->setIsHtml5ParserEnabled($value); + } elseif ($key === 'isFontSubsettingEnabled' || $key === 'is_font_subsetting_enabled' || $key === 'enable_font_subsetting') { + $this->setIsFontSubsettingEnabled($value); + } elseif ($key === 'debugPng' || $key === 'debug_png') { + $this->setDebugPng($value); + } elseif ($key === 'debugKeepTemp' || $key === 'debug_keep_temp') { + $this->setDebugKeepTemp($value); + } elseif ($key === 'debugCss' || $key === 'debug_css') { + $this->setDebugCss($value); + } elseif ($key === 'debugLayout' || $key === 'debug_layout') { + $this->setDebugLayout($value); + } elseif ($key === 'debugLayoutLines' || $key === 'debug_layout_lines') { + $this->setDebugLayoutLines($value); + } elseif ($key === 'debugLayoutBlocks' || $key === 'debug_layout_blocks') { + $this->setDebugLayoutBlocks($value); + } elseif ($key === 'debugLayoutInline' || $key === 'debug_layout_inline') { + $this->setDebugLayoutInline($value); + } elseif ($key === 'debugLayoutPaddingBox' || $key === 'debug_layout_padding_box') { + $this->setDebugLayoutPaddingBox($value); + } elseif ($key === 'pdfBackend' || $key === 'pdf_backend') { + $this->setPdfBackend($value); + } elseif ($key === 'pdflibLicense' || $key === 'pdflib_license') { + $this->setPdflibLicense($value); + } elseif ($key === 'adminUsername' || $key === 'admin_username') { + $this->setAdminUsername($value); + } elseif ($key === 'adminPassword' || $key === 'admin_password') { + $this->setAdminPassword($value); + } + } + return $this; + } + + /** + * @param string $key + * @return mixed + */ + public function get($key) + { + if ($key === 'tempDir' || $key === 'temp_dir') { + return $this->getTempDir(); + } elseif ($key === 'fontDir' || $key === 'font_dir') { + return $this->getFontDir(); + } elseif ($key === 'fontCache' || $key === 'font_cache') { + return $this->getFontCache(); + } elseif ($key === 'chroot') { + return $this->getChroot(); + } elseif ($key === 'logOutputFile' || $key === 'log_output_file') { + return $this->getLogOutputFile(); + } elseif ($key === 'defaultMediaType' || $key === 'default_media_type') { + return $this->getDefaultMediaType(); + } elseif ($key === 'defaultPaperSize' || $key === 'default_paper_size') { + return $this->getDefaultPaperSize(); + } elseif ($key === 'defaultFont' || $key === 'default_font') { + return $this->getDefaultFont(); + } elseif ($key === 'dpi') { + return $this->getDpi(); + } elseif ($key === 'fontHeightRatio' || $key === 'font_height_ratio') { + return $this->getFontHeightRatio(); + } elseif ($key === 'isPhpEnabled' || $key === 'is_php_enabled' || $key === 'enable_php') { + return $this->getIsPhpEnabled(); + } elseif ($key === 'isRemoteEnabled' || $key === 'is_remote_enabled' || $key === 'enable_remote') { + return $this->getIsRemoteEnabled(); + } elseif ($key === 'isJavascriptEnabled' || $key === 'is_javascript_enabled' || $key === 'enable_javascript') { + return $this->getIsJavascriptEnabled(); + } elseif ($key === 'isHtml5ParserEnabled' || $key === 'is_html5_parser_enabled' || $key === 'enable_html5_parser') { + return $this->getIsHtml5ParserEnabled(); + } elseif ($key === 'isFontSubsettingEnabled' || $key === 'is_font_subsetting_enabled' || $key === 'enable_font_subsetting') { + return $this->getIsFontSubsettingEnabled(); + } elseif ($key === 'debugPng' || $key === 'debug_png') { + return $this->getDebugPng(); + } elseif ($key === 'debugKeepTemp' || $key === 'debug_keep_temp') { + return $this->getDebugKeepTemp(); + } elseif ($key === 'debugCss' || $key === 'debug_css') { + return $this->getDebugCss(); + } elseif ($key === 'debugLayout' || $key === 'debug_layout') { + return $this->getDebugLayout(); + } elseif ($key === 'debugLayoutLines' || $key === 'debug_layout_lines') { + return $this->getDebugLayoutLines(); + } elseif ($key === 'debugLayoutBlocks' || $key === 'debug_layout_blocks') { + return $this->getDebugLayoutBlocks(); + } elseif ($key === 'debugLayoutInline' || $key === 'debug_layout_inline') { + return $this->getDebugLayoutInline(); + } elseif ($key === 'debugLayoutPaddingBox' || $key === 'debug_layout_padding_box') { + return $this->getDebugLayoutPaddingBox(); + } elseif ($key === 'pdfBackend' || $key === 'pdf_backend') { + return $this->getPdfBackend(); + } elseif ($key === 'pdflibLicense' || $key === 'pdflib_license') { + return $this->getPdflibLicense(); + } elseif ($key === 'adminUsername' || $key === 'admin_username') { + return $this->getAdminUsername(); + } elseif ($key === 'adminPassword' || $key === 'admin_password') { + return $this->getAdminPassword(); + } + return null; + } + + /** + * @param string $adminPassword + * @return $this + */ + public function setAdminPassword($adminPassword) + { + $this->adminPassword = $adminPassword; + return $this; + } + + /** + * @return string + */ + public function getAdminPassword() + { + return $this->adminPassword; + } + + /** + * @param string $adminUsername + * @return $this + */ + public function setAdminUsername($adminUsername) + { + $this->adminUsername = $adminUsername; + return $this; + } + + /** + * @return string + */ + public function getAdminUsername() + { + return $this->adminUsername; + } + + /** + * @param string $pdfBackend + * @return $this + */ + public function setPdfBackend($pdfBackend) + { + $this->pdfBackend = $pdfBackend; + return $this; + } + + /** + * @return string + */ + public function getPdfBackend() + { + return $this->pdfBackend; + } + + /** + * @param string $pdflibLicense + * @return $this + */ + public function setPdflibLicense($pdflibLicense) + { + $this->pdflibLicense = $pdflibLicense; + return $this; + } + + /** + * @return string + */ + public function getPdflibLicense() + { + return $this->pdflibLicense; + } + + /** + * @param string $chroot + * @return $this + */ + public function setChroot($chroot) + { + $this->chroot = $chroot; + return $this; + } + + /** + * @return string + */ + public function getChroot() + { + return $this->chroot; + } + + /** + * @param boolean $debugCss + * @return $this + */ + public function setDebugCss($debugCss) + { + $this->debugCss = $debugCss; + return $this; + } + + /** + * @return boolean + */ + public function getDebugCss() + { + return $this->debugCss; + } + + /** + * @param boolean $debugKeepTemp + * @return $this + */ + public function setDebugKeepTemp($debugKeepTemp) + { + $this->debugKeepTemp = $debugKeepTemp; + return $this; + } + + /** + * @return boolean + */ + public function getDebugKeepTemp() + { + return $this->debugKeepTemp; + } + + /** + * @param boolean $debugLayout + * @return $this + */ + public function setDebugLayout($debugLayout) + { + $this->debugLayout = $debugLayout; + return $this; + } + + /** + * @return boolean + */ + public function getDebugLayout() + { + return $this->debugLayout; + } + + /** + * @param boolean $debugLayoutBlocks + * @return $this + */ + public function setDebugLayoutBlocks($debugLayoutBlocks) + { + $this->debugLayoutBlocks = $debugLayoutBlocks; + return $this; + } + + /** + * @return boolean + */ + public function getDebugLayoutBlocks() + { + return $this->debugLayoutBlocks; + } + + /** + * @param boolean $debugLayoutInline + * @return $this + */ + public function setDebugLayoutInline($debugLayoutInline) + { + $this->debugLayoutInline = $debugLayoutInline; + return $this; + } + + /** + * @return boolean + */ + public function getDebugLayoutInline() + { + return $this->debugLayoutInline; + } + + /** + * @param boolean $debugLayoutLines + * @return $this + */ + public function setDebugLayoutLines($debugLayoutLines) + { + $this->debugLayoutLines = $debugLayoutLines; + return $this; + } + + /** + * @return boolean + */ + public function getDebugLayoutLines() + { + return $this->debugLayoutLines; + } + + /** + * @param boolean $debugLayoutPaddingBox + * @return $this + */ + public function setDebugLayoutPaddingBox($debugLayoutPaddingBox) + { + $this->debugLayoutPaddingBox = $debugLayoutPaddingBox; + return $this; + } + + /** + * @return boolean + */ + public function getDebugLayoutPaddingBox() + { + return $this->debugLayoutPaddingBox; + } + + /** + * @param boolean $debugPng + * @return $this + */ + public function setDebugPng($debugPng) + { + $this->debugPng = $debugPng; + return $this; + } + + /** + * @return boolean + */ + public function getDebugPng() + { + return $this->debugPng; + } + + /** + * @param string $defaultFont + * @return $this + */ + public function setDefaultFont($defaultFont) + { + $this->defaultFont = $defaultFont; + return $this; + } + + /** + * @return string + */ + public function getDefaultFont() + { + return $this->defaultFont; + } + + /** + * @param string $defaultMediaType + * @return $this + */ + public function setDefaultMediaType($defaultMediaType) + { + $this->defaultMediaType = $defaultMediaType; + return $this; + } + + /** + * @return string + */ + public function getDefaultMediaType() + { + return $this->defaultMediaType; + } + + /** + * @param string $defaultPaperSize + * @return $this + */ + public function setDefaultPaperSize($defaultPaperSize) + { + $this->defaultPaperSize = $defaultPaperSize; + return $this; + } + + /** + * @return string + */ + public function getDefaultPaperSize() + { + return $this->defaultPaperSize; + } + + /** + * @param int $dpi + * @return $this + */ + public function setDpi($dpi) + { + $this->dpi = $dpi; + return $this; + } + + /** + * @return int + */ + public function getDpi() + { + return $this->dpi; + } + + /** + * @param string $fontCache + * @return $this + */ + public function setFontCache($fontCache) + { + $this->fontCache = $fontCache; + return $this; + } + + /** + * @return string + */ + public function getFontCache() + { + return $this->fontCache; + } + + /** + * @param string $fontDir + * @return $this + */ + public function setFontDir($fontDir) + { + $this->fontDir = $fontDir; + return $this; + } + + /** + * @return string + */ + public function getFontDir() + { + return $this->fontDir; + } + + /** + * @param float $fontHeightRatio + * @return $this + */ + public function setFontHeightRatio($fontHeightRatio) + { + $this->fontHeightRatio = $fontHeightRatio; + return $this; + } + + /** + * @return float + */ + public function getFontHeightRatio() + { + return $this->fontHeightRatio; + } + + /** + * @param boolean $isFontSubsettingEnabled + * @return $this + */ + public function setIsFontSubsettingEnabled($isFontSubsettingEnabled) + { + $this->isFontSubsettingEnabled = $isFontSubsettingEnabled; + return $this; + } + + /** + * @return boolean + */ + public function getIsFontSubsettingEnabled() + { + return $this->isFontSubsettingEnabled; + } + + /** + * @return boolean + */ + public function isFontSubsettingEnabled() + { + return $this->getIsFontSubsettingEnabled(); + } + + /** + * @param boolean $isHtml5ParserEnabled + * @return $this + */ + public function setIsHtml5ParserEnabled($isHtml5ParserEnabled) + { + $this->isHtml5ParserEnabled = $isHtml5ParserEnabled; + return $this; + } + + /** + * @return boolean + */ + public function getIsHtml5ParserEnabled() + { + return $this->isHtml5ParserEnabled; + } + + /** + * @return boolean + */ + public function isHtml5ParserEnabled() + { + return $this->getIsHtml5ParserEnabled(); + } + + /** + * @param boolean $isJavascriptEnabled + * @return $this + */ + public function setIsJavascriptEnabled($isJavascriptEnabled) + { + $this->isJavascriptEnabled = $isJavascriptEnabled; + return $this; + } + + /** + * @return boolean + */ + public function getIsJavascriptEnabled() + { + return $this->isJavascriptEnabled; + } + + /** + * @return boolean + */ + public function isJavascriptEnabled() + { + return $this->getIsJavascriptEnabled(); + } + + /** + * @param boolean $isPhpEnabled + * @return $this + */ + public function setIsPhpEnabled($isPhpEnabled) + { + $this->isPhpEnabled = $isPhpEnabled; + return $this; + } + + /** + * @return boolean + */ + public function getIsPhpEnabled() + { + return $this->isPhpEnabled; + } + + /** + * @return boolean + */ + public function isPhpEnabled() + { + return $this->getIsPhpEnabled(); + } + + /** + * @param boolean $isRemoteEnabled + * @return $this + */ + public function setIsRemoteEnabled($isRemoteEnabled) + { + $this->isRemoteEnabled = $isRemoteEnabled; + return $this; + } + + /** + * @return boolean + */ + public function getIsRemoteEnabled() + { + return $this->isRemoteEnabled; + } + + /** + * @return boolean + */ + public function isRemoteEnabled() + { + return $this->getIsRemoteEnabled(); + } + + /** + * @param string $logOutputFile + * @return $this + */ + public function setLogOutputFile($logOutputFile) + { + $this->logOutputFile = $logOutputFile; + return $this; + } + + /** + * @return string + */ + public function getLogOutputFile() + { + return $this->logOutputFile; + } + + /** + * @param string $tempDir + * @return $this + */ + public function setTempDir($tempDir) + { + $this->tempDir = $tempDir; + return $this; + } + + /** + * @return string + */ + public function getTempDir() + { + return $this->tempDir; + } + + /** + * @param string $rootDir + * @return $this + */ + public function setRootDir($rootDir) + { + $this->rootDir = $rootDir; + return $this; + } + + /** + * @return string + */ + public function getRootDir() + { + return $this->rootDir; + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/PhpEvaluator.php b/vendor/dompdf/dompdf/src/PhpEvaluator.php new file mode 100644 index 000000000..c7b877729 --- /dev/null +++ b/vendor/dompdf/dompdf/src/PhpEvaluator.php @@ -0,0 +1,55 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf; + +use Dompdf\Frame; + +/** + * Executes inline PHP code during the rendering process + * + * @package dompdf + */ +class PhpEvaluator +{ + + /** + * @var Canvas + */ + protected $_canvas; + + function __construct(Canvas $canvas) + { + $this->_canvas = $canvas; + } + + function evaluate($code, $vars = array()) + { + if (!$this->_canvas->get_dompdf()->get_option("enable_php")) { + return; + } + + // Set up some variables for the inline code + $pdf = $this->_canvas; + $fontMetrics = $pdf->get_dompdf()->getFontMetrics(); + $PAGE_NUM = $pdf->get_page_number(); + $PAGE_COUNT = $pdf->get_page_count(); + + // Override those variables if passed in + foreach ($vars as $k => $v) { + $$k = $v; + } + + //$code = html_entity_decode($code); // @todo uncomment this when tested + eval($code); + } + + function render(Frame $frame) + { + $this->evaluate($frame->get_node()->nodeValue); + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/Absolute.php b/vendor/dompdf/dompdf/src/Positioner/Absolute.php new file mode 100644 index 000000000..4feae8208 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/Absolute.php @@ -0,0 +1,123 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Positions absolutely positioned frames + */ +class Absolute extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + function position() + { + + $frame = $this->_frame; + $style = $frame->get_style(); + + $p = $frame->find_positionned_parent(); + + list($x, $y, $w, $h) = $frame->get_containing_block(); + + $top = $style->length_in_pt($style->top, $h); + $right = $style->length_in_pt($style->right, $w); + $bottom = $style->length_in_pt($style->bottom, $h); + $left = $style->length_in_pt($style->left, $w); + + if ($p && !($left === "auto" && $right === "auto")) { + // Get the parent's padding box (see http://www.w3.org/TR/CSS21/visuren.html#propdef-top) + list($x, $y, $w, $h) = $p->get_padding_box(); + } + + list($width, $height) = array($frame->get_margin_width(), $frame->get_margin_height()); + + $orig_style = $this->_frame->get_original_style(); + $orig_width = $orig_style->width; + $orig_height = $orig_style->height; + + /**************************** + * + * Width auto: + * ____________| left=auto | left=fixed | + * right=auto | A | B | + * right=fixed | C | D | + * + * Width fixed: + * ____________| left=auto | left=fixed | + * right=auto | E | F | + * right=fixed | G | H | + *****************************/ + + if ($left === "auto") { + if ($right === "auto") { + // A or E - Keep the frame at the same position + $x = $x + $frame->find_block_parent()->get_current_line_box()->w; + } else { + if ($orig_width === "auto") { + // C + $x += $w - $width - $right; + } else { + // G + $x += $w - $width - $right; + } + } + } else { + if ($right === "auto") { + // B or F + $x += $left; + } else { + if ($orig_width === "auto") { + // D - TODO change width + $x += $left; + } else { + // H - Everything is fixed: left + width win + $x += $left; + } + } + } + + // The same vertically + if ($top === "auto") { + if ($bottom === "auto") { + // A or E - Keep the frame at the same position + $y = $frame->find_block_parent()->get_current_line_box()->y; + } else { + if ($orig_height === "auto") { + // C + $y += $h - $height - $bottom; + } else { + // G + $y += $h - $height - $bottom; + } + } + } else { + if ($bottom === "auto") { + // B or F + $y += $top; + } else { + if ($orig_height === "auto") { + // D - TODO change height + $y += $top; + } else { + // H - Everything is fixed: top + height win + $y += $top; + } + } + } + + $frame->set_position($x, $y); + + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php b/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php new file mode 100644 index 000000000..1c19356f8 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/AbstractPositioner.php @@ -0,0 +1,52 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Base AbstractPositioner class + * + * Defines postioner interface + * + * @access private + * @package dompdf + */ +abstract class AbstractPositioner +{ + + /** + * @var \Dompdf\FrameDecorator\AbstractFrameDecorator + */ + protected $_frame; + + //........................................................................ + + function __construct(AbstractFrameDecorator $frame) + { + $this->_frame = $frame; + } + + //........................................................................ + + abstract function position(); + + function move($offset_x, $offset_y, $ignore_self = false) + { + list($x, $y) = $this->_frame->get_position(); + + if (!$ignore_self) { + $this->_frame->set_position($x + $offset_x, $y + $offset_y); + } + + foreach ($this->_frame->get_children() as $child) { + $child->move($offset_x, $offset_y); + } + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/Block.php b/vendor/dompdf/dompdf/src/Positioner/Block.php new file mode 100644 index 000000000..fdb418096 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/Block.php @@ -0,0 +1,63 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Positions block frames + * + * @access private + * @package dompdf + */ +class Block extends AbstractPositioner { + + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function position() + { + $frame = $this->_frame; + $style = $frame->get_style(); + $cb = $frame->get_containing_block(); + $p = $frame->find_block_parent(); + + if ($p) { + $float = $style->float; + + if (!$float || $float === "none") { + $p->add_line(true); + } + $y = $p->get_current_line_box()->y; + + } else { + $y = $cb["y"]; + } + + $x = $cb["x"]; + + // Relative positionning + if ($style->position === "relative") { + $top = $style->length_in_pt($style->top, $cb["h"]); + //$right = $style->length_in_pt($style->right, $cb["w"]); + //$bottom = $style->length_in_pt($style->bottom, $cb["h"]); + $left = $style->length_in_pt($style->left, $cb["w"]); + + $x += $left; + $y += $top; + } + + $frame->set_position($x, $y); + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/Fixed.php b/vendor/dompdf/dompdf/src/Positioner/Fixed.php new file mode 100644 index 000000000..018f66c57 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/Fixed.php @@ -0,0 +1,95 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Positions fixely positioned frames + */ +class Fixed extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + function position() + { + + $frame = $this->_frame; + $style = $frame->get_original_style(); + $root = $frame->get_root(); + $initialcb = $root->get_containing_block(); + $initialcb_style = $root->get_style(); + + $p = $frame->find_block_parent(); + if ($p) { + $p->add_line(); + } + + // Compute the margins of the @page style + $margin_top = $initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]); + $margin_right = $initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]); + $margin_bottom = $initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]); + $margin_left = $initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]); + + // The needed computed style of the element + $height = $style->length_in_pt($style->height, $initialcb["h"]); + $width = $style->length_in_pt($style->width, $initialcb["w"]); + + $top = $style->length_in_pt($style->top, $initialcb["h"]); + $right = $style->length_in_pt($style->right, $initialcb["w"]); + $bottom = $style->length_in_pt($style->bottom, $initialcb["h"]); + $left = $style->length_in_pt($style->left, $initialcb["w"]); + + $y = $margin_top; + if (isset($top)) { + $y = $top + $margin_top; + if ($top === "auto") { + $y = $margin_top; + if (isset($bottom) && $bottom !== "auto") { + $y = $initialcb["h"] - $bottom - $margin_bottom; + $margin_height = $this->_frame->get_margin_height(); + if ($margin_height !== "auto") { + $y -= $margin_height; + } else { + $y -= $height; + } + } + } + } + + $x = $margin_left; + if (isset($left)) { + $x = $left + $margin_left; + if ($left === "auto") { + $x = $margin_left; + if (isset($right) && $right !== "auto") { + $x = $initialcb["w"] - $right - $margin_right; + $margin_width = $this->_frame->get_margin_width(); + if ($margin_width !== "auto") { + $x -= $margin_width; + } else { + $x -= $width; + } + } + } + } + + $frame->set_position($x, $y); + + $children = $frame->get_children(); + foreach ($children as $child) { + $child->set_position($x, $y); + } + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/src/Positioner/Inline.php b/vendor/dompdf/dompdf/src/Positioner/Inline.php new file mode 100644 index 000000000..80eb677ba --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/Inline.php @@ -0,0 +1,82 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; +use Dompdf\FrameDecorator\Inline as InlineFrameDecorator; +use Dompdf\FrameDecorator\Block as BlockFrameDecorator; +use Dompdf\Exception; + +/** + * Positions inline frames + * + * @package dompdf + */ +class Inline extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function position() + { + /** + * Find our nearest block level parent and access its lines property. + * @var BlockFrameDecorator + */ + $p = $this->_frame->find_block_parent(); + + // Debugging code: + +// Helpers::pre_r("\nPositioning:"); +// Helpers::pre_r("Me: " . $this->_frame->get_node()->nodeName . " (" . spl_object_hash($this->_frame->get_node()) . ")"); +// Helpers::pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")"); + + // End debugging + + if (!$p) + throw new Exception("No block-level parent found. Not good."); + + $f = $this->_frame; + + $cb = $f->get_containing_block(); + $line = $p->get_current_line_box(); + + // Skip the page break if in a fixed position element + $is_fixed = false; + while ($f = $f->get_parent()) { + if ($f->get_style()->position === "fixed") { + $is_fixed = true; + break; + } + } + + $f = $this->_frame; + + if (!$is_fixed && $f->get_parent() && + $f->get_parent() instanceof InlineFrameDecorator && + $f->is_text_node() + ) { + + $min_max = $f->get_reflower()->get_min_max_width(); + + // If the frame doesn't fit in the current line, a line break occurs + if ($min_max["min"] > ($cb["w"] - $line->left - $line->w - $line->right)) { + $p->add_line(); + } + } + + $f->set_position($cb["x"] + $line->w, $line->y); + + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/ListBullet.php b/vendor/dompdf/dompdf/src/Positioner/ListBullet.php new file mode 100644 index 000000000..117c52182 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/ListBullet.php @@ -0,0 +1,81 @@ + + * @author Helmut Tischer + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Positions list bullets + * + * @package dompdf + */ +class ListBullet extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function position() + { + + // Bullets & friends are positioned an absolute distance to the left of + // the content edge of their parent element + $cb = $this->_frame->get_containing_block(); + + // Note: this differs from most frames in that we must position + // ourselves after determining our width + $x = $cb["x"] - $this->_frame->get_width(); + + $p = $this->_frame->find_block_parent(); + + $y = $p->get_current_line_box()->y; + + // This is a bit of a hack... + $n = $this->_frame->get_next_sibling(); + if ($n) { + $style = $n->get_style(); + $line_height = $style->length_in_pt($style->line_height, $style->get_font_size()); + $offset = $style->length_in_pt($line_height, $n->get_containing_block("h")) - $this->_frame->get_height(); + $y += $offset / 2; + } + + // Now the position is the left top of the block which should be marked with the bullet. + // We tried to find out the y of the start of the first text character within the block. + // But the top margin/padding does not fit, neither from this nor from the next sibling + // The "bit of a hack" above does not work also. + + // Instead let's position the bullet vertically centered to the block which should be marked. + // But for get_next_sibling() the get_containing_block is all zero, and for find_block_parent() + // the get_containing_block is paper width and the entire list as height. + + // if ($p) { + // //$cb = $n->get_containing_block(); + // $cb = $p->get_containing_block(); + // $y += $cb["h"]/2; + // print 'cb:'.$cb["x"].':'.$cb["y"].':'.$cb["w"].':'.$cb["h"].':'; + // } + + // Todo: + // For now give up on the above. Use Guesswork with font y-pos in the middle of the line spacing + + /*$style = $p->get_style(); + $font_size = $style->get_font_size(); + $line_height = $style->length_in_pt($style->line_height, $font_size); + $y += ($line_height - $font_size) / 2; */ + + //Position is x-end y-top of character position of the bullet. + $this->_frame->set_position($x, $y); + + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php b/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php new file mode 100644 index 000000000..6b27f1949 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/NullPositioner.php @@ -0,0 +1,31 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Dummy positioner + * + * @package dompdf + */ +class NullPositioner extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + function position() + { + return; + } + +} diff --git a/vendor/dompdf/dompdf/src/Positioner/TableCell.php b/vendor/dompdf/dompdf/src/Positioner/TableCell.php new file mode 100644 index 000000000..1fda93d54 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/TableCell.php @@ -0,0 +1,37 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; +use Dompdf\FrameDecorator\Table; + +/** + * Positions table cells + * + * @package dompdf + */ +class TableCell extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function position() + { + + $table = Table::find_parent_table($this->_frame); + $cellmap = $table->get_cellmap(); + $this->_frame->set_position($cellmap->get_frame_position($this->_frame)); + + } +} diff --git a/vendor/dompdf/dompdf/src/Positioner/TableRow.php b/vendor/dompdf/dompdf/src/Positioner/TableRow.php new file mode 100644 index 000000000..4dce49452 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Positioner/TableRow.php @@ -0,0 +1,43 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ + +namespace Dompdf\Positioner; + +use Dompdf\FrameDecorator\AbstractFrameDecorator; + +/** + * Positions table rows + * + * @package dompdf + */ +class TableRow extends AbstractPositioner +{ + + function __construct(AbstractFrameDecorator $frame) + { + parent::__construct($frame); + } + + //........................................................................ + + function position() + { + + $cb = $this->_frame->get_containing_block(); + $p = $this->_frame->get_prev_sibling(); + + if ($p) + $y = $p->get_position("y") + $p->get_margin_height(); + + else + $y = $cb["y"]; + + $this->_frame->set_position($cb["x"], $y); + + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer.php b/vendor/dompdf/dompdf/src/Renderer.php new file mode 100644 index 000000000..492a52364 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer.php @@ -0,0 +1,296 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf; + +use Dompdf\Renderer\AbstractRenderer; +use Dompdf\Renderer\Block; +use Dompdf\Renderer\Image; +use Dompdf\Renderer\ListBullet; +use Dompdf\Renderer\TableCell; +use Dompdf\Renderer\TableRowGroup; +use Dompdf\Renderer\Text; + +use Dompdf\Frame; + +/** + * Concrete renderer + * + * Instantiates several specific renderers in order to render any given frame. + * + * @package dompdf + */ +class Renderer extends AbstractRenderer +{ + + /** + * Array of renderers for specific frame types + * + * @var AbstractRenderer[] + */ + protected $_renderers; + + /** + * Cache of the callbacks array + * + * @var array + */ + private $_callbacks; + + /** + * Advance the canvas to the next page + */ + function new_page() + { + $this->_canvas->new_page(); + } + + /** + * Render frames recursively + * + * @param Frame $frame the frame to render + */ + function render(Frame $frame) + { + global $_dompdf_debug; + + if ($_dompdf_debug) { + echo $frame; + flush(); + } + + $style = $frame->get_style(); + + if (in_array($style->visibility, array("hidden", "collapse"))) { + return; + } + + $display = $style->display; + + // Starts the CSS transformation + if ($style->transform && is_array($style->transform)) { + $this->_canvas->save(); + list($x, $y) = $frame->get_padding_box(); + $origin = $style->transform_origin; + + foreach ($style->transform as $transform) { + list($function, $values) = $transform; + if ($function === "matrix") { + $function = "transform"; + } + + $values = array_map("floatval", $values); + $values[] = $x + $style->length_in_pt($origin[0], $style->width); + $values[] = $y + $style->length_in_pt($origin[1], $style->height); + + call_user_func_array(array($this->_canvas, $function), $values); + } + } + + switch ($display) { + + case "block": + case "list-item": + case "inline-block": + case "table": + case "inline-table": + $this->_render_frame("block", $frame); + break; + + case "inline": + if ($frame->is_text_node()) { + $this->_render_frame("text", $frame); + } else { + $this->_render_frame("inline", $frame); + } + break; + + case "table-cell": + $this->_render_frame("table-cell", $frame); + break; + + case "table-row-group": + case "table-header-group": + case "table-footer-group": + $this->_render_frame("table-row-group", $frame); + break; + + case "-dompdf-list-bullet": + $this->_render_frame("list-bullet", $frame); + break; + + case "-dompdf-image": + $this->_render_frame("image", $frame); + break; + + case "none": + $node = $frame->get_node(); + + if ($node->nodeName === "script") { + if ($node->getAttribute("type") === "text/php" || + $node->getAttribute("language") === "php" + ) { + // Evaluate embedded php scripts + $this->_render_frame("php", $frame); + } elseif ($node->getAttribute("type") === "text/javascript" || + $node->getAttribute("language") === "javascript" + ) { + // Insert JavaScript + $this->_render_frame("javascript", $frame); + } + } + + // Don't render children, so skip to next iter + return; + + default: + break; + + } + + // Starts the overflow: hidden box + if ($style->overflow === "hidden") { + list($x, $y, $w, $h) = $frame->get_padding_box(); + + // get border radii + $style = $frame->get_style(); + 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); + } else { + $this->_canvas->clipping_rectangle($x, $y, $w, $h); + } + } + + $stack = array(); + + foreach ($frame->get_children() as $child) { + // < 0 : nagative z-index + // = 0 : no z-index, no stacking context + // = 1 : stacking context without z-index + // > 1 : z-index + $child_style = $child->get_style(); + $child_z_index = $child_style->z_index; + $z_index = 0; + + if ($child_z_index !== "auto") { + $z_index = intval($child_z_index) + 1; + } elseif ($child_style->float !== "none" || $child->is_positionned()) { + $z_index = 1; + } + + $stack[$z_index][] = $child; + } + + ksort($stack); + + foreach ($stack as $by_index) { + foreach ($by_index as $child) { + $this->render($child); + } + } + + // Ends the overflow: hidden box + if ($style->overflow === "hidden") { + $this->_canvas->clipping_end(); + } + + if ($style->transform && is_array($style->transform)) { + $this->_canvas->restore(); + } + + // Check for end frame callback + $this->_check_callbacks("end_frame", $frame); + } + + /** + * Check for callbacks that need to be performed when a given event + * gets triggered on a frame + * + * @param string $event the type of event + * @param Frame $frame the frame that event is triggered on + */ + protected function _check_callbacks($event, $frame) + { + if (!isset($this->_callbacks)) { + $this->_callbacks = $this->_dompdf->get_callbacks(); + } + + if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) { + $info = array(0 => $this->_canvas, "canvas" => $this->_canvas, + 1 => $frame, "frame" => $frame); + $fs = $this->_callbacks[$event]; + foreach ($fs as $f) { + if (is_callable($f)) { + if (is_array($f)) { + $f[0]->{$f[1]}($info); + } else { + $f($info); + } + } + } + } + } + + /** + * Render a single frame + * + * Creates Renderer objects on demand + * + * @param string $type type of renderer to use + * @param Frame $frame the frame to render + */ + protected function _render_frame($type, $frame) + { + + if (!isset($this->_renderers[$type])) { + + switch ($type) { + case "block": + $this->_renderers[$type] = new Block($this->_dompdf); + break; + + case "inline": + $this->_renderers[$type] = new Renderer\Inline($this->_dompdf); + break; + + case "text": + $this->_renderers[$type] = new Text($this->_dompdf); + break; + + case "image": + $this->_renderers[$type] = new Image($this->_dompdf); + break; + + case "table-cell": + $this->_renderers[$type] = new TableCell($this->_dompdf); + break; + + case "table-row-group": + $this->_renderers[$type] = new TableRowGroup($this->_dompdf); + break; + + case "list-bullet": + $this->_renderers[$type] = new ListBullet($this->_dompdf); + break; + + case "php": + $this->_renderers[$type] = new PhpEvaluator($this->_canvas); + break; + + case "javascript": + $this->_renderers[$type] = new JavascriptEmbedder($this->_dompdf); + break; + + } + } + + $this->_renderers[$type]->render($frame); + + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php b/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php new file mode 100644 index 000000000..31b595fd4 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/AbstractRenderer.php @@ -0,0 +1,768 @@ + + * @author Helmut Tischer + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Adapter\CPDF; +use Dompdf\Css\Color; +use Dompdf\Css\Style; +use Dompdf\Dompdf; +use Dompdf\Helpers; +use Dompdf\Frame; +use Dompdf\Image\Cache; + +/** + * Base renderer class + * + * @package dompdf + */ +abstract class AbstractRenderer +{ + + /** + * Rendering backend + * + * @var \Dompdf\Canvas + */ + protected $_canvas; + + /** + * Current dompdf instance + * + * @var Dompdf + */ + protected $_dompdf; + + /** + * Class constructor + * + * @param Dompdf $dompdf The current dompdf instance + */ + function __construct(Dompdf $dompdf) + { + $this->_dompdf = $dompdf; + $this->_canvas = $dompdf->get_canvas(); + } + + /** + * Render a frame. + * + * Specialized in child classes + * + * @param Frame $frame The frame to render + */ + abstract function render(Frame $frame); + + //........................................................................ + + /** + * Render a background image over a rectangular area + * + * @param string $url The background image to load + * @param float $x The left edge of the rectangular area + * @param float $y The top edge of the rectangular area + * @param float $width The width of the rectangular area + * @param float $height The height of the rectangular area + * @param Style $style The associated Style object + * + * @throws \Exception + */ + protected function _background_image($url, $x, $y, $width, $height, $style) + { + if (!function_exists("imagecreatetruecolor")) { + throw new \Exception("The PHP GD extension is required, but is not installed."); + } + + $sheet = $style->get_stylesheet(); + + // Skip degenerate cases + if ($width == 0 || $height == 0) { + return; + } + + $box_width = $width; + $box_height = $height; + + //debugpng + if ($this->_dompdf->get_option("debugPng")) print '[_background_image ' . $url . ']'; + + list($img, $type, /*$msg*/) = Cache::resolve_url( + $url, + $sheet->get_protocol(), + $sheet->get_host(), + $sheet->get_base_path(), + $this->_dompdf + ); + + // Bail if the image is no good + if (Cache::is_broken($img)) { + return; + } + + //Try to optimize away reading and composing of same background multiple times + //Postponing read with imagecreatefrom ...() + //final composition parameters and name not known yet + //Therefore read dimension directly from file, instead of creating gd object first. + //$img_w = imagesx($src); $img_h = imagesy($src); + + list($img_w, $img_h) = Helpers::dompdf_getimagesize($img, $this->_dompdf->getHttpContext()); + if (!isset($img_w) || $img_w == 0 || !isset($img_h) || $img_h == 0) { + return; + } + + $repeat = $style->background_repeat; + $dpi = $this->_dompdf->get_option("dpi"); + + //Increase background resolution and dependent box size according to image resolution to be placed in + //Then image can be copied in without resize + $bg_width = round((float)($width * $dpi) / 72); + $bg_height = round((float)($height * $dpi) / 72); + + //Need %bg_x, $bg_y as background pos, where img starts, converted to pixel + + list($bg_x, $bg_y) = $style->background_position; + + if (Helpers::is_percent($bg_x)) { + // The point $bg_x % from the left edge of the image is placed + // $bg_x % from the left edge of the background rectangle + $p = ((float)$bg_x) / 100.0; + $x1 = $p * $img_w; + $x2 = $p * $bg_width; + + $bg_x = $x2 - $x1; + } else { + $bg_x = (float)($style->length_in_pt($bg_x) * $dpi) / 72; + } + + $bg_x = round($bg_x + $style->length_in_pt($style->border_left_width) * $dpi / 72); + + if (Helpers::is_percent($bg_y)) { + // The point $bg_y % from the left edge of the image is placed + // $bg_y % from the left edge of the background rectangle + $p = ((float)$bg_y) / 100.0; + $y1 = $p * $img_h; + $y2 = $p * $bg_height; + + $bg_y = $y2 - $y1; + } else { + $bg_y = (float)($style->length_in_pt($bg_y) * $dpi) / 72; + } + + $bg_y = round($bg_y + $style->length_in_pt($style->border_top_width) * $dpi / 72); + + //clip background to the image area on partial repeat. Nothing to do if img off area + //On repeat, normalize start position to the tile at immediate left/top or 0/0 of area + //On no repeat with positive offset: move size/start to have offset==0 + //Handle x/y Dimensions separately + + if ($repeat !== "repeat" && $repeat !== "repeat-x") { + //No repeat x + if ($bg_x < 0) { + $bg_width = $img_w + $bg_x; + } else { + $x += ($bg_x * 72) / $dpi; + $bg_width = $bg_width - $bg_x; + if ($bg_width > $img_w) { + $bg_width = $img_w; + } + $bg_x = 0; + } + + if ($bg_width <= 0) { + return; + } + + $width = (float)($bg_width * 72) / $dpi; + } else { + //repeat x + if ($bg_x < 0) { + $bg_x = -((-$bg_x) % $img_w); + } else { + $bg_x = $bg_x % $img_w; + if ($bg_x > 0) { + $bg_x -= $img_w; + } + } + } + + if ($repeat !== "repeat" && $repeat !== "repeat-y") { + //no repeat y + if ($bg_y < 0) { + $bg_height = $img_h + $bg_y; + } else { + $y += ($bg_y * 72) / $dpi; + $bg_height = $bg_height - $bg_y; + if ($bg_height > $img_h) { + $bg_height = $img_h; + } + $bg_y = 0; + } + if ($bg_height <= 0) { + return; + } + $height = (float)($bg_height * 72) / $dpi; + } else { + //repeat y + if ($bg_y < 0) { + $bg_y = -((-$bg_y) % $img_h); + } else { + $bg_y = $bg_y % $img_h; + if ($bg_y > 0) { + $bg_y -= $img_h; + } + } + } + + //Optimization, if repeat has no effect + if ($repeat === "repeat" && $bg_y <= 0 && $img_h + $bg_y >= $bg_height) { + $repeat = "repeat-x"; + } + + if ($repeat === "repeat" && $bg_x <= 0 && $img_w + $bg_x >= $bg_width) { + $repeat = "repeat-y"; + } + + if (($repeat === "repeat-x" && $bg_x <= 0 && $img_w + $bg_x >= $bg_width) || + ($repeat === "repeat-y" && $bg_y <= 0 && $img_h + $bg_y >= $bg_height) + ) { + $repeat = "no-repeat"; + } + + //Use filename as indicator only + //different names for different variants to have different copies in the pdf + //This is not dependent of background color of box! .'_'.(is_array($bg_color) ? $bg_color["hex"] : $bg_color) + //Note: Here, bg_* are the start values, not end values after going through the tile loops! + + $filedummy = $img; + + $is_png = false; + $filedummy .= '_' . $bg_width . '_' . $bg_height . '_' . $bg_x . '_' . $bg_y . '_' . $repeat; + + //Optimization to avoid multiple times rendering the same image. + //If check functions are existing and identical image already cached, + //then skip creation of duplicate, because it is not needed by addImagePng + if ($this->_canvas instanceof CPDF && + $this->_canvas->get_cpdf()->image_iscached($filedummy) + ) { + $bg = null; + } else { + + // Create a new image to fit over the background rectangle + $bg = imagecreatetruecolor($bg_width, $bg_height); + + switch (strtolower($type)) { + case "png": + $is_png = true; + imagesavealpha($bg, true); + imagealphablending($bg, false); + $src = imagecreatefrompng($img); + break; + + case "jpeg": + $src = imagecreatefromjpeg($img); + break; + + case "gif": + $src = imagecreatefromgif($img); + break; + + case "bmp": + $src = Helpers::imagecreatefrombmp($img); + break; + + default: + return; // Unsupported image type + } + + if ($src == null) { + return; + } + + //Background color if box is not relevant here + //Non transparent image: box clipped to real size. Background non relevant. + //Transparent image: The image controls the transparency and lets shine through whatever background. + //However on transparent image preset the composed image with the transparency color, + //to keep the transparency when copying over the non transparent parts of the tiles. + $ti = imagecolortransparent($src); + + if ($ti >= 0) { + $tc = imagecolorsforindex($src, $ti); + $ti = imagecolorallocate($bg, $tc['red'], $tc['green'], $tc['blue']); + imagefill($bg, 0, 0, $ti); + imagecolortransparent($bg, $ti); + } + + //This has only an effect for the non repeatable dimension. + //compute start of src and dest coordinates of the single copy + if ($bg_x < 0) { + $dst_x = 0; + $src_x = -$bg_x; + } else { + $src_x = 0; + $dst_x = $bg_x; + } + + if ($bg_y < 0) { + $dst_y = 0; + $src_y = -$bg_y; + } else { + $src_y = 0; + $dst_y = $bg_y; + } + + //For historical reasons exchange meanings of variables: + //start_* will be the start values, while bg_* will be the temporary start values in the loops + $start_x = $bg_x; + $start_y = $bg_y; + + // Copy regions from the source image to the background + if ($repeat === "no-repeat") { + + // Simply place the image on the background + imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $img_h); + + } else if ($repeat === "repeat-x") { + + for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) { + if ($bg_x < 0) { + $dst_x = 0; + $src_x = -$bg_x; + $w = $img_w + $bg_x; + } else { + $dst_x = $bg_x; + $src_x = 0; + $w = $img_w; + } + imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $img_h); + } + + } else if ($repeat === "repeat-y") { + + for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) { + if ($bg_y < 0) { + $dst_y = 0; + $src_y = -$bg_y; + $h = $img_h + $bg_y; + } else { + $dst_y = $bg_y; + $src_y = 0; + $h = $img_h; + } + imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $img_w, $h); + + } + + } else if ($repeat === "repeat") { + + for ($bg_y = $start_y; $bg_y < $bg_height; $bg_y += $img_h) { + for ($bg_x = $start_x; $bg_x < $bg_width; $bg_x += $img_w) { + + if ($bg_x < 0) { + $dst_x = 0; + $src_x = -$bg_x; + $w = $img_w + $bg_x; + } else { + $dst_x = $bg_x; + $src_x = 0; + $w = $img_w; + } + + if ($bg_y < 0) { + $dst_y = 0; + $src_y = -$bg_y; + $h = $img_h + $bg_y; + } else { + $dst_y = $bg_y; + $src_y = 0; + $h = $img_h; + } + imagecopy($bg, $src, $dst_x, $dst_y, $src_x, $src_y, $w, $h); + } + } + } else { + print 'Unknown repeat!'; + } + + imagedestroy($src); + + } /* End optimize away creation of duplicates */ + + $this->_canvas->clipping_rectangle($x, $y, $box_width, $box_height); + + //img: image url string + //img_w, img_h: original image size in px + //width, height: box size in pt + //bg_width, bg_height: box size in px + //x, y: left/top edge of box on page in pt + //start_x, start_y: placement of image relative to pattern + //$repeat: repeat mode + //$bg: GD object of result image + //$src: GD object of original image + //When using cpdf and optimization to direct png creation from gd object is available, + //don't create temp file, but place gd object directly into the pdf + if (!$is_png && $this->_canvas instanceof CPDF) { + // Note: CPDF_Adapter image converts y position + $this->_canvas->get_cpdf()->addImagePng($filedummy, $x, $this->_canvas->get_height() - $y - $height, $width, $height, $bg); + } else { + $tmp_dir = $this->_dompdf->get_option("temp_dir"); + $tmp_name = tempnam($tmp_dir, "bg_dompdf_img_"); + @unlink($tmp_name); + $tmp_file = "$tmp_name.png"; + + //debugpng + if ($this->_dompdf->get_option("debugPng")) print '[_background_image ' . $tmp_file . ']'; + + imagepng($bg, $tmp_file); + $this->_canvas->image($tmp_file, $x, $y, $width, $height); + imagedestroy($bg); + + //debugpng + if ($this->_dompdf->get_option("debugPng")) print '[_background_image unlink ' . $tmp_file . ']'; + + if (!$this->_dompdf->get_option("debugKeepTemp")) { + unlink($tmp_file); + } + } + + $this->_canvas->clipping_end(); + } + + protected function _get_dash_pattern($style, $width) + { + $pattern = array(); + + switch ($style) { + default: + /*case "solid": + case "double": + case "groove": + case "inset": + case "outset": + case "ridge":*/ + case "none": + break; + + case "dotted": + if ($width <= 1) + $pattern = array($width, $width * 2); + else + $pattern = array($width); + break; + + case "dashed": + $pattern = array(3 * $width); + break; + } + + return $pattern; + } + + protected function _border_none($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + return; + } + + protected function _border_hidden($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + return; + } + + // Border rendering functions + + protected function _border_dotted($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dotted", $r1, $r2); + } + + + protected function _border_dashed($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "dashed", $r1, $r2); + } + + + protected function _border_solid($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + // TODO: Solve rendering where one corner is beveled (radius == 0), one corner isn't. + if ($corner_style !== "bevel" || $r1 > 0 || $r2 > 0) { + // do it the simple way + $this->_border_line($x, $y, $length, $color, $widths, $side, $corner_style, "solid", $r1, $r2); + return; + } + + list($top, $right, $bottom, $left) = $widths; + + // All this polygon business is for beveled corners... + switch ($side) { + case "top": + $points = array($x, $y, + $x + $length, $y, + $x + $length - $right, $y + $top, + $x + $left, $y + $top); + $this->_canvas->polygon($points, $color, null, null, true); + break; + + case "bottom": + $points = array($x, $y, + $x + $length, $y, + $x + $length - $right, $y - $bottom, + $x + $left, $y - $bottom); + $this->_canvas->polygon($points, $color, null, null, true); + break; + + case "left": + $points = array($x, $y, + $x, $y + $length, + $x + $left, $y + $length - $bottom, + $x + $left, $y + $top); + $this->_canvas->polygon($points, $color, null, null, true); + break; + + case "right": + $points = array($x, $y, + $x, $y + $length, + $x - $right, $y + $length - $bottom, + $x - $right, $y + $top); + $this->_canvas->polygon($points, $color, null, null, true); + break; + + default: + return; + } + } + + protected function _apply_ratio($side, $ratio, $top, $right, $bottom, $left, &$x, &$y, &$length, &$r1, &$r2) + { + switch ($side) { + + case "top": + $r1 -= $left * $ratio; + $r2 -= $right * $ratio; + $x += $left * $ratio; + $y += $top * $ratio; + $length -= $left * $ratio + $right * $ratio; + break; + + case "bottom": + $r1 -= $right * $ratio; + $r2 -= $left * $ratio; + $x += $left * $ratio; + $y -= $bottom * $ratio; + $length -= $left * $ratio + $right * $ratio; + break; + + case "left": + $r1 -= $top * $ratio; + $r2 -= $bottom * $ratio; + $x += $left * $ratio; + $y += $top * $ratio; + $length -= $top * $ratio + $bottom * $ratio; + break; + + case "right": + $r1 -= $bottom * $ratio; + $r2 -= $top * $ratio; + $x -= $right * $ratio; + $y += $top * $ratio; + $length -= $top * $ratio + $bottom * $ratio; + break; + + default: + return; + + } + } + + protected function _border_double($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + list($top, $right, $bottom, $left) = $widths; + + $third_widths = array($top / 3, $right / 3, $bottom / 3, $left / 3); + + // draw the outer border + $this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2); + + $this->_apply_ratio($side, 2 / 3, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); + + $this->_border_solid($x, $y, $length, $color, $third_widths, $side, $corner_style, $r1, $r2); + } + + protected function _border_groove($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + list($top, $right, $bottom, $left) = $widths; + + $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2); + + $this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); + + $this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); + + $this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); + + } + + protected function _border_ridge($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + list($top, $right, $bottom, $left) = $widths; + + $half_widths = array($top / 2, $right / 2, $bottom / 2, $left / 2); + + $this->_border_outset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); + + $this->_apply_ratio($side, 0.5, $top, $right, $bottom, $left, $x, $y, $length, $r1, $r2); + + $this->_border_inset($x, $y, $length, $color, $half_widths, $side, $corner_style, $r1, $r2); + + } + + protected function _tint($c) + { + if (!is_numeric($c)) + return $c; + + return min(1, $c + 0.16); + } + + protected function _shade($c) + { + if (!is_numeric($c)) + return $c; + + return max(0, $c - 0.33); + } + + protected function _border_inset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + switch ($side) { + case "top": + case "left": + $shade = array_map(array($this, "_shade"), $color); + $this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2); + break; + + case "bottom": + case "right": + $tint = array_map(array($this, "_tint"), $color); + $this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2); + break; + + default: + return; + } + } + + protected function _border_outset($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $r1 = 0, $r2 = 0) + { + switch ($side) { + case "top": + case "left": + $tint = array_map(array($this, "_tint"), $color); + $this->_border_solid($x, $y, $length, $tint, $widths, $side, $corner_style, $r1, $r2); + break; + + case "bottom": + case "right": + $shade = array_map(array($this, "_shade"), $color); + $this->_border_solid($x, $y, $length, $shade, $widths, $side, $corner_style, $r1, $r2); + break; + + default: + return; + } + } + + // Draws a solid, dotted, or dashed line, observing the border radius + protected function _border_line($x, $y, $length, $color, $widths, $side, $corner_style = "bevel", $pattern_name, $r1 = 0, $r2 = 0) + { + list($top, $right, $bottom, $left) = $widths; + + $width = $$side; + $pattern = $this->_get_dash_pattern($pattern_name, $width); + + $half_width = $width / 2; + $r1 -= $half_width; + $r2 -= $half_width; + $adjust = $r1 / 80; + $length -= $width; + + switch ($side) { + case "top": + $x += $half_width; + $y += $half_width; + + if ($r1 > 0) { + $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 90 - $adjust, 135 + $adjust, $color, $width, $pattern); + } + + $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern); + + if ($r2 > 0) { + $this->_canvas->arc($x + $length - $r2, $y + $r2, $r2, $r2, 45 - $adjust, 90 + $adjust, $color, $width, $pattern); + } + break; + + case "bottom": + $x += $half_width; + $y -= $half_width; + + if ($r1 > 0) { + $this->_canvas->arc($x + $r1, $y - $r1, $r1, $r1, 225 - $adjust, 270 + $adjust, $color, $width, $pattern); + } + + $this->_canvas->line($x + $r1, $y, $x + $length - $r2, $y, $color, $width, $pattern); + + if ($r2 > 0) { + $this->_canvas->arc($x + $length - $r2, $y - $r2, $r2, $r2, 270 - $adjust, 315 + $adjust, $color, $width, $pattern); + } + break; + + case "left": + $y += $half_width; + $x += $half_width; + + if ($r1 > 0) { + $this->_canvas->arc($x + $r1, $y + $r1, $r1, $r1, 135 - $adjust, 180 + $adjust, $color, $width, $pattern); + } + + $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern); + + if ($r2 > 0) { + $this->_canvas->arc($x + $r2, $y + $length - $r2, $r2, $r2, 180 - $adjust, 225 + $adjust, $color, $width, $pattern); + } + break; + + case "right": + $y += $half_width; + $x -= $half_width; + + if ($r1 > 0) { + $this->_canvas->arc($x - $r1, $y + $r1, $r1, $r1, 0 - $adjust, 45 + $adjust, $color, $width, $pattern); + } + + $this->_canvas->line($x, $y + $r1, $x, $y + $length - $r2, $color, $width, $pattern); + + if ($r2 > 0) { + $this->_canvas->arc($x - $r2, $y + $length - $r2, $r2, $r2, 315 - $adjust, 360 + $adjust, $color, $width, $pattern); + } + break; + } + } + + protected function _set_opacity($opacity) + { + if (is_numeric($opacity) && $opacity <= 1.0 && $opacity >= 0.0) { + $this->_canvas->set_opacity($opacity); + } + } + + protected function _debug_layout($box, $color = "red", $style = array()) + { + $this->_canvas->rectangle($box[0], $box[1], $box[2], $box[3], Color::parse($color), 0.1, $style); + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/Block.php b/vendor/dompdf/dompdf/src/Renderer/Block.php new file mode 100644 index 000000000..d16212307 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/Block.php @@ -0,0 +1,240 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\AbstractFrameDecorator; +use Dompdf\Helpers; + +/** + * Renders block frames + * + * @package dompdf + */ +class Block extends AbstractRenderer +{ + + //........................................................................ + + 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->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutBlocks")) { + $this->_debug_layout($frame->get_border_box(), "red"); + if ($this->_dompdf->get_option("debugLayoutPaddingBox")) { + $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5)); + } + } + + if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutLines") && $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"); + } + } + } + + protected function _render_border(AbstractFrameDecorator $frame, $border_box = null, $corner_style = "bevel") + { + $style = $frame->get_style(); + $bp = $style->get_border_properties(); + + if (empty($border_box)) { + $border_box = $frame->get_border_box(); + } + + // find the radius + $radius = $style->get_computed_border_radius($border_box[2], $border_box[3]); // w, h + + // Short-cut: If all the borders are "solid" with the same color and style, and no radius, we'd better draw a rectangle + if ( + in_array($bp["top"]["style"], array("solid", "dashed", "dotted")) && + $bp["top"] == $bp["right"] && + $bp["right"] == $bp["bottom"] && + $bp["bottom"] == $bp["left"] && + array_sum($radius) == 0 + ) { + $props = $bp["top"]; + if ($props["color"] === "transparent" || $props["width"] <= 0) return; + + list($x, $y, $w, $h) = $border_box; + $width = $style->length_in_pt($props["width"]); + $pattern = $this->_get_dash_pattern($props["style"], $width); + $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern); + return; + } + + // Do it the long way + $widths = array($style->length_in_pt($bp["top"]["width"]), + $style->length_in_pt($bp["right"]["width"]), + $style->length_in_pt($bp["bottom"]["width"]), + $style->length_in_pt($bp["left"]["width"])); + + foreach ($bp as $side => $props) { + list($x, $y, $w, $h) = $border_box; + $length = 0; + $r1 = 0; + $r2 = 0; + + if (!$props["style"] || + $props["style"] === "none" || + $props["width"] <= 0 || + $props["color"] == "transparent" + ) + continue; + + switch ($side) { + case "top": + $length = $w; + $r1 = $radius["top-left"]; + $r2 = $radius["top-right"]; + break; + + case "bottom": + $length = $w; + $y += $h; + $r1 = $radius["bottom-left"]; + $r2 = $radius["bottom-right"]; + break; + + case "left": + $length = $h; + $r1 = $radius["top-left"]; + $r2 = $radius["bottom-left"]; + break; + + case "right": + $length = $h; + $x += $w; + $r1 = $radius["top-right"]; + $r2 = $radius["bottom-right"]; + break; + default: + break; + } + $method = "_border_" . $props["style"]; + + // draw rounded corners + $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2); + } + } + + protected function _render_outline(AbstractFrameDecorator $frame, $border_box = null, $corner_style = "bevel") + { + $style = $frame->get_style(); + + $props = array( + "width" => $style->outline_width, + "style" => $style->outline_style, + "color" => $style->outline_color, + ); + + if (!$props["style"] || $props["style"] === "none" || $props["width"] <= 0) + return; + + if (empty($border_box)) { + $border_box = $frame->get_border_box(); + } + + $offset = $style->length_in_pt($props["width"]); + $pattern = $this->_get_dash_pattern($props["style"], $offset); + + // If the outline style is "solid" we'd better draw a rectangle + if (in_array($props["style"], array("solid", "dashed", "dotted"))) { + $border_box[0] -= $offset / 2; + $border_box[1] -= $offset / 2; + $border_box[2] += $offset; + $border_box[3] += $offset; + + list($x, $y, $w, $h) = $border_box; + $this->_canvas->rectangle($x, $y, $w, $h, $props["color"], $offset, $pattern); + return; + } + + $border_box[0] -= $offset; + $border_box[1] -= $offset; + $border_box[2] += $offset * 2; + $border_box[3] += $offset * 2; + + $method = "_border_" . $props["style"]; + $widths = array_fill(0, 4, $props["width"]); + $sides = array("top", "right", "left", "bottom"); + $length = 0; + + foreach ($sides as $side) { + list($x, $y, $w, $h) = $border_box; + + switch ($side) { + case "top": + $length = $w; + break; + + case "bottom": + $length = $w; + $y += $h; + break; + + case "left": + $length = $h; + break; + + case "right": + $length = $h; + $x += $w; + break; + default: + break; + } + + $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style); + } + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/Image.php b/vendor/dompdf/dompdf/src/Renderer/Image.php new file mode 100644 index 000000000..1630794a4 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/Image.php @@ -0,0 +1,125 @@ + + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Frame; +use Dompdf\Image\Cache; + +/** + * Image renderer + * + * @access private + * @package dompdf + */ +class Image extends Block +{ + + 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->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutBlocks")) { + $this->_debug_layout($frame->get_border_box(), "blue"); + if ($this->_dompdf->get_option("debugLayoutPaddingBox")) { + $this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5)); + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/Inline.php b/vendor/dompdf/dompdf/src/Renderer/Inline.php new file mode 100644 index 000000000..a7c8fd107 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/Inline.php @@ -0,0 +1,198 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Frame; +use Dompdf\Helpers; + +/** + * Renders inline frames + * + * @access private + * @package dompdf + */ +class Inline extends AbstractRenderer +{ + + //........................................................................ + + function render(Frame $frame) + { + $style = $frame->get_style(); + + if (!$frame->get_first_child()) + return; // No children, no service + + // Draw the left border if applicable + $bp = $style->get_border_properties(); + $widths = array($style->length_in_pt($bp["top"]["width"]), + $style->length_in_pt($bp["right"]["width"]), + $style->length_in_pt($bp["bottom"]["width"]), + $style->length_in_pt($bp["left"]["width"])); + + // Draw the background & border behind each child. To do this we need + // to figure out just how much space each child takes: + list($x, $y) = $frame->get_first_child()->get_position(); + $w = null; + $h = 0; +// $x += $widths[3]; +// $y += $widths[0]; + + $this->_set_opacity($frame->get_opacity($style->opacity)); + + $first_row = true; + + foreach ($frame->get_children() as $child) { + list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box(); + + if (!is_null($w) && $child_x < $x + $w) { + //This branch seems to be supposed to being called on the first part + //of an inline html element, and the part after the if clause for the + //parts after a line break. + //But because $w initially mostly is 0, and gets updated only on the next + //round, this seem to be never executed and the common close always. + + // The next child is on another line. Draw the background & + // borders on this line. + + // Background: + 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 this is the first row, draw the left border + if ($first_row) { + + if ($bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $bp["left"]["width"] > 0) { + $method = "_border_" . $bp["left"]["style"]; + $this->$method($x, $y, $h + $widths[0] + $widths[2], $bp["left"]["color"], $widths, "left"); + } + $first_row = false; + } + + // Draw the top & bottom borders + if ($bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $bp["top"]["width"] > 0) { + $method = "_border_" . $bp["top"]["style"]; + $this->$method($x, $y, $w + $widths[1] + $widths[3], $bp["top"]["color"], $widths, "top"); + } + + if ($bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $bp["bottom"]["width"] > 0) { + $method = "_border_" . $bp["bottom"]["style"]; + $this->$method($x, $y + $h + $widths[0] + $widths[2], $w + $widths[1] + $widths[3], $bp["bottom"]["color"], $widths, "bottom"); + } + + // Handle anchors & links + $link_node = null; + if ($frame->get_node()->nodeName === "a") { + $link_node = $frame->get_node(); + } else if ($frame->get_parent()->get_node()->nodeName === "a") { + $link_node = $frame->get_parent()->get_node(); + } + + if ($link_node && $href = $link_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); + } + + $x = $child_x; + $y = $child_y; + $w = $child_w; + $h = $child_h; + continue; + } + + if (is_null($w)) + $w = $child_w; + else + $w += $child_w; + + $h = max($h, $child_h); + + if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutInline")) { + $this->_debug_layout($child->get_border_box(), "blue"); + if ($this->_dompdf->get_option("debugLayoutPaddingBox")) { + $this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5)); + } + } + } + + + // Handle the last child + if (($bg = $style->background_color) !== "transparent") + $this->_canvas->filled_rectangle($x + $widths[3], $y + $widths[0], $w, $h, $bg); + + //On continuation lines (after line break) of inline elements, the style got copied. + //But a non repeatable background image should not be repeated on the next line. + //But removing the background image above has never an effect, and removing it below + //removes it always, even on the initial line. + //Need to handle it elsewhere, e.g. on certain ...clone()... usages. + // Repeat not given: default is Style::__construct + // ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ... + //different position? $this->_background_image($url, $x, $y, $w, $h, $style); + if (($url = $style->background_image) && $url !== "none") + $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style); + + // Add the border widths + $w += $widths[1] + $widths[3]; + $h += $widths[0] + $widths[2]; + + // make sure the border and background start inside the left margin + $left_margin = $style->length_in_pt($style->margin_left); + $x += $left_margin; + + // If this is the first row, draw the left border too + if ($first_row && $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0) { + $method = "_border_" . $bp["left"]["style"]; + $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left"); + } + + // Draw the top & bottom borders + if ($bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0) { + $method = "_border_" . $bp["top"]["style"]; + $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top"); + } + + if ($bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0) { + $method = "_border_" . $bp["bottom"]["style"]; + $this->$method($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom"); + } + + // Helpers::var_dump(get_class($frame->get_next_sibling())); + // $last_row = get_class($frame->get_next_sibling()) !== 'Inline'; + // Draw the right border if this is the last row + if ($bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0) { + $method = "_border_" . $bp["right"]["style"]; + $this->$method($x + $w, $y, $h, $bp["right"]["color"], $widths, "right"); + } + + // Only two levels of links frames + $link_node = null; + if ($frame->get_node()->nodeName === "a") { + $link_node = $frame->get_node(); + + if (($name = $link_node->getAttribute("name")) || ($name = $link_node->getAttribute("id"))) { + $this->_canvas->add_named_dest($name); + } + } + + if ($frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a") { + $link_node = $frame->get_parent()->get_node(); + } + + // Handle anchors & links + if ($link_node) { + if ($href = $link_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); + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/ListBullet.php b/vendor/dompdf/dompdf/src/Renderer/ListBullet.php new file mode 100644 index 000000000..c7fcc89b5 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/ListBullet.php @@ -0,0 +1,248 @@ + + * @author Helmut Tischer + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Helpers; +use Dompdf\FontMetrics; +use Dompdf\Frame; +use Dompdf\Image\Cache; +use Dompdf\FrameDecorator\ListBullet as ListBulletFrameDecorator; + +/** + * Renders list bullets + * + * @access private + * @package dompdf + */ +class ListBullet extends AbstractRenderer +{ + static function get_counter_chars($type) + { + static $cache = array(); + + if (isset($cache[$type])) { + return $cache[$type]; + } + + $uppercase = false; + $text = ""; + + switch ($type) { + case "decimal-leading-zero": + case "decimal": + case "1": + return "0123456789"; + + case "upper-alpha": + case "upper-latin": + case "A": + $uppercase = true; + case "lower-alpha": + case "lower-latin": + case "a": + $text = "abcdefghijklmnopqrstuvwxyz"; + break; + + case "upper-roman": + case "I": + $uppercase = true; + case "lower-roman": + case "i": + $text = "ivxlcdm"; + break; + + case "lower-greek": + for ($i = 0; $i < 24; $i++) { + $text .= Helpers::unichr($i + 944); + } + break; + } + + if ($uppercase) { + $text = strtoupper($text); + } + + return $cache[$type] = "$text."; + } + + /** + * @param integer $n + * @param string $type + * @param integer $pad + * + * @return string + */ + private function make_counter($n, $type, $pad = null) + { + $n = intval($n); + $text = ""; + $uppercase = false; + + switch ($type) { + case "decimal-leading-zero": + case "decimal": + case "1": + if ($pad) + $text = str_pad($n, $pad, "0", STR_PAD_LEFT); + else + $text = $n; + break; + + case "upper-alpha": + case "upper-latin": + case "A": + $uppercase = true; + case "lower-alpha": + case "lower-latin": + case "a": + $text = chr(($n % 26) + ord('a') - 1); + break; + + case "upper-roman": + case "I": + $uppercase = true; + case "lower-roman": + case "i": + $text = Helpers::dec2roman($n); + break; + + case "lower-greek": + $text = Helpers::unichr($n + 944); + break; + } + + if ($uppercase) { + $text = strtoupper($text); + } + + return "$text."; + } + + 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->get_option("dpi"); + $w = ((float)rtrim($width, "px") * 72) / $dpi; + $h = ((float)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 /*-ListBulletFrameDecorator::BULLET_THICKNESS*/)) / 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 + 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; + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/TableCell.php b/vendor/dompdf/dompdf/src/Renderer/TableCell.php new file mode 100644 index 000000000..541b9cd7c --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/TableCell.php @@ -0,0 +1,160 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Frame; +use Dompdf\FrameDecorator\Table; + +/** + * Renders table cells + * + * @package dompdf + */ +class TableCell extends Block +{ + + //........................................................................ + + function render(Frame $frame) + { + $style = $frame->get_style(); + + if (trim($frame->get_node()->nodeValue) === "" && $style->empty_cells === "hide") { + return; + } + + $this->_set_opacity($frame->get_opacity($style->opacity)); + list($x, $y, $w, $h) = $frame->get_border_box(); + + // Draw our background, border and content + 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); + } + + $table = Table::find_parent_table($frame); + + if ($table->get_style()->border_collapse !== "collapse") { + $this->_render_border($frame); + $this->_render_outline($frame); + return; + } + + // The collapsed case is slightly complicated... + // @todo Add support for outlines here + + $cellmap = $table->get_cellmap(); + $cells = $cellmap->get_spanned_cells($frame); + $num_rows = $cellmap->get_num_rows(); + $num_cols = $cellmap->get_num_cols(); + + // Determine the top row spanned by this cell + $i = $cells["rows"][0]; + $top_row = $cellmap->get_row($i); + + // Determine if this cell borders on the bottom of the table. If so, + // then we draw its bottom border. Otherwise the next row down will + // draw its top border instead. + if (in_array($num_rows - 1, $cells["rows"])) { + $draw_bottom = true; + $bottom_row = $cellmap->get_row($num_rows - 1); + } else + $draw_bottom = false; + + + // Draw the horizontal borders + foreach ($cells["columns"] as $j) { + $bp = $cellmap->get_border_properties($i, $j); + + $y = $top_row["y"] - $bp["top"]["width"] / 2; + + $col = $cellmap->get_column($j); + $x = $col["x"] - $bp["left"]["width"] / 2; + $w = $col["used-width"] + ($bp["left"]["width"] + $bp["right"]["width"]) / 2; + + if ($bp["top"]["style"] !== "none" && $bp["top"]["width"] > 0) { + $widths = array($bp["top"]["width"], + $bp["right"]["width"], + $bp["bottom"]["width"], + $bp["left"]["width"]); + $method = "_border_" . $bp["top"]["style"]; + $this->$method($x, $y, $w, $bp["top"]["color"], $widths, "top", "square"); + } + + if ($draw_bottom) { + $bp = $cellmap->get_border_properties($num_rows - 1, $j); + if ($bp["bottom"]["style"] === "none" || $bp["bottom"]["width"] <= 0) + continue; + + $y = $bottom_row["y"] + $bottom_row["height"] + $bp["bottom"]["width"] / 2; + + $widths = array($bp["top"]["width"], + $bp["right"]["width"], + $bp["bottom"]["width"], + $bp["left"]["width"]); + $method = "_border_" . $bp["bottom"]["style"]; + $this->$method($x, $y, $w, $bp["bottom"]["color"], $widths, "bottom", "square"); + + } + } + + $j = $cells["columns"][0]; + + $left_col = $cellmap->get_column($j); + + if (in_array($num_cols - 1, $cells["columns"])) { + $draw_right = true; + $right_col = $cellmap->get_column($num_cols - 1); + } else + $draw_right = false; + + // Draw the vertical borders + foreach ($cells["rows"] as $i) { + $bp = $cellmap->get_border_properties($i, $j); + + $x = $left_col["x"] - $bp["left"]["width"] / 2; + + $row = $cellmap->get_row($i); + + $y = $row["y"] - $bp["top"]["width"] / 2; + $h = $row["height"] + ($bp["top"]["width"] + $bp["bottom"]["width"]) / 2; + + if ($bp["left"]["style"] !== "none" && $bp["left"]["width"] > 0) { + + $widths = array($bp["top"]["width"], + $bp["right"]["width"], + $bp["bottom"]["width"], + $bp["left"]["width"]); + + $method = "_border_" . $bp["left"]["style"]; + $this->$method($x, $y, $h, $bp["left"]["color"], $widths, "left", "square"); + } + + if ($draw_right) { + $bp = $cellmap->get_border_properties($i, $num_cols - 1); + if ($bp["right"]["style"] === "none" || $bp["right"]["width"] <= 0) + continue; + + $x = $right_col["x"] + $right_col["used-width"] + $bp["right"]["width"] / 2; + + $widths = array($bp["top"]["width"], + $bp["right"]["width"], + $bp["bottom"]["width"], + $bp["left"]["width"]); + + $method = "_border_" . $bp["right"]["style"]; + $this->$method($x, $y, $h, $bp["right"]["color"], $widths, "right", "square"); + + } + } + + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php b/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php new file mode 100644 index 000000000..9b29babfd --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/TableRowGroup.php @@ -0,0 +1,44 @@ + + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Frame; + +/** + * Renders block frames + * + * @package dompdf + */ +class TableRowGroup extends Block +{ + + //........................................................................ + + function render(Frame $frame) + { + $style = $frame->get_style(); + + $this->_set_opacity($frame->get_opacity($style->opacity)); + + $this->_render_border($frame); + $this->_render_outline($frame); + + if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutBlocks")) { + $this->_debug_layout($frame->get_border_box(), "red"); + if ($this->_dompdf->get_option("debugLayoutPaddingBox")) { + $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5)); + } + } + + if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutLines") && $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"); + } + } + } +} diff --git a/vendor/dompdf/dompdf/src/Renderer/Text.php b/vendor/dompdf/dompdf/src/Renderer/Text.php new file mode 100644 index 000000000..3072a1792 --- /dev/null +++ b/vendor/dompdf/dompdf/src/Renderer/Text.php @@ -0,0 +1,158 @@ + + * @author Helmut Tischer + * @author Fabien Ménager + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + */ +namespace Dompdf\Renderer; + +use Dompdf\Adapter\CPDF; +use Dompdf\FontMetrics; +use Dompdf\Frame; + +/** + * Renders text frames + * + * @package dompdf + */ +class Text extends AbstractRenderer +{ + + const DECO_THICKNESS = 0.02; // Thickness of underline. Screen: 0.08, print: better less, e.g. 0.04 + + //Tweaking if $base and $descent are not accurate. + //Check method_exists( $this->_canvas, "get_cpdf" ) + //- For cpdf these can and must stay 0, because font metrics are used directly. + //- For other renderers, if different values are wanted, separate the parameter sets. + // But $size and $size-$height seem to be accurate enough + const UNDERLINE_OFFSET = 0.0; // Relative to bottom of text, as fraction of height. + const OVERLINE_OFFSET = 0.0; // Relative to top of text + const LINETHROUGH_OFFSET = 0.0; // Relative to centre of text. + const DECO_EXTENSION = 0.0; // How far to extend lines past either end, in pt + + //........................................................................ + + /** + * @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->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutLines")) { + $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)); + } + } +} diff --git a/vendor/dompdf/dompdf/tests/Dompdf/Tests/AutoloaderTest.php b/vendor/dompdf/dompdf/tests/Dompdf/Tests/AutoloaderTest.php new file mode 100644 index 000000000..91ee9205b --- /dev/null +++ b/vendor/dompdf/dompdf/tests/Dompdf/Tests/AutoloaderTest.php @@ -0,0 +1,20 @@ +assertEquals($declaredCount, count(get_declared_classes()), 'Dompdf\\Autoloader::autoload() is trying to load classes outside of the Dompdf namespace'); + Autoloader::autoload('Dompdf\Dompdf'); + $this->assertTrue(in_array('Dompdf\Dompdf', get_declared_classes()), 'Dompdf\\Autoloader::autoload() failed to autoload the Dompdf\Dompdf class'); + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/tests/Dompdf/Tests/DompdfTest.php b/vendor/dompdf/dompdf/tests/Dompdf/Tests/DompdfTest.php new file mode 100644 index 000000000..388bfd697 --- /dev/null +++ b/vendor/dompdf/dompdf/tests/Dompdf/Tests/DompdfTest.php @@ -0,0 +1,70 @@ +assertInstanceOf('Dompdf\Adapter\Cpdf', $dompdf->getCanvas()); + $this->assertEquals('', $dompdf->getBaseHost()); + $this->assertEquals('', $dompdf->getBasePath()); + $this->assertInternalType('array', $dompdf->getCallbacks()); + $this->assertInstanceOf('Dompdf\Css\Stylesheet', $dompdf->getCss()); + $this->assertNull($dompdf->getDom()); + $this->assertNull($dompdf->getHttpContext()); + $this->assertInstanceOf('Dompdf\Options', $dompdf->getOptions()); + $this->assertNull($dompdf->getProtocol()); + $this->assertFalse($dompdf->getQuirksmode()); + $this->assertNull($dompdf->getTree()); + } + + public function testSetters() + { + $dompdf = new Dompdf(); + $dompdf->setBaseHost('test1'); + $dompdf->setBasePath('test2'); + $dompdf->setCallbacks(array('test' => array('event' => 'test', 'f' => function() {}))); + $dompdf->setCss(new Stylesheet($dompdf)); + $dompdf->setDom(new DOMDocument()); + $dompdf->setHttpContext(fopen(__DIR__ . "/_files/jamaica.jpg", 'r')); + $dompdf->setOptions(new Options()); + $dompdf->setProtocol('test3'); + $dompdf->setTree(new FrameTree($dompdf->getDom())); + + $this->assertEquals('test1', $dompdf->getBaseHost()); + $this->assertEquals('test2', $dompdf->getBasePath()); + $this->assertCount(1, $dompdf->getCallbacks()); + $this->assertInstanceOf('Dompdf\Css\Stylesheet', $dompdf->getCss()); + $this->assertInstanceOf('DOMDocument', $dompdf->getDom()); + $this->assertInternalType('resource', $dompdf->getHttpContext()); + $this->assertInstanceOf('Dompdf\Options', $dompdf->getOptions()); + $this->assertEquals('test3', $dompdf->getProtocol()); + $this->assertInstanceOf('Dompdf\Frame\FrameTree', $dompdf->getTree()); + } + + public function testLoadHtml() + { + $dompdf = new Dompdf(); + $dompdf->loadHtml('Hello'); + $dom = $dompdf->getDom(); + $this->assertEquals('Hello', $dom->textContent); + } + + public function testRender() + { + $dompdf = new Dompdf(); + $dompdf->loadHtml('Hello'); + $dompdf->render(); + + $dom = $dompdf->getDom(); + $this->assertEquals('', $dom->textContent); + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/tests/Dompdf/Tests/HelpersTest.php b/vendor/dompdf/dompdf/tests/Dompdf/Tests/HelpersTest.php new file mode 100644 index 000000000..da88db504 --- /dev/null +++ b/vendor/dompdf/dompdf/tests/Dompdf/Tests/HelpersTest.php @@ -0,0 +1,24 @@ + 'data:image/png;base64,', + 'data' => 'iVBORw0KGgoAAAANSUhEUgAAAAUA +AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO +9TXL0Y4OHwAAAABJRU5ErkJggg==' + ); + $helpers = new Helpers(); + $result = $helpers->parse_data_uri(implode('', $imageParts)); + $this->assertEquals( + $result['data'], + base64_decode($imageParts['data']) + ); + } +} diff --git a/vendor/dompdf/dompdf/tests/Dompdf/Tests/OptionsTest.php b/vendor/dompdf/dompdf/tests/Dompdf/Tests/OptionsTest.php new file mode 100644 index 000000000..b7c36fd71 --- /dev/null +++ b/vendor/dompdf/dompdf/tests/Dompdf/Tests/OptionsTest.php @@ -0,0 +1,99 @@ +assertEquals(sys_get_temp_dir(), $option->getTempDir()); + $this->assertEquals($root . '/lib/fonts', $option->getFontDir()); + $this->assertEquals($root . '/lib/fonts', $option->getFontCache()); + $this->assertEquals($root, $option->getChroot()); + $this->assertEquals($root . '/lib/fonts/log.htm', $option->getLogOutputFile()); + $this->assertEquals('screen', $option->getDefaultMediaType()); + $this->assertEquals('letter', $option->getDefaultPaperSize()); + $this->assertEquals('serif', $option->getDefaultFont()); + $this->assertEquals(96, $option->getDpi()); + $this->assertEquals(1.1, $option->getFontHeightRatio()); + $this->assertFalse($option->getIsPhpEnabled()); + $this->assertFalse($option->getIsRemoteEnabled()); + $this->assertTrue($option->getIsJavascriptEnabled()); + $this->assertFalse($option->getIsHtml5ParserEnabled()); + $this->assertFalse($option->getIsFontSubsettingEnabled()); + $this->assertFalse($option->getDebugPng()); + $this->assertFalse($option->getDebugKeepTemp()); + $this->assertFalse($option->getDebugCss()); + $this->assertFalse($option->getDebugLayout()); + $this->assertTrue($option->getDebugLayoutLines()); + $this->assertTrue($option->getDebugLayoutBlocks()); + $this->assertTrue($option->getDebugLayoutInline()); + $this->assertTrue($option->getDebugLayoutPaddingBox()); + $this->assertEquals('user', $option->getAdminUsername()); + $this->assertEquals('password', $option->getAdminPassword()); + + $option = new Options(array('tempDir' => 'test1')); + $this->assertEquals('test1', $option->getTempDir()); + } + + public function testSetters() + { + $option = new Options(); + $option->set(array( + 'tempDir' => 'test1', + 'fontDir' => 'test2', + 'fontCache' => 'test3', + 'chroot' => 'test4', + 'logOutputFile' => 'test5', + 'defaultMediaType' => 'test6', + 'defaultPaperSize' => 'test7', + 'defaultFont' => 'test8', + 'dpi' => 300, + 'fontHeightRatio' => 1.2, + 'isPhpEnabled' => true, + 'isRemoteEnabled' => true, + 'isJavascriptEnabled' => false, + 'isHtml5ParserEnabled' => true, + 'isFontSubsettingEnabled' => true, + 'debugPng' => true, + 'debugKeepTemp' => true, + 'debugCss' => true, + 'debugLayout' => true, + 'debugLayoutLines' => false, + 'debugLayoutBlocks' => false, + 'debugLayoutInline' => false, + 'debugLayoutPaddingBox' => false, + 'adminUsername' => 'test9', + 'adminPassword' => 'test10', + )); + $this->assertEquals('test1', $option->getTempDir()); + $this->assertEquals('test2', $option->getFontDir()); + $this->assertEquals('test3', $option->getFontCache()); + $this->assertEquals('test4', $option->getChroot()); + $this->assertEquals('test5', $option->getLogOutputFile()); + $this->assertEquals('test6', $option->getDefaultMediaType()); + $this->assertEquals('test7', $option->getDefaultPaperSize()); + $this->assertEquals('test8', $option->getDefaultFont()); + $this->assertEquals(300, $option->getDpi()); + $this->assertEquals(1.2, $option->getFontHeightRatio()); + $this->assertTrue($option->getIsPhpEnabled()); + $this->assertTrue($option->getIsRemoteEnabled()); + $this->assertFalse($option->getIsJavascriptEnabled()); + $this->assertTrue($option->getIsHtml5ParserEnabled()); + $this->assertTrue($option->getIsFontSubsettingEnabled()); + $this->assertTrue($option->getDebugPng()); + $this->assertTrue($option->getDebugKeepTemp()); + $this->assertTrue($option->getDebugCss()); + $this->assertTrue($option->getDebugLayout()); + $this->assertFalse($option->getDebugLayoutLines()); + $this->assertFalse($option->getDebugLayoutBlocks()); + $this->assertFalse($option->getDebugLayoutInline()); + $this->assertFalse($option->getDebugLayoutPaddingBox()); + $this->assertEquals('test9', $option->getAdminUsername()); + $this->assertEquals('test10', $option->getAdminPassword()); + } +} \ No newline at end of file diff --git a/vendor/dompdf/dompdf/tests/Dompdf/Tests/_files/jamaica.jpg b/vendor/dompdf/dompdf/tests/Dompdf/Tests/_files/jamaica.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bc4cc769b583b1caf3cbb2380a0e4c41826a4b8 GIT binary patch literal 1377280 zcmeFYcUV(R*Ebq^5$PoXq$PAjIs}nk5~PNNCMXbk6GBINFQFt9>Ag3p3IYm92SI6~ zBBC^rrXV7UaKc@l`~JT3e(!bO^WV9yGhs5nz4n?lYt5{^$y$5%`QrHp+I+1*7e@d9 z4i^DX0ssJN04)(QfQNwM2$hb2$p~!~q0$pDHKA=FR7N5a01=_RsO&^!f3yz?nBy<} zgn)(q;vptrDMDXnLOV>TOvHcoy`a0qlm5~74FQ)B2t5CN0hkyXSO5ST7V26E6PO_q z03-Cf(Bbb^N-GYB% zdjbZeQvgT_jf9k>1WEdznv)W=BmD~l3781?Cl3+98e-g^^2IKA@YH{3BtyVt_&@1N z1WbYdb1V{qT*|-j#ZXlL!qk89YZCZF@Du|HDz z$={fqFz#PC>Y{Hs#UJ`yj7#(vzL>F#ajNYRmH+_6gwKT>B7&z}91#)f#k?b+ z3Iz0z%>)ubF3Dg1L@@9_e#u4X__tp|2>8G9OK}4IZ@-iy;Qz`ml?ikr;y-88gn)_v z!YY?8#{Scy|Eb>r&KJ+$0%8F4muP5dsOf1h(=sy9GXaIzfvl`RNihEvAw}sMN>FJ9 zc~zK|fvTpNmb`+Ihq2imJ11u+Wqt1;FZ)0%2PZTU10y4l1$d2}{Tf= zGq%rl-qwmK*PJR**+~M!?r$zs= zhk;-ZF)1ktDaD07M8p9X#xjtS@k)|2su@$*dNc7!MN%@W<4Rllsld{RFD!PLm(;8f znGgJ5FHHKwqW@(00Si;5Kuxw#0wy1AR=KPI)4M8At7863?vKy z6~H2K0hza)Un-%wX`?`G-62op|MFpSL=1vKUxHmrCaI#&g*gT#z*}JgtLqX|7p|)N zNI%0Kz>>^k(${4Ayg`ZDi-lH$i?x8Y>f_~hkFphkH!jSxLY-BJp?}wf@v|y~IqZ$LV19MC2yA^M>26-)QnP-6mB2pr=L~%K; zvsdESUF!8r+4W`e+Q-=SdF%8{#jnCT24A;`B;m9i7jyZN(yxl*uY2%XlFB5d#Ik`n zkou-Mqi=HDG)HV>W~u7+#3b@uWL@wtW?ZQL=&jc=B;fv1B&m?h{xwamX(h6%Lpr1R z>lI$zmm?aod~&+6*=>%sONrT~w)#>pnW$6hHOE^(RZNxwtU!H@y^jB9gT9i0hPnT?e2gP{OqY;7&)Hip7A@=ee8shTp1 z;K(JD#5zr}Bc>bf$t@gk<6Kc>%rHnec3U$MeRKBaJOpliH~%c?9I!gi_gPG3z4+{g zrILKE$Wxru=fHD7w#PXjlsZ>7Bz!{fl(NAgCUpG!*f+6}h8n^-L|E~vsolcI8wj-@ z)C1=5#+;@K>tu_>$iA=}TFCp>rk(bt1F;m!w+#;~R!whaG-p9N9N-<18^oRtRH;Z+ zqSMchxBb6@l-`bn6e;zQtMDS5+d@?syUG$q62vM!S|+V~iP=qR2ZJTg0Z;Uuo7=1@ zc5RnZI)H7*(`&BM;h-}~OA$tEvR(9&?Gx-d09chjc=n?n>9A-}aWCZ;f_s&D7W4Ey zccEEZXyT^z@b6N?uXI!CQz|_wik0NzzE-RZQ3hvE+Rp*aRT9*jbJ1rq@5~m9G!DhWs8;8GQL%{6>BRWxme|6rHPi#knfdMKBk|6 zS*+5^*c3kx=O;YftUHqlN_g*gpZUc8@ughlGDelxCB=G1yaDhxR-t4{H+g`EM9QDT zD`^=*sS%-LtU?Pu=deWlvX z;s>%Dl^ZwwRh8qXL$cX{ptJgVTGyN8rhPNtn*1E#8V6-v9I1#w$dwm`;Fa;TE}<63 zrzCGqD6iSt9_kPrzBkXSGxo96=6hyE6D{GPxOLB!-+`Dj0UGZ-JLVEi+}uE zLAI>!rFfpbp-pdR6~~S8Y~vpbNsXhvJA$usjw!y%#4VXV8Z zYFXjet!pc8=40P*Qa77tMxP$^$A8dwVd`;Lp`I63X?F^2iq>o1tfBbidQpv(F*~c@=Cl5=vFDRIi%o{xmcm2zi&hUhBRv5t z(Lab_H17u$gJrMJ+U}Q#-&+fHmHM%NlE) zqRIzLA6T-cLE-4nmz`WO?6NyoNp(02noor%_%c$Sah*&bRL$5Joj1IA^)q@?5wen+Ei$fhymVq>ZP+=KiJ_Cb;cIAZqu8%@BHeF zp)GJ@Zbd$q3Uqpo%Kn`AOgN+WXWH;eH{cNcTQq8P4P^KtZQI~5{|02bn{EsFF;{6a z5civs+tNFoYxV3zpv~L*5+YQ!W+Z$dKT6>&^TCoo)5evPpR)m65stMM_&r|RSx>`W zL9U2Ukq$wP^Vfj$k7VX>4UIcS2t#eSo)#fYAcQtBTQ4tnVjcj%2knVL=&17$er57d z%o3u7zakP_w2zmXk&)iTufhx7i}rsl-xvPmoxS>BpZ{OE|F@${7{Y*r-^dp+BeT<= z_#(Ptw)+!b#6rvgzFxir9?c7kcD5zNS48FnEQUcMGzd6`fN7onh3)=@?Hzp3gfMcE zz~hPb!Vu(;W)iTPy${-h(3gOT&n|2x&&x# z{KnovQ|m8!j-!h(D+Kb#c*8Sg?9hj@eU z|B+xv(8>qkM(F1P@F!q*!jS`k-}f&)|2=zuYxR#N7yK8R|7V7$d>+a6;2agXA#=*w{Pe z%w0zpcZWade}4VWC}=0$u0^B zDLFYg8TkeLrynsHf#rhqKP&%#UgG~Fc?ohtg7N>9m-y}Ux^obwnc!3vpt5Qx$%>ai zMe^*@yoS6wV6LkhJ*)OaL~O{DMPL6gEVl>AzS1W%ElSr_pkPP)DRL#)XSp@j(l}D) zF0)1Uy|^H1%6Cy&78Zv4M0-KoFmJ|(8%ch-3P_A4`1fU}OX^)H#zc}5yh4K1xH9s2$I^-{h~xyjwob*# zaMXmNp0CT%#lQ+ArmZr0s?5kL3-c+KSA}RDTJ38E02V!irAENYPn7AD7u;V`Ggeg7RmB zIjb0$%i!voz|o$s(|QG*zmTPc9R60>3NDlzUE7M-#xdfuzVADIiS~>#DHC+nmDKd> zx}$Pks*As#Ej<2mT*=5&r>nWkY_6d2?x39eqb!Fw-Sd?C2}U2R8D#Sg$f#>*j8Rgw z_g(s}mEi2>yeSsm4>jKe04n0{hKX!Fb>bC=WpqDyy@YMS&8xnTH+lcQ(!%@$N7SQz zhru8_|4z>1753FeOQS)uJdoH`68YS?^!1xOD|C%wn5K2rHK9JST!rbHrtxo;V#2{l z&N{HEx7-#9=blM?t!l~}C|HLdt?an8d-bv>3AYoWO<3b6PaN@VQQc~95^maMD@(xud0v1__k`R4GXb2^sK!QSU0S%mtKJo zY1i?Wnlw*Go&zj3Gvi>Xaft`To_NZLR!*4>hQ*etwYt8m|K=gabb2| zbe4w>*L-UT^LDkKue+4v8L!TSQ|UQCAX^_d*$mNqbX6=;`5d4s6)s|&EfQ;Fk|qh6 z0NJ$g5TOFDVV0ljy7s9A@B}8qCJzTc^|yBRPix>#>&q$%ygvHzvl@KKL>0*=1f_M9 z*ae6~M}N+~y8?Q5|8AZXG3V+hw>(6(L8p(K{iP`d}ax5ZBugrz$$%B?7#}{Wj7Ip6yn*aFy)m4ba|O~Srw$2 zn5h?tOlGk_8Nj;-Gb?59Ze}xR!i`67=))6@acN_hBuy!$r<>e_lmipTY8kKPt{>ov zCD_zCHf}urHJ8jB$trwX8apO1Nza{162LM|>pWRs6~W`t$f`ziwToz@0_H%oq8%q= zG?;O$_S>y?I8%gLM5)4&rv$JPg^^?Q&&${hxe|Hjdcew+vv`)2MjnrLAyO!|JZjwH z7)_%kJHQ8SxW@#ft_icc=U->FOKc{H&=mz#$&Z=78!vXXNwGs}t1mn4-=BnJj~Fhr zRU@cL57ZuzmY{K8Yh#oK z_CvQn15RB!arSV$sZqihUnEYzWw?@z50x3unKNDr;;j9~JT0y!IJG4|PMPkx^3&$0 zZv&VTo^ntjv7StBs$-EO^5|>Lr_ef0{*pxVy4KMXBMfYn6D8ECm+P}g0Vp-~;W( z`mN&MeOt3xnVY>oUwdD;bJPW6NR~-#AbFhdu`<$<9~YQz#hvxW0DUSvRY=Hj!`kCu z4L!KtE)?}sIda9{&eT>9_Rx$pW$8DWa0Lb5Hf1u)5^f(dG?sf61$lkF^2|l4s4(rY zGVq1k`d&_5lNoevbEc`j$;ElnaY$Sa%LuSr!wb`B>|yH*x=95UcEW!iSsi*)J`K#) zqP42UMIXpxn{S+)1K5GgG?C2o#JNOJaIYpmFt?@_md4Ov+~6UAR_U3rmzCk{){gl7 ze8(%yav{Hf$K*%sEjZ+QsmQGf8&kv88?LhNMKsmlo@lB0Y%sMnOQ%Y?RRL?XNyiP` zO)jyTl4b$oP7H6qUnoe1=CGt*tzIJq7=*%_ps$)Aa8NO8p~U7*73_jQRA5_{$ zJxM@UDlg=1+)0tfuV&~rumM@n2@Hr-F__z86Ki>7-Q|B{wC?+7 zUF%~FV_nJBJ znSHhcWdB(CTO40MiO?|BQhD@`pRbhIS~YKF;Sv}E9!>U1h?V2Xq&=yYMgZ<6Q4)r( zj}6Kb>jU^CC`s0ytY449^yd|ePy|V-O;4()Se1+k=l-^S@qQ+YQk9u# z;ecJ3qb#2$M5L00IG8IS?-NoGm}Ow1`hrdBqv6$3?COMVSDNkgVNK@aUB~PBcM(!P z`(~(dV`-Pp)WFDtRR6)P!`ihtS!UzmhhORj><;GQ)n48JjJTT=@e9$KcvnDb9z1bM zv2{qEOd$8X$NhD4rhbGWRqk*BdMjX}MZ&-Mw%dc{K@|HVo=>}F^g%XcOBPx8p?Whx zxW>n(Q_?{Si`mWAdrzodkN7ndt5(O`_otEunfnz;cB;7Ju+lH;$ zRqoAgYtO($a3Nekn!7t|HU2qX+X||L+eYZq7{f^QW}TRf)kZP|ve3y01SP4fo(q_*2#HApOQ8O;UQX%HRyqKkxVy2E|nQixde*_{In zHFQ&S=i#*zdWobiU21o58en=glOmTCNY`PY$0o1tfzSJ&^Yi+u$<_&aiQtgo+ft;R zBU?u0vIj&+70uJ9R1npWxpJx3Q3yqjeQ!d+r`r z3sz=_=kax#Wm~P1u@qnxc~YmeyTdsLH3k5+0%e0>!d0=lRQj`{_2L^fgNh_GS?33wLEnQnllopOT3sF0OzsYsoe>!ZQV*tyUIA}izG9x{G zcMh2D@K8*RfqS!R8io1uf4|bXpDsM!IkMN>P#QCWONX))y7pvFS`|Y{vgsh&lrO#T zu)5iv{pp|+2vm8sg@5T+GDbbE_Z;x5 z!PRzk@+LMP)GE2o6{hw3)77!6=ZuCB#?#du*I}MqvS;DyxLeSm7c zM6Y2>IkNgb$yiEA{F4RKK8yZf#*l}IbfsSI47N-Ml7zdK!Eybh`^$1~X9aqL&B=jI zDxDeo?F>~3G(cj7AC{RNY?$7ai4-~QPp5~fn7m18fi-SOi>+k?MmiOa#y$m`wy%}) z&PC<1n5rkSg!|KSdAwc>|M^WQGyY9q!qmQG*w?$8R#TGYe4JK}nqWhImZH#xw^Acw zus!c>gbXgi!Xs;Kf`$e1v5BD}9T{Ua{)eR1Bi>C6PfS!$`&K62 z>*~me@64ynokux{uknyTzk_OkF}TK_G~QLH-@zzU`RFzKR7o{y`Z++7CFqbLUkI*p zZ|kUT#unv8879ApD>{l{(e=CRAm}}vQtlGo6-CJ@Yi6E{PJ))NReiMD^z(R5?Teke zBMEMZGoP`}{(9mhPVOHeC21V9-12b4h#bAt(|jb`T|2?pTR7Su1-Fpj^|M|Pv;U0= zYahau!D*_e880vP^DAc!e-Jl;4t3Gog~o_erfQ0^4^MiT2u3K!%pHi(Y7=i39Lv6p zt7~D2relpG;u{gTtt3f0Of*4v_*`c_POZI@60`@JdY$ko6RpI0;7e(Q?0JX1F> ze9SI*b0K5Hy{jLPPPF4(I*yACPLI)913qlMva7thj*SKQ)tCzUla8%}tnf&Z?khEU zr3fvJjMr(tc;sTIztKo`f3P#$Sg+`&c9H71C}&%6#?~#ZnR?Z%@fCHPWadrjF#-A} z>B5q^yPaKcH-ymZCk|nb)5Mv!@d)X>%(_dmJue^OcLD@h&<_1ZLEO`_R7qM+%W}IO z^<8aGBZB=mWqmV0kH!iiHT+9XtjMP);-H}IAvjp1X`Qa6b0uUxh0Ro`GwgsY@Yue^ zl!RLp5N3klHR+`HKGkvAHE0wRPBQgoSWj$s&g2{H?( z*swxJkDax*N|N>41(LWn5y|$>2c~7q)ZiLy&m0joz$jLC)*H|v$ik;(1eyBOshItv z8-aDza@hOVcox63CQ|G(*K0w7l;|wohFFL2yb#`{lPI05-LqU-W4ayT&JJJok^(Dj zfbw}25hLDf_V#lx$~F0s4!>8^K@{&-0vb;~=tlajQVu4&HY{7&qH<2wkMYx3`+{%Z zN?8V*z@ft*S~1Y+D#J$00v@#RJxy)Yqq>Ji(d|{ICwFw^$$74~M?3-D$Cp*sYHPRD zY)U?OETyYmGufGhpn}{(x-lP~7>6CWyiBH-vNV-_6+dM1-O<;uul4mSrs0a3a6Cy1i%L>g>W(x%vr2?$0a{=}q7zP`dQP zS?;~^OX<~5T>414Tu%-Phv~1Z^$_~eCixA*+#wUzIkAK zg7E^H`feXc_Wv5(U*8kMSS+zj!Hzyws@88bZQTLdFHx+IY+6<#Iv5_fzLd%}l`0XU zp)%So>fQQaABeK&h(Rm)%T74KqoXomgHGNzXkU1dV?wu!6>BWJGQwK7Xh)7H3RKw7;LhYv;ncx|U8` z5uA7RH20BYR*P#xLd^+Tyt^sVmc@KnxHBU=c8>Luh%V8T6d1a%`?7UH;jlE9rMY#e zu$MwTcp+m`@3jH*hLpcI#OOgj#~AiG7wyab{_o(E`C5=gt304K?((}j2klCcs*K+& z1Gq6xu_rbji?-`uyx%H!T+91}cA>b>N+W)&u;>Vtxjn}%is1UxFcX9T*}^F@2RWbi z8hn+K5M$osRuBvj=z3@9W;9VG%+SV*sZuH-xoaG4XaUCdq2*IV$3MF8rx<2M9;{N7 zu0Cj_-6Q#qXjUV2Qz+(gSc|A1g8=HADS)6_zT`A1y$|rKKq$@fT)ja)&ecFK%Ss9M z#IlULz&32N5pFX>Yfrk#ZQ%L| zmBQ|zE$$q);V*!I0a7W#=H4Y?BXv7THf*4GTn89+OOuTef~KPYQuDs+5x0GgswyZlnK95@D29}(Xekm3>=789~_rEsNU9%>KRXa3`-Xnb{G_? zxUSPJV50AELi4r6W0E;4Z0pSTgQaKZzG4DiVTGwD7PKBXcuPa_%{}kgrC4r8OW3@;pvN#gpK)M$zygl}0J znGBh5GGPF6ozxob7>5aO?CMWrafbj*_=2)7QU6Hw2V|u|hO}|d1hu>tvjc*s0UgV# z{yYM{soe9zT&msJL#o8o!3IO5#OXgpr#zoUIn}6+=u}AWNu$ouKGI3a`8J}mP$|ry zouZfjFp<9Pi$TzI&9KWy2J|#bi+gWU6I+X%I@OLz?#BcIcMSt4fA0>nI+YAq`dv zqS5u51I>Qx?|?dcqLIl)OC)M*l>J4j!gTiJ=G}cFGi}n{Z7jEC2JM&Dbyj)z)25pW zTu%xXwq~j|Idg#OgH4qI8Bs-<`MLIy(H`cxd71}fPAljyWhg;p{zEcLQx{;})2oHO zaKe@!1e`h%^)Nfv%v0xBANrA30I|T=e4y7_l6_-QM`5i03Pnrhd%?_7m4F^DNZLk7 z+VpZ#mXKbmc{?TU?jxH-=5d(EX)HxlXzgC|CF`N)_5o9rUl`>0)Qw6Wl)C4`E6%Dg zr8aCZ$!K)UZ3)YavgZN*5DXyiKswg4zs97g`rq6TA7k~h30%r(|M_e4#0c3fMgC@| zqMknRxKdp*F>93-EdKiwke(KD(q*E3T^*pGR5E(gHcooBMdrSeqd|*Z&fFe{dK`fD z?Qu9eqjkee*yvCuw&O??TqEHe)k)Plv={rGh6;ctl-`2t9NfviYXf1S4WKW3Oia4#Mx> znu?9symAQV3oWh49Ib;dt@|7}b_=3rYgp~zATy(u5lHy(WYCDG$m0s{edH*dRxj{_ zK3b%MpFZ|PM|=+5PV9|`9o5Y6UzWQ=v)1m;T;LA^H8m*n^`uvJzT%UL8RSUU916rH zS=i-xWULRyG~eAf7OsQUQ$alW7#Tr6;~8T&M5J2k#OD~qcW2}d`g4A}uHUXO*A_t! zigSwC?2UiHuxFw3p@%f;f)fvyb}Pm76p6$)FrLM&H6Lt-KD~Crlz$|Fyn z#dzm3JGs$ve-=&A#jD@V1Am_!-@%0z$z3;CHd~@OL>0goIW(LYM0O<$(G%%jfa#Nc z>#wzEF9??!wj@<2Htr>3jcP)er}T8M_{^f+B5+ua5YAnDpShDzGM)XJ(&1gPECrO4 zq3DRIgvi3eM9`YY}4leRzscOFVG!* zp9;s(X#cy7K8A0M)iW!Z#b+*!U^=JVD;jJBZ^DuiM-7wgrN^~RKqD+*KltE#nXLv z3+tVxyX95Cqx;=^4U!cyX7GY~MH&(W9bF6aV=p0gde3erg=Wl%2;BynWhusJm#vfX zmmKgj=!>PtcTsm|B@Dx+-Dk@Z*MzEI;52_&CkRDS)LT~#3bop-T8EgVFO8l9dT#oq zc{@-Y$5&tJuRG8lpyGv}=R+C29A+Dgg|^;#)-x@yKgTQcEY%PiXeP-$&9JhKje zYui*aC{m6>EMh-kjc3 z=FeAGmGo{TD9AIA-dZ+G7Yaf)gc<$nNxc#N+gDtDoVZ-^8gMRija%6t?(SEY;Pc&s1|@*?K|x>fyjZ4#wM zVTr0Wo;7wsled~LZ{l;_OSGnJx7&CakD+yAZ;}Q2bS1-LA_C7ks<;a5uutQ8+tLKC zLz{mQBA_ScG<9mA_glN$s6azGJ&IBOpQl+5L37D6kCQne5We)Lq{a^754mZzH5&|& z0a;%u%F|&KreB(niK+M?gQh%`1pi)h9ocZ;w^-z4+TBH&6Y-7a@N#rgG%N_a2z{9fBH8#PZVjs>PdJb>taoEQ^1Dl$r?a4*d{ntI^(m;I+0P*T6&j_ zp{TWw>qE#CgzM%sXV+4sIm?oC0Rvti%m4(0eN8XK!uwe|oItIGLLxCidFF%7Bb%bS zAp;PACI!WVUO63xR>l$1T@H%(%2|wOl1$MU&f89a9{X&Y5pOZ(w893%DmSppDbHO~6t$$5U*&z2~1 z?UIv7b>5Mjw~1pay3VB0-_ej(sp8D)4KkPK$~Jje^M!Xz_TybGw8$bCN z((nMRJHyn;R6E^py;$W;-kuPw;|wtz}N_Q{R;7$!SKAgtG06XoDc& zXi}-YPU1~Y^aQ$K^UILyr$x*@^j9_s4SLwNk>vE&E1*dA=>7OVf8v{^?Fk2q!8`Qr1ZWCh@ZFS zaY7i2+!`Y=duhqB?0uKDKQ@|>E_zR;i=m*{iM+k>R%#G0lcBn>A=JDi3EKX)z2~a% zLE(<<0Lhf)vNc{tPMU3it zChv#qUT#&o;^Zb}Ys2jf!^0sxMJ8tlWP)N8f)qAk>J=U2bE40B4u(8ojeTLV6n z3ga4hiI*c@^$D*-Dx4_5;2Vl_48s9`E1KP?pr$b;PBK$V3y(@cXPEv@w5byNsAXON!#TZ+ZiYt5S^&`qxDN0wBQ z>0>c=vN4?ZuaMlAlkNiGVJO&=PJmEQFX6)f*!}(iy5e0 zk>1X;dnVQhq_(hEzlj_1JTgy`bspSEQCN!86dF`!4&4wPCC`JTjXip7M&y`~$-P{) z^~403Nmmx2E|-3(<=0kf*Ky4U+P9Aw4y1)h1XX?qpN2`9s+eHks>Z%76M3CpOS4FE zccGZZ84|j7D;A+cnwZZuXHXQ2jFn)Jz)Eq_;3tY7>#K;oMZbyQqV!a&_gRm;FP0fu zK|N$aL^;Staibeqeu>nRc^};)Irdy1j#^VJ7inRxgXs>*6!&7;Ab7$m)S(;?MpOEY zB>E2m!epr%bzAt9T5)2C6ZE9fm{3MFsp7{xiBjF6E;#>N6$#laSq04|o!v{UEhAm0 zN1c-6lk1f>lXSP~s$4!-DA`(D=?(LXC~|eG#G(xja1sp_@uIeTc&VqoR^(P|-#3cN z6c!W=?{i`|bcn(ixNG*86H$0v*o<-ddP1|a-9f+BVJ>JOZfo{^FIfFK$%rQ|u^gf4 zZaC%g%T+jgE?Kgpt25T#R1*iw(y)Dm2Al(mbetkxZZtopvK4)@Ig6^FlA%$d(D1_x%>N5?t1_e69o=G?$sB9Fb zxytjbcRB4LTJr_shR8;~nkh12h^R==2QLNdU$k(Q6kW6RG-s5ZftgBRcnao4qYM)s z!>`~cNXpd56Z*!RXwuzmlVILK=x5=NXpxvQHN55MMAvkd@_eE-dc%x(81pRnGLTCKMfl4q< zm*yqVVCa}&2Mja9fBaqio!gx_aI_Ec)_}_Bpy$=-=eMk6^b4PYJprluPF#p;Hoe68 z7!R(wbcT!(H3Nnx>qJ&$Q~d>w<#>rmarqi}BF)vF21JkjpcgFR7xvIF{OT0jW3r`^ z(~+(w|IY}Gp3Jxg<=e`}yd>*Vn9$E=DVgr}2Wxk8A0BYbRH5c@Mj;8|S&&=owhxuQ ztn8un{X!?zpDcu@ubg#M27mn?mpEYm_4EOLXQYgGm}+D*Pdnl9V;CqPq>ULP7rC#S zj1|ohs^qh!MbgQ^R>eut2RFJzZ#SyX>Se8JtKOC~74&td0G3JB zAOVy4aGd0E+JlAmXm9DfT1h_jwjF2H$XAn-4~o1~-xnG*#CsE!Gd!dqq0#Yl6Qu5N z%Tshu-l-GFv!H+Q7Jz#d)W6CZhFpIQk{F@+{_ErGUh~I{%GJHDRa*-(!DZTT4p-on z65IQkxTt#o>4IPL6^T`(O1PR->Gj$(FyTSXc2c7ji9AY1i&+XHOwPXkS9dS8jA2ca zUs%GZFJ;^u%UJ&OKs(Sl9_ROzL*H+jk8=M(?ka|RWW*gDQFbg<3-ae`le*e^VaXPbaRpDFhcW>VT z&gS&KhRKRrJr+AEMh>|Xg?Lt@r`=LtRV9TSXP%LyrwA6+Viqt86Z*IFb@qb>fy`dTX9#PE^^;#yiv||m-iNw3~(Lxy{usq zl$ozF10|v){*WW1Mte&+r;_3EB%|X;yP-8Z6@S<&c;?ZwS82S3O=hGCRY_{!6KP59 z6rSwSS>>4>@(Q(Thk2rTFv=ZtbfB!B_+n{XucjlPp1pmWe=R+%j}|9_2)R|Ez7W zLgX+y#+6I4jY8xNjK;kZMxhwi`ZhGO6@HCWxuCHpJOiZ>UJbcx_vYscTBOBa3FJP6 z(}*>s@Q5DT@4MUEgi3`|+ob5$Gj>P1$8!EM6}A&H5>Wa|?{QuAja(CeDI9+)M`5yWK7adz_*Xs*uIj)dZYdT8MI&m) zsRnA_0-e-PYkwN$XHx9TsUPea>EsyS=aU>WboBy^S|>V^D45KxCT(rjl*!W~&C=Oy zLAXfHE7g$bg#y(B!@c=M2a*S-H(Etj)|C`8D;X*uxsMm@KJ&aXqGv23szn>7lDuKZ=JHunNA5W4^5CbE^x%H z78L8goApT`?Al2wx;KPkj9m&d-6Y1VCUSl3%i<*ht!;E&doC?kz`zv8>%YbVv`YPU zn893ROZ1kM0cb=C+}*Xd+5^|z=NVnmQa7;!Ml4T6;@?qm9o_PBU(Y?zZMmZJQPC6_ z%or^osfUZ^6vEi8u_=AqJ*rBW2vU=;fBPuED_`LDIUvi!)Mv1-YL(%EMDFX?QTOj} zjIZK@?@^<>K$dCwJ$8XmOoA~id-NI5P>3-d{5KIYK*&!tM zO8h7mXUhZU6OarI?n8{W=^XEGXonKEZQb9Q>^gbLCCIQt_{YOPM$Ihs@cJz07=ME# zFdIy>^U-U>_p@r>NXc+G`!$`n*_pT4j$Iy!QGxNBrQhlfa($@RCU5a<7K?YpSV43I zC9q6;oaowVU0+9#*l=xAR(OfgldyG(Kx3+*SF!5LZx;qhK{aZBd?Y_ zzPF};1)-WrvPK}yIA$A+&wTueN})PJXkDsD04}H%r>)jUq99lt*3n)~##k;?`UGhw znk_*hBm9I;+|v`vE%Z&rBvsh{S0Z!bK`a^ar(ffhyUT1-Yl`cGqm@={4gg`o`_DH1 z#PvC|LZ%WBtPii!qX)O=C#Yq?(jcUl{Vi5)v6VRY)3+Ec_0bp62lkm$-ziR$-ZU!C z<1*6Pc_qq*J%Meolnr~X+;7KKu$_<|03pF=CiaYFHo8zp&)XPhVG{(b7oz^eZTnfd zLn3x#)co`{G3jEtSZ}v!8jFFz!{qcI=RLU zcNBekz3cd5zs+I6ka1@#2z>}%YJt%gUkf_%F^-ZOttD)|&9-P}rtP}&qpotYHdi~D z$vv{%|I>)OgErh#ky`x@MMFx|q=D4@r`uS{f?GA}Nt@25{IKPh8OMepbKVB81k4_0 zK_Uj3Wp3hu-1&mrBP*`GRqWbL-ywmE_2bN8yO=&=i*9c{UOLIqWVv?@7KY=7s-bQv zbCoh^V+@RK9nR_mvhVY~a#{6>rmdZJk#$Ag39g9l)ok9U6nTXV?~y7FyYgtx!bbQ#s#0L6jpPv4JNKB%uGacwEs zO2Hl5i!|Tvy#2cJ03A3A*u5Q*dc-g|SK&1@21|uo?P_bM0b+t9v$c4%8_+iLW8K%& zI-7c=O3D4?D&jj+nR*zfDgdn!287p&(>6GDclz6SfxkK`*d*_F6nuotl1Bj7t?Jim z)glRRL{@~f+ngk4sj8Q3S>5T%lBRn39RXI6hSYrmr0qpcAo$un;&x&aX?#YfkD8K< z3suuPN3Ci^fogo&OE>*%0>E*M4y#$Zv8vCUYM$%a0zsCp#82J}4beNl7RB4k%P0#FAL!OpLNNlK6}NzYHc3e zge0R<^cD>}0p1iH1iOTL$GH2R@hHv~u2ENpJQWWR&yM49yR%$S$T808mxdfCj`b#avXf@ry5 z2Cq_M>6~tSc=j#uQk4~L0CM9lQL=l3suG7QnAL-2bBs&|{`wtNZoY4Zp}q$c{L;v{#$dJ))hp%pOfN=7Kk64H_;e|3+Hvc~K6(Ul zs2W$?W`bn`IwH&-yCfW4!t5Ka{Q5BPI7^#`oHUG6K3jXXi{#H;1&7;vjPV!B5yZpE zchE+UdT-d53_-_aY16bVe+L~&wb>5YG6UDN20RkDs)2`QZ?b(nSZZEeDeCsNer>i< zD(l|Ez-8Y=?%PVL-{x|5{i0g^OpGM(Lfc>%qB?`;ay%cZ&NedfSV_o09=?&STncLGbcR7z;0JRRE`YkEKv*2`5oC zU!SOXa3_CRFMUhbj&f_5{pyDaYaXAEE_zwhxOu)Jx@yy?t!-z+mMQ?kcXz@d*?2_Y zJ2e9MdX$|nMPW1FgfKf_&JXP>;D?ustYe>GzW=P#v=3a%ovuiXtH9;e+GQ}TA_CH|~&EqzfG#ah`EQ%i%E1>|oGXAZG|9#)2 zM^+&{CEOg#Vfa@SnrRx15omwt@bq3#7Ss{PRL&5dL|2xpjt$@0W^MwKvxL%2)9`0$ zRJxHPZnCjMj$z4^YIq#B?=I-$C-@$b5A}=PO9>xP!W40#y&AsveWoRTgY$emoeyoi z45fwT=|WrIy!Uq-E_H5odlYU1GsP1%v6m!%kG#AK+b8`9?UJ`5Cj&x53Z##0Mz-`* zwD|EDc!stSGW~sJZ6qo*{(CXhcR@tnk_TCzf2eO8$~Uhjej!%C!2c9Yh5FObJe8J1 zKp1SJ3OwC;+M7P1kvjVl@>qKkG5UM<02?@O=<%Y%%Gu}|WN zhimAB(92`YRqKyt?F9=x33FhkZm0US6T7A=G3h$CilAwLDP|n^?$vVhv6MvQelb9A zMkejtfgJ$lnVJHg{*NK$TC}MN8;yjx$Zf(2Ar$9fWK!vzua+qDkCp(k0|to=j8*XA zN1T&K`N;N1Yb_u%3P(NVe+<79)#eiD47F~$sa^eDk)xse#frCdT;kGNM(jHjwo#a; z;vX3D$0uHt)Rq2Is)YOre2V0BgBI{}wOO)lxO<lDyW`b$Na^0gz=He9 z(-5>9yp@D`^e7-wX+xyo`cd$xTi!2G`e%3{)8!#E{Bv%wnEgc)+~Nx%r4$7bzpYq_yr>X7v{NVWadW>FTs<;dwFgOP< zUJL(@@*D8fN*x`@b7TJ1wE6)O%%KXzN|?sRz?xdvShTDj{+!xEnbUskxnv1F;<^Lg zQH;sQkj01qqB%_Iut=@w=4{r#lV9r3*AdbpA&Nd-QyNoxXfJFJf@4T1-j{xax$i6F zkY*hY+)g}5hmEA4H_^>th(>^ZGDSU5^~YW)0{?T5^>?{)t%fh7^E%&$I#itNSUw4{ zSu8OC=)+IbX ze=S67CrTi)?+S=V5x$pc+$^@9Jf>YGW8!ujm zsAH*2ed&%IL*$a$S)Fod@1YXtp}+8=RlxI3>cXBNe`Z;C_F+IsQ924s)WK?1z9ij)P!BJy-B+s&zv)P5oIkk*}#_)U}paU=)j{|x%mCg z6<07RP(P|pQT0&+KsyoI;bRVCp#6LNLA1U~3@xoQ7nD|S@u|c<5I^)RRlJCVMNBoD zgD(+N;Z$wIFJcK0rMIg4Sl@rbJEhhla#GZ&6=OgKyjV}@S-x}|# zs||`|L79_$k}#8_%Stlmz5Wv6ojIA^XtjZVVDLc1v>51;FvZ0YW~F$+>l1P0^GxBM zz$VOVEs3MW^7?$+pGYuT9ieIU4s?$w`=xM@RfmR)7zqv#GQU=Xi@wyEI=S}E=wIZ* zVil9}2?FTj-Ib2JqTeneJr}t6dE84_@dH0XJsA&EQDKdZZn4sByr?CJcrj)=eZgz2 z*LYIxzge$Wp^^mSdwN5dN8jz;o54gGbuG+_#|79ZfZC@+C39k55Ayp|GlzNUN}YGM zM9TT zbAjAei7F~A50k$&(k+Ix$tkHLoeM_qPu zqsP?fndT5LYX8|xb3hum5X2^UZHA)7FY~KE78!}F1aSTqUTN>_3`GOHa|R!~%28tvl!-}Qe87BE~&v1$BeEq-p7r6XL_aqTOP zXJa_d*1(M2iiwL>=t_>aDr{JZyo>rd6R&n20W3KYv_YbQQRMQZQQm*dx^`GkzI<)qf{#p@Ak zwxS5g<;{U#QKJ;p-j!M$OzKV{94c{Pa&4*XXrUR&>xHc1Wnf7jOc7aF|3WkHN2kt; z0prILF>?2FqnKB6w^3mdRd!}T2(_hgQ#oDQTXdho^R@U{yU?Qi56g?=K~t`;Bkyq3 z47+K%6|rSj=SwFeF2$QNPFhsd1?TlMG7*QhnYYfA-q=-vL>&-93wOjdgP9yZE()$? z(Y>6V=7IZ;sti3LBe$EOVHzc7h=)L6;NBR}vuzv+k{HRhMW)ZCL*(IJ_C&)szbo(Z z2!Kou@dvrjxsQg$I{v;4mU=fA0KAzwC8oqS&Wm|UtE;B1s8-q-kJ|sPU&c01u8M!ZuFXO zHEIIgVw>)0AMxD2X5Bh;*=G>sZ`N^Pr0x}13x77_!~XdNo5gMGSf!MPoOBHxSqljQ z1Z_N>IP@ZD@_w_L9Fg=FViu5c2J^w=C2EY!-UyKH6s#Bcx@X z@($4Ixf@oeS;6&5i^6vtt^7upoQr$vN;qNU-E10ROcltrm1>7O8^&p|9RE6NM0ojQ zi;%})73n=26ZBYgRn(fT8ham6rLL@}hi$4>32c{Q*ZVZk;r{XdeXPs95MXBE-^dAg zm;j)_f#-v#-U~v;{Oe4FfPy-(Q9H@dx{R@FkhUI-D@{Ju5N9hAa)Z0Q;>%t0mzsQ) zVh&3O7vs`^xD*^on2Ut5$#|lvvL14HO#UB({oMLiN3elErK*Kmyjc$wy7}*6CX!$PubS$p#FNeEmMQ$n5`?Ajh1xqAI+}Wd zoWlg%!vurS8<9u{^0?eJf8LTE2YA1u9g+o@^B>xaw*GImVd$dgm{(h!w!JSmmT+w@ z8Xm2Z$n{gQCOsz0pf~zg{cSlo173%s;~G%`dM`&t0Zfs}vD+D{m(}i6{Hjm&Uhcq3 z1YWToE4w|}(nLPBTSHzI5J)=el>5)YKJoGA`SOJcwH`t;+PzgUrbv6oFS*K54hgXp zJmC?rAhz&~!>6v~vP+)(z{fpXJ3>tMZINeN;p*UV5e% z$r@i|2l6~~J*Y#&ptPh!u^ls`qN4`RpeP;r3I>&hHKXgadX!xwU&g;_JCei*ax}Ca zjj(Yb<9R=ApNFHjvLZ3O)E`zx5#xm(Urxnv`caKh;E?+Tq8c=A|b=95tGHD*@U{F+B!wfZ}v!eq8&U*cwp=u*AVMFg+kG#qjH z``(TTtB%oRB|cn$%)#!t!I%GcvmrCmv4}{*q&WC88hcC~-+M3z>ILW(LX^=(u;``$ z3YMTzqHfu)bI~bG40OVjlfOnk8S5d}WMsTfMe;%lf6~SB2pIRKKn*xt)|6V~KECm0 zTj>~-W)igidu>zapHjtqqu1_DlJ`M0Z&P5IS`*bt0_S~nF)>AQs*q~%m}}n@SLYyS z+h8g(-I@*!%3|U?_*0#wJ)N7++0xg^To+(a5=|P^5lvLr~dl%$8WxDX2GM$VgD=0?FM>lEB+Q#z^TZ+s{96TD9KurCo zBNl}$o(k<+3y|}QXazffYjH~ZFZyu!YkG|!z9~i3<(}{j+NUkU_HUo285t!6XgTlZ z1zHGs2v;+eU5TTc&q{cQoW%b!jkMNEEZ3Vym)1;SVX3HZ~HKnm9pLQ5so6 z`**_;G@~X7qscbKX;?yUpJqy&z;}%FHWfmtj(*cZ$iO4x^|Ejqs15ro3OoL6Ty4(# zufsIiHqSP^mE**dQw26D<#lc8BwGLX{z|Rv_FA~ALatQ6YcQ_#WH`c8QgP_n9g$gZ zTCslIm<%po>Db><7(XUU%@p+DdYZM(-dJ+mTR=;G)3h!yRk~6GwZ}8Dl0YSNs5We| z@jS?g{ghj#Y|dmN8gfl*IpyA+ev@AY{>)v9pE$!ZyW2vQI3Prw+8Pvwf3i%~kb5ou z9=5U?VJCNo(egwdvdPs4+RZk*RT7P~*F;`p;TRi;&hC^VK>DRz+js|{L9NxE=S_Iz zR)vx4Mx)-GD#@2N18$kkW5E#XwCUKiJ=B>Jwn@H5gl+i?EvFT4^4AG5J?~6rdNq#V z1aw|Ml1L!Mw*N_S6XhBy*q}9UqyXPMjB^D$K9=FQO2wZ&AAS2Tfb3UDVlevq+aBOm zBw6EPBRL)S@Uwa@`C}aj2AE#+=EUl?HEtb;q?-LEvlh#AW^VXjU9g5E1Y-UGADqr- zye7fw`&B!YyOvV^%2IlQw(8eOwC@b=EFg^$`*0S=pa&4{y(u zafOs?jU_5LCL7UGc7s`XnK3XST zfx#XfAvab}^j|UF)azR^Id9*2|CG=qzm(#LYtwm@DPH8w&Fw(QUJuY3ufa;jhxC}7 zJlYitkEn){`ynQ25D0DmuIxSmlW_0ynu5VYyY>dwoQ;c%^6Nx+S`58O&_Dwmn*rB- zOH76F4F8!v4*pW4e%V$K+p6ar6&xo;ukm%UjaIiPH9+;(#-m%Jn()D~On@Az^wTeO zracVDqGe_$ek(*H`Hq-izq^BBLL@6E_3|bl_V8X@3P67NBjyNFAnttcuhT|HijEX{ zK(%&+=_$ZtBRfB)&!~47mDYo|P&89065ilMlFDp%_wHuhcB%pd!(q%Auc!Aegvo~s z^Jt&9pI<>!$J2SJ_awkML`IGGsGYR!6<)bd$8-EO1$w>KZ@_*<%Zx?#Vd5@%t?mEx ze%^|y+5Z9>J!ERjM^Eylk6npMFuNuM_}KWoz`Y!o_5NA=MuU5Usd=l~K&PXX9m;tDIBM~8EMm*U;C23ryOa`0h8djWQ!lj5wjg8#3k=p6^x z%5GYXkE3EA(R#ddYu7G5F8Vd>-_Abpj?%Bj;Lutm(MDt?u=eUy_vm9<6varY8CCPf z`7w#Jyp{EWTNHh;@q6~~K&EW%EGAJqoc~#V>o9)BL`wTxoWxv1E2=@*!itmm`JHEW zdUF;6_lr6wD@8Yjj)ZkEn9)ETibXKk+~;GJqRC0RD3$K~SoKGed$m`9t)A08oh!a9 zuTMO3zMtRFm7L%= zxAMUO>91pd8XDus_6hGwZy43MGB?*49)gqGia zi8XCm{>V_4voZ2hijKA`2e|D!Gh4Ik6$;GP3M4;i57Y<1zm5lnR%b3J{n13(0IS;|p)=~A z_QJ0vud|JLp8aaPfXULpn|Avucw@>6y^Y3WBVUI26~ZP6-K>P3RZ&;-g|RY}@$rO# z2>-WMfcle;@D^u}tkUz})ww^W)&KZIUx=~wNAsmR$&e)0&SKj$Ce#kRR`nCvSi|YC z$~Z31bqIlN?GME@WgJN41!LRy*xF`Z4PT;!6Ysi)XS!BAQzX(SA8lP+nbU1Ng;(NA ztk_chT!<=9*c}{2M^1LpQ|!5GB18CStktCnpns@opaPiZrNR48)gtT?cMr8=ir#WB z?>;Td;q{$O!#839tYNIoqPv#-H^f9r&IaOB@gULBwG4FangA*|!pg&|Jkaa8cK#i= zl6V~FxncXdF6l-$nzkokGveda{VRLb1 z4$SUtx40&a;e9|lZV8BN&=ysHx7?f~wqfS;m!I1(_s2vcp#>2-)Wv+~nd`HV3jjwe z{*Z$^9N0w@hCdauj|ifS7tLiD*7>=4W}cH>Git?*AN0#dd9a&|DeB`PWwYu7mN!&< z(8;5Ps$ZVpw%(e!lTJq2DU@Elq$sOBSIu!7EwV$4zssKOov?DW=+n+xg8> zK49+e2cXa$hhD*yr9~%hOG{B{25jBug?yuH>abA2lBuA?YD-Tv_%YbDtj9%M2E_o@ zsb#nn6!w^*bx8;C(r>rnTfng#zB;4SwUCB+eK3hQ&)tL_K6jCLd%K{<6a2G+-)qJU zkcm8-cz(xE?tw&@ZKW=((l^VWxAkbq=iXL1vqJf>zn!fODA+aA<-^0Xrt(y7#OVG^ zp{zJtnJR;J;FtWpyIStEwZL3wBBIw(vPLAdO~}C9a$_Wv(GmOetd6yA&dJB(R};zw>jRibHi1EZntbSGM)3-f^mm{dx$g z$&y!=k1q*8pVo{ggobBD9nBh*goxWh4<9Bbe=e!cEN`{pnabXUqo0oF_%8x{{>QM= zqO4wpf+8lv7&q937#CHA0vQl)Tdcq8lhjzTav?=Ymw*5M>*ThyJ*RPF6sLnz(iLTl zbyzRP*8cW4^jj1~d%Mz_{EhhoOgE4TvU>2rkiwoMs|?MdfUr&Kh#VweXnfa+1Seni z2pXSAHd#+>(Z2BZ?{9%LDjv}tj^hc;-f*49)jM!RWyruk0g}}KZRNJDq4y2`{d9B^ zcS#lv&f2NQJvRJ%;@;>bujb~eUq-H5wLV+^;}CJd2ZXo&>Z-uedO-vl#mnlEwoXPnvMP?e6>^s?@JclC{h|`= ze0;X+@DhAB@FF^_%+Mjl3p+za!6pC4z`>buMHm<2Xu6c$Ll5mjn2XjQ&MB=!4nJ=Y zxc{IhjSY-+!xU%Kpv{L|$#li}?j6^NC;kNWYt2_wCpzxxVJ-ffdjTKu{MbNyiY4RL zK1lxCsnfkGvVet(CspbfaW)<*uE(lZ^f@R5FG(=PZh}l`elw6<|176e2q&&uDfp=9 zaiE0v&)wo?V0^WQ;-qO6XUY2yND{bGwjrEr!BdsNU5?Wsb6nei-pWdJ!Z9Aa9l+E{ zp0MI?i8umM|4;%t-lIk|{AxB})B2*Fc#%i0=OGTO!$PKneRumq+U2mV6Ev4jjL7g4 z`-0#NF>p`d9FbIEm2!=p2iqtKTX5yl#jAe-A9z>Sy>;4$o{oE=y@)98{hs~5?|m*h zPrTW-T@EE)V^3o)Rimrl&+Nq}^Hk@A;Av*a#iVhHvEU6=72lAUBRES=>1kffE3TzS z4;^3RnKQLi@YPEeo9k8HmIiq&c94GkuJ?jangATJUaDBQ!Op+-oht1Wd+{WRtVN$f zT?WpHp=ka6?<2js@|oUUM*wBksZI6xAR8Tqdo3T0{L&mYi;&J9M1j|W`JXq6pijE* zGIvTmP;77{uDUy)b9b~3Yq9@n>o8!(JiZ@R<6hK?uV0dGB6KKdn^U-QqGds1yIk7KsmN##y9qcAB^?sQRTVe zQ*V3GqDHUn%&Jc~9)Aaoxb9VfQ3)W5df!0Jr#xWh_<*^`$3was>bG5VBJ^5y&lAwK z$*pH`&9^l;jWvMUBO)b$=;J|C@5pdWA9Qg zDQV@YLSb7wFUx&S6Wo*jsaUY|_TFi-kQmi^O|D+TII=nY>+Dwtup9mtL8OI8p!IZ*Fa?Q%pXIW-tR1 zUyO)&;txkVx!#s3)PlP2b*D4xuyivXTeCLb6`Ky#`3%GdC29mV)j9@^rP9j(#~?AA zD7v1(=75k%slDgje&9wl_)m!T{#H1;8V)7u^Qbu4?1-6(VQMV8^BtAHyxO=@mJ%^r zbH(gw&H~&dQP{cWWc30j^Ml@-(mY#llJeJiom$&Xb53aHmp@ZRC7$f^cTYR1c{Ln_ z=%^{qH;&t;uh8Oe4R++kSC?A!$G?mu(GleaApnd8h6D&<7#-SPMaNoiqwbi9?OPGo zz4d?GZ~8HZMo1jlZOLMZGRl%7nqQpAhUatBvcYE3oGe$xD!f#z%|_gu;$HULQ0_|2 zi(&?KAqj6om@-@QZ0JCh^pV?sJz6C(r$N5EB=OO4ZgSHqPX2&lGS{ioAtY+i(SMVK}`{?0FQV1D6l-*aj!=gN^~qU zkXI{Xi1j`J&k15dP7D*^dYLySr1MD8CCfl%Xs~6KKz6e~3e`SF-1Jlma;AE@qFnT{ z0@$C9T?Ml)STAwI?dctKOT#lF5FBZV9OiqRUoDX9yNj-Nin>u9lO&y0{ksLMT};mj zsI7ujD@MzEj31uO@*|d(Sp^&V0XY+3$YJWpvckgalK=-z&yuPwjb!ON;AKH|^ zN9`}%=lLJQRW5WD@Me|HjHqmMJ#{4T(bp$B)NkR)deNKV1(AV4VYG9DZJ1EyIPkOf zY=Vq5PW4M|?1mQ2i^i;6WT2znT>e$lthx)Hp+iVCiPXKo{bR8f75+hLzDBv>dz&bq zTR4DdR#s!~LV2oDbAu}~0&@kUmcxq|DU(&+0{m(i=4{P*S!&m9f5-m+L$CZ`*rF00 z?QtN_b4vZ!#7FZ}T;Gw5w?W$CIVA47m2U8d8ufsuVVAusF8D0J*dPd@5cFYh?zs|h66r;UIU)=p-@w_{`aKbD!uaJ{=YFEsF$;__!C0mQ5?;HR ztaz$==PqBkY|H-mgCJ(TxW98>B?1~d9wbo3|6`pmdpWmWn+NAYX9~lX4z}>!;S(lX zAk)L_-s6F-95g#f{K)bXzq!~ld$_1mhVlpmpb)ms{V&CGqY@Bv7-Ie9GwD3$-A{h9 z6-{L$LB#jtxc5c(8p6>)cHDyu9q|eGgeQVSrKVE3^ecY%GCR07ELTBV{EwR2<)vZM z4)pffb~Z<)xSK5gvJ*JUS8)O<=iw_FN%N`S(Zqlzyqf z9roWfQvNL2Dw31;=t#g(2|gJCPCw$HN{fft zW9ujHJvClo-Eep{i_f5{5HdFoo0$Ip0R7zw6}|eg9p6v|ZphPH zB#CVeJ&Xp(*~)8w=UOjxRP@NEbV1!5_ZqqP>{fvDVEY@?hR)JA&FmcJtA9D?j~Y?s ztGTwarbH=KkWHQ=cJopBmk8#rU1VQV7&yMcKB*n|_XBvy9Idv@9VXY2yZ6+xuDH8E zKT7@2vXZ$p@CRMCiCoR~HmA-ztO50a_(P?$pZF$}OV_R`yt_omWh3JjAO37msO3tY zD714~*o3P5KZfqyD}YPI*|aRUi zua*nZZaVh2u})^AZid6Q0LUC3!$L7eB;<`uW`49!diCB!jOnHh<=^Mq$jQ*~a_z-J zmC@r_e|yry-(1)A);DP&x|aZA;aI z$Yt>+5==}cdnD`p_k>vcD(3SWc+<25q9^r&Ng$D3!hZGQjiwL$FPbhI$@MLcnCfk| zHOh&IPK-heu8mhDa9-RDg_t$EowcF(1oy9I{cBjt1@kNeKY`1^ZI-gNb6|^!tU(R+ zo$XD~jYgoeiwoAo@bi4<5(r!~aLu02K``NFU^B;Mn+N&7tHqy!&%9+`(Nha2PEBi2 zYdAkaUhd79#>fA_p+nCtmPIq!ywXeK3<;HkZ#n9X0=RO%6aN{Km3ExCNlPcnhC znayu$L}(!Oh;fUxW5e3VR+_`|+H_WzzT>4&io7ku)NDf+!o62MC;tT(_ML5q+NiLc zcpoHw^03y3C~GfwA5$IPNcM#}5%j5(-`~{LNx9-i1QVsgkLnZ7OTocqj~@h$+G{$(&3!)s8X7O?a6DL#`@Q|2&qufYBly)0 zV)?v4?Gj=-3rsB1fBsaa&&O(7z%oyuO=w%>(lO#Z@>-r)#L$rYRF9}o7%>xf^c{uv zwaCmZ2oxl0j?wLs%}%;`cC&tNW)c-zG;7W)@I%N7q0N?kh2NB->9fU*BP`_p*olPS z3nX6Z{c#f^b2CXf@UjPh28M5~6xZ)lL)qg>u;IT~i^Pqg@2{w>;+t!P#Jt}D0u zLU=Bfi&sl>Jw@wcM*Xyo!?k_2(|&f=s)7PB6M}Uih5KpqfCme%9>t%D!5Cdx?M9@I><(@=eby6H)O4voWa2B3RE=8{;;mv zpEnn1BD#Kri8$A!s6Ncecxm@K!EVFv39smTD`H&3wFXA_>c2@)+Y2`;HWq-s6jk=& zJJ!coxp3#)8=<>^D%kkj?#XvuBO-rS8>&++z6m|NqhI=aT6eDDokITLf+(S-Auv*a%ElbW^$3a~I z^6PlL!jD^_m0w1C-7)^a`*RaLSL#UNpH~{1s-O}=eP6rS8sLKr?DZ6&^Bj>Xj~TcV z5xccJwQ+OUh5fYpf}NtfY??{+Xg*d^iRD^YJ*9?lbS5`#tK40o8cux1hv zTjJ0oFr+7aUbbJ(O>cj6>S!O?VNnw?XH!wT)RWbuwW~N++$TkwCzdC)1KfH8=s9oO=AB!12I#MOzQ(xwg z9c5Do^(okHTFZ1-B6-X3mzQYCs^4chLu_XMZL7cY(@kBR`-+fydC;pBtxK0_{b7Am z_Pf@y7NSIp6K&;BMzprS^L&niRpNZnFqLY3!ibDq#@nk?fKqzaULZPq%x6~`_`QXS zt`j!B!4~>l+tL3`AOasQS`WP|3lmyG03XL0-OJMb`yLh zn+Zf?bup<%NQb+f#j%H0*x*BB=P^-yyYV_dudrgsZr)USgc z5xWV8QnqvUsKiR8nJ2Ol1LQl`ue-g~U(0}o>JP(visTtLFC1R-CSB=V?dUEsV>h8D zji*d2JWS5e0WvgsEAy<)iP>)|!KXV!(on z(Ua(JRXrIKu+W2zPg6xx!{3&cAt|VCDP9OW;|u5 zWTjtQ?J1<-@OUCJmCYGGD%4kmPK72v_?v;L8H0PH5enkfhYms7-yrTnU{l3;2+E94 zqTY>smC*Zwbm~=GEC9^k<)|je@HO)EjK|$-&$~;-dK^?Ipsh4q8l7h>IvXcHTl-;$^Fk(Tyhcp(bGSJ@h6B@sVv82sPV zgLJEBV)?ffqD0pMgKr1yRg!?(r?XdN9F}g$`$RFX=WI=}X4ij*Pru$*X1nmp^YKJ! z&xfnX8B#LoBvoWldQV#+Phzt?OR*AeA062T(;nkkp5H9Dw8NjQDb}KWJIxFDD1&*& zySCbF*)jv(-*evOxO)D>Rff)H`V-QkSAbEUN%Dr@XPyFsYvoM^g$FT*)p2G>v?5uO z51Sz+d-yT(3)j%SDSdRrqauW6i(3vL{68nC6Ogk3Y3KbE^F-Vyb$&tOiuf*aLz96( z))^Dhnd++Vb#6U69SX!?1~}I}{w7(a`=}zTg$xm3=l?M@O2@gTpad(uR?~1;bHTu; zn3X6R;^grgP!#l2W+`;?!x5i}LRs9=M1*c08K8)ml-1oUsp9WRw0|wXpmv!#>AyL^ zLn^J?H z*arf5?&IKuyz%f(=^)6O;>g^Uxvi%h8}}X^uub0Z*S(*fqWB4ao%;lLz@9HUr7%+n zI9#?ZRMMI>^j>-O2Pwb~69Q)wiV%l#q1~E2tuHuBlf!J)gzUz(RA6X*qQTwbuoRs_ zhm=M>66cAi&tgLNv)=2ulhpWq@%wC$Bko-LMlqpFIG=HOt>9>&-a8DA=sXwpqLFtb zpmqIRXm-B>bg5WVY^R12E@Px+JzpjRGZq#~V@~Q&xJTANgY9bs^bm70#@YPf3MUV5 zk)7B)iHDx4a{LH2cJZh~6gcle-X|p3PQpz;YrLtsLy;FtDLN{2jmV{p9p|;?6tAQx zSw((OPr#`L0*MTq&e^N18p88<>R~ta&@xY^?{LJVZ+{q^ZbcrZ6ryS!oGU-xoVu<0 zwK{~r>K0czH}M?ztWeJ5(sPEh!MfY7#h;!3Sctz)+jL&%Y~Z}*LQ56pG1k2v?7tNCzH9_a8)6FULSx zMO@AL!MH)}O}>rxc*(xfm*RWZFBjx57tVQXq&R%F%eBe{+v0z53C}o`82HO7 z>8cja14jqp@#`6N*Zr+xW=L$N_z`*>J5P)Mz9{Z>2s-y?r{ogd5xq_-@ylJipP4sQ zdtHs8ez8k%eWscytE42dem`+38mlRiZR>7hhqKDn@iMK+a!@5sjE?A|v0t5qdE~{p zPHRsZmYSU#rnl1N-}S%x+0Q7rrXil%#Y2}L`UX8D_|7$&{ zh-(u|xKabMplm^U)kg_U&CyQKZvTN&t-zn$G}1FVX~yvCUAL1ALPz^bW%W|4;zC72 zAm>riuCtert}P^qw8~L`1*6gk07SIq4bruhk+X9<0`d6S=y18|Y@A`<|unGhHWLT*JKP%XHsQUBV(j zYltOGli&HDUs_&zQ6733=L=-vRU;iCA-OKOb0xA~F<%abiRKp)P2cWX*BNl>tGxmY zrmg9mu&yY~cabTL_2xQSOi(*7PR!!Qn{SkZaAb~%ao*7F9$zQZw~${t`=s~76M5jQ zz!EW_@pL-#>s&l?@kcm)&&%b)H0skLwDBMSv-Y!zJlAYjZ~tFkQB00Hqy05K}KL|0EKF9Q>A&PKQ}>KP+1A z1_;=iMHQO+l?U;^@IGkYKYmbLdRx5-7Om9?bHBK^C;Cs34NrMF%GXMfGL3fU)fr*u%;;=FZn`AkKeX z8k8+ZqNKq{aL9|a_xMyi{Iu$%|JPIvLhSJL++Heb^7gj<#V?N~Mf$Jjo_O`grC8X- zzVv=5ix6i_r~DWjW!-gBL=K&5X8@OeHb8~S*hVC^hqaaQQrA?qhE7&41OINeSJ>}R z7xPO-RZE@S^x(c~daXtv3d3L9SE4@XyoJR;b8pDl`O7IU!}xhY|JNFDxAt|T&4i%$ zEu1Y5t-iMyBv~bS=4*_ZzaNe1ztwTzDr{X;$hxZx^#mH-9Y^l;!N+lFeNrX;E0-%q z0!q1HYvew4!a1|up9{NU^fE_Kk zjcaB&cvLVS8XPR@vZ;-i4Ei_XW%gd%pEdsuTH`#iK}7|v!R-R0QJNW;m`cOxrW ze`0CKEWvIdWufV&{0$OqBVC1kPS%=+q3J#_I$%0o`N z)aqvZhCawQi|$q#{Xkc!7p~buM^RO5X9bQY9o5Pv<{qjh>pTxc+i>1lz)bNCRm2hL z^nsJI=Y))$c7`ZYRz1M2-d8$jDuhzhuJe&wvWuCel;>Hmn@-on_ACx#Ksrg|lbTE) zH{lT22tOmk^VY9}kJ|I_SCW7KMe909Tf9zZj7fpwTL!MU#Z>=g{ybkM5+ORuvd-7h z+T?Qq%n~V=&R2UPDIu!Oi-EB3d!k zck!#P_q?~>-#JL$_ECqe4c`?syKA3)L9f!d+e|E`jle`&OcA;ZC1 zbTtSy@TEJH)-~0!wYzUWcYh!IV^;m@x@GJ^1^6!oDd5*kzL2 zdFe6F6CQ>+)ncA8#jjEXa z-@~AlHcuJu46D}Yw}X2I-^i$^Ee`a}4vA)+79yUB)#1gNRs2;-YS$+jrN89Z{N#&3 z;M{y&OW~XMEAN{jGlX59*59@s>opa*7$$I5^W)X}0q-f#`P<$b4OsjE)zNh7(A56! z^PqLfEj%~tmYFawTTJsvn1?CXmeEW%d4RMUG$u?fPn?$Z;apt>-HfopRiBk_g?)WJ zEe4lS6%4{fwc6tA-p!P?SMec7xgfMCkP2RR|5nk~vj_gx%4NDHk3)#?5&BEWSkUlT z1$N=*Z;XuJff+}!92xqKJV3An0nKRmAV=T_y)a+ z@vmZEzE_<2a{&o~hZMZ_?Q?WSjV6Z2>t^YOTS-rJ$29$i|5qx^e9X)&b<5(x7O4(g zs~SX9q6SMYTlIfo-#7`l7=}yKnKagLiC-TBv`>Bx#nHFb*gux>my_XiJ6qoeC_N`k zC=D&r!(*r5u z=r;yFBTz3FgiRO|I`KWk!ueIx$vOr3*Yx&OUuCKCUC!1xC`1~P>c;;TGID#e)OrGc zNm@#CjoP$SoWPfXL;h&t>c;^~|Bs@xj%)gTyExqvgDD-`sDa7`(o(|MM#D%!=>}mm zBGToE4Mq--Zj=T=r6fivAdS)}bf);CBwfc3b7?8z-2Lk}dFoqUJ#u3Y>cs_qe(l4%`4z*gz0|a?z~(wIz3^;O zCh^kCRwN4x*TdGBiMYH0piXvS9VLsMT8h z-1qAGS)y6=$xdLbQZApH$vPtu!HV!krgh~%8jhYqi7CyJBQo%4wby{+8+p!Hm zbQ~xDGgehH){{fR{9~yvm8A+;p2#%SE~ISMi*)KdoZP3Kq!RX~x7kkD0yJ9$H$aM> zY5ubM9$*Tyeg-;IOznFME95n|PUp_<&Z7E_w{V98`56I-vSQc$y&pV#yT|$yQ=rOs z1!Zgm1;=mf@+sfH9TuXrrY$X>(R4?L@p}y#4mLj7#J#Z)6&rpg3MF%pqsuARa;TxR zz2FV}G)l5`v?=JVM{<5q50Bd?%MP2>?A;`MKtpL{1V(^UCYGOgX#!jhF|KW};|4i4 z@D&;)aC9>r4+>41V7(*b^R)MbOm5u{s~wH3 z5pjPv0YSKc48oA4(EuiarQ$}lK%+CfRj`@?vn5)AF-W-P+VMNgx(v6t*z;3^><+|n z&9CU3K^KAaUKQLeC8huOaom|RAiUxcR~BV1XaS%%^t(5(0)qd5+;u&%&r^juRi}2! z0hR+Bq{xtl1aU-JDb%nz`L?LYK|c#SHZ0?9ld)VNcO4`H@^G`ENyD8xzIH6CeBhtE zz+*y$#yPEY%C&vIfC~5f*`xlS&NXIv4p<51m5^#z#~z2+ms5+h|J9*YEBwUbHf<cdxYr1CL{7d#wxnzjapyGN=F(r;IeOhUcEP!e_Mo|7(eF0NTmID*4d50^_a_N~R0c=0M znS{!=NLhx@yXA{bhy*!cij@n{0ltYTYwrD)nqujheCL#(b58vo>~(k7y0k{XN=;Dc zm5<#A%aN^}k(f3rB{r;jYjV;>rOg8iX*pgO1oF~NxJ!xu4ofPxz}QCS%RniO=1wn|!DeJOp4590#^F z+_EVCP{X4Y8~^IkW0GJrthOKOjTqudVMD`N{3(qpHJC+Wch-~lE|%_&+LnR|qg7md z$VV^-^0i;r1|M(ry4I0nNp;v^FTTG=1oHPIaWhP2(cGuP76e*?#t+v@w5L?_QU+k5 zMGbH3bz4CNzwS6z2J4}^pEE#^#Im{3^q1%L4J|udpMkwiEXqLyv}rx163bu&RM16J zMMMsa@=Cs#$EZ!3)kpZB#9A&j-{+&16tTky?u!1*G7Lyxk10%TyV0q!~Jfj@^(^M`L3`~#1e#qCozxr^mB2|@4d2n99DReC)tu^ z{5EMahDY?qC(dn+{JRI1=@2cWLCNLuBA1D_$1c2wXHTT+lDt@R1F{xp#-b{OH_uM| zF(vtw1lW>osF;R%r?JYoI>yLT8H;6V>6X8B$|NE8;lkn@+Nj@31|-yS8TDM?KdOD< z^+SE;Gd?mbI4yVcXL}H|_t9tmew!nzFbGSFAi#J)OokQcytjeNQt7`?F7Ikfw74D0 zC8q0TtKOMCjZ+Bszxr9fr*f}roy>LmQu5JVBQKL1EQVFmTGpPp;a-L3owL7G@G1K| z1WpL;7~j1_aB{S?#eSfO`nH%jzDg=?z8`QGSNXJ2*<>b(fx4^_Zvf z_ebv3(D2uZUC5p`yl%9p>T`wX3E*@~v^BSlme@~=3=>tdaQN9aoZy!9gKw_qPHdX(;i|R0g4|Y8BteuqGE4%MGVH&}`lh!}k)pJy=Cy)LaaXh#<=0d|orw zO>NoAvO&Tc8AZ-k$s>q5WrMF?jr1nCiM#vm6^bKQK>zJjTs1Q9ub$S|@SpEUoh@Ne zY%w|Gr%QD#@@c_|cB15`VSEF(v*SlJ?Tjs7KS$M$;rL=VF=KFS@>_qXK@d0sACY@B z+j5z6nh>CUh1Fz9%OQs2`78+1&qK8c3jSY?sxaAUxe-7Y-0_p4UDwgiD%-$isP`SV zMR?Ypc>Zq59nDDjX?fFeS?Z?c9EMoizUdQV*pIJ^pDH-c^ZN^Q0QesgY&|G2Dr!4M zq^t&39LOj0N}RK}VSIG%?dxc5#VXqKXk%N>kuybZ0hiAgET{TE8b+4Jp@ZU37J{~N z|48Hq{$`06SgJ~Tsfkx|W*N{? z{I7?;B_XX)o@lP^wSw*1yA*WAgPt$1vhGwI^XO}YsW*B1V+e*^WEc836C&_%#6eyWG8l^W^MAI;Vi1#H{*P9Cb@aSU;0`Io;Q`cCp6m^ z{q}T{B14r(C4G(62DNUPMwV?CZZ^+@ba^n(=v_q=oFX0)!J1)0%C$VBJhx?};B3YF zzw`qy=SQMH6k!L3TW7?{I>OeOp8al`VXI$_yU@n{FCRK(f^(FK{kv(r@UE{zQS%Nb3E9ko42jl^h^2U#U9cqA93FlyIwWxj+T}C$r z%x1T3DZP16Fmglqy3{t2En96T0tzFl?3Y%F8d3|WVC}mK*PlY`^Iq=Wkf!mwEEkKB z8H!z8skFqnncEEF1xY*c|A4p>5GlQ)4)zI1=U;g=ep^JM#AbNBn*h4KfuhY${O6~Yl);cp?NIzQKRL*C?Zj^3d#b{ECQG!kTyou^iT z2Qs@4tmA(iPZ=T69olx*f>E7bwm7GlbwM8zWy@q|Ie=Lf-MRWMrIzy~GHCUynR)sH za~J-Wl;iYdCiV|xLWJ_a4p6c)C<77kKyFrA$mH#>c}yMiSo>_MRGQK3sF+P<3f1R6 z#^}e?m+uSgpPM4S!Lq6HLuoL0!Lf4MY>NKG}$vJZMLnON&aO z2eO1rK1D4A9}bafPhYMa&Gw}a_V|Qoe=srJZ!+L_*$)3PSSyKsGVIi0jTfhu?}N48MP$u*D?#a;f~k9};0rgKjy z|Mc{B>n>r89BAsZ7NO23y7rb?}4-uRvH2OgzTzZoB)~AhqJkQK|UN5NYL7ZH#wb*m@ z3VD^7gTAXtm8PI_2*B?f~*^M01sKfU(x7NK?R;xN1r_ z!it}ZUwxEl>5roOA5}JzCl^+`h9X zPGz=Nq4-(x&JO=V@hxx2^0io{o*bsh|0z9&YW(~$cgallqN6h9NxxN(UqufOp5?`Sqy7S%IKRN z6%2^yZx~Gf^DbHP;v=@fJlKHHM^%e4l!-o(a1s7?-e^L1F;>}yptmLR4PJ-+-4(H0 zv2-%l!8OrvQ%TD3Gc#?}eTl9n)rKAu6#f*IPDX9aPjFe}sFZJ6!$uwkkjE(+PMp@y z!+Sh>ESpKxj^KM)PyW8?m~E&7Y&!f5UIE>(SBbD=Ou zCgO1@d~*Wze(zQNsWHCDP}l03m^n{u7ROU3voYRl{Y>P2wtei&b5PF#x=H(8nVlz* zESgSJ&72y*?hP=!rxup$_dEt(P@j%UA2Fs~dZ{WX^>3?ag~{x2-i3X0 z;Pv(|xT&lg2ZL0jEJG!>-u9i3Y9Ah=t&Gy?#;7+JeOzB`$-MrEakM}oT@x!X!uH9Y zqGCe-+KWDR;(5Z=n}3SNf9gIMH?O5s9?RtFP$EkvMV_k!%)DrUZ^M4=}ub( z3WBmKpEryUBxbFQs$ze9v+N_1qh7=qFU*MbT6L%8oES

prhc2O}KLlEU`G=FMfE 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

1tBD9fj4Bs-7 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 z

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

sOe&4q?~7DiZ-nsoRbEG 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

&Dx(Z3_md66UN|_ES59@BMR9d?C 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